Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
pointer_injector_delegate_unittest.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <fuchsia/ui/pointerinjector/cpp/fidl.h>
6#include <fuchsia/ui/views/cpp/fidl.h>
7#include <gmock/gmock.h>
8#include <gtest/gtest.h>
9#include <lib/async-loop/cpp/loop.h>
10#include <lib/async-loop/default.h>
11#include <lib/async/cpp/task.h>
12#include <lib/zx/eventpair.h>
13
14#include <lib/fidl/cpp/binding_set.h>
15
19
21
22using fup_DeviceType = fuchsia::ui::pointerinjector::DeviceType;
23using fup_DispatchPolicy = fuchsia::ui::pointerinjector::DispatchPolicy;
24using fup_EventPhase = fuchsia::ui::pointerinjector::EventPhase;
25using fup_RegistryHandle = fuchsia::ui::pointerinjector::RegistryHandle;
26using fuv_ViewRef = fuchsia::ui::views::ViewRef;
27
28namespace {
29
30// clang-format off
31 static constexpr std::array<float, 9> kIdentityMatrix = {
32 1, 0, 0, // column one
33 0, 1, 0, // column two
34 0, 0, 1, // column three
35 };
36// clang-format on
37
38rapidjson::Value ParsePlatformMessage(std::string json) {
39 rapidjson::Document document;
40 document.Parse(json);
41 if (document.HasParseError() || !document.IsObject()) {
42 FML_LOG(ERROR) << "Could not parse document";
43 return rapidjson::Value();
44 }
45 return document.GetObject();
46}
47
48zx_koid_t ExtractKoid(const zx::object_base& object) {
49 zx_info_handle_basic_t info{};
50 if (object.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr,
51 nullptr) != ZX_OK) {
52 return ZX_KOID_INVALID; // no info
53 }
54
55 return info.koid;
56}
57
58zx_koid_t ExtractKoid(const fuv_ViewRef& view_ref) {
59 return ExtractKoid(view_ref.reference);
60}
61
62class PlatformMessageBuilder {
63 public:
64 PlatformMessageBuilder& SetViewId(uint64_t view_id) {
65 view_id_ = view_id;
66 return *this;
67 }
68
69 PlatformMessageBuilder& SetPointerX(float x) {
70 pointer_x_ = x;
71 return *this;
72 }
73
74 PlatformMessageBuilder& SetPointerY(float y) {
75 pointer_y_ = y;
76 return *this;
77 }
78
79 PlatformMessageBuilder& SetPhase(int phase) {
80 phase_ = phase;
81 return *this;
82 }
83
84 PlatformMessageBuilder& SetPointerId(int pointer_id) {
85 pointer_id_ = pointer_id;
86 return *this;
87 }
88
89 PlatformMessageBuilder& SetTraceFlowId(int trace_flow_id) {
90 trace_flow_id_ = trace_flow_id;
91 return *this;
92 }
93
94 PlatformMessageBuilder& SetLogicalWidth(float width) {
95 width_ = width;
96 return *this;
97 }
98
99 PlatformMessageBuilder& SetLogicalHeight(float height) {
100 height_ = height;
101 return *this;
102 }
103
104 PlatformMessageBuilder& SetTimestamp(int timestamp) {
105 timestamp_ = timestamp;
106 return *this;
107 }
108
109 rapidjson::Value Build() {
110 std::ostringstream message;
111 message << "{" << " \"method\":\""
113 << " \"args\": {" << " \"viewId\":" << view_id_ << ","
114 << " \"x\":" << pointer_x_ << ","
115 << " \"y\":" << pointer_y_ << ","
116 << " \"phase\":" << phase_ << ","
117 << " \"pointerId\":" << pointer_id_ << ","
118 << " \"traceFlowId\":" << trace_flow_id_ << ","
119 << " \"viewRef\":" << view_ref_.reference.get() << ","
120 << " \"logicalWidth\":" << width_ << ","
121 << " \"logicalHeight\":" << height_ << ","
122 << " \"timestamp\":" << timestamp_ << " }" << "}";
123 return ParsePlatformMessage(message.str());
124 }
125
126 private:
127 uint64_t view_id_ = 0;
128 float pointer_x_ = 0.f, pointer_y_ = 0.f;
129 int phase_ = 1, pointer_id_ = 0, trace_flow_id_ = 0;
130 fuv_ViewRef view_ref_;
131 float width_ = 0.f, height_ = 0.f;
132 int timestamp_ = 0;
133};
134
135} // namespace
136
137class PointerInjectorDelegateTest : public ::testing::Test,
138 public ::testing::WithParamInterface<bool> {
139 protected:
141 : loop_(&kAsyncLoopConfigAttachToCurrentThread) {}
142
143 // TODO(fxbug.dev/104285): Replace the RunLoop methods with the one provided
144 // by the sdk.
145 void RunLoopUntilIdle() { loop_.RunUntilIdle(); }
146
147 bool RunGivenLoopWithTimeout(async::Loop* loop, zx::duration timeout) {
148 // This cannot be a local variable because the delayed task below can
149 // execute after this function returns.
150 auto canceled = std::make_shared<bool>(false);
151 bool timed_out = false;
152 async::PostDelayedTask(
153 loop->dispatcher(),
154 [loop, canceled, &timed_out] {
155 if (*canceled) {
156 return;
157 }
158 timed_out = true;
159 loop->Quit();
160 },
161 timeout);
162 loop->Run();
163 loop->ResetQuit();
164
165 if (!timed_out) {
166 *canceled = true;
167 }
168 return timed_out;
169 }
170
171 bool RunLoopWithTimeoutOrUntil(fit::function<bool()> condition,
172 zx::duration timeout,
173 zx::duration step) {
174 const zx::time timeout_deadline = zx::deadline_after(timeout);
175
176 while (zx::clock::get_monotonic() < timeout_deadline &&
177 loop_.GetState() == ASYNC_LOOP_RUNNABLE) {
178 if (condition()) {
179 loop_.ResetQuit();
180 return true;
181 }
182
183 if (step == zx::duration::infinite()) {
184 // Performs a single unit of work, possibly blocking until there is work
185 // to do or the timeout deadline arrives.
186 loop_.Run(timeout_deadline, true);
187 } else {
188 // Performs work until the step deadline arrives.
189 RunGivenLoopWithTimeout(&loop_, step);
190 }
191 }
192
193 loop_.ResetQuit();
194 return condition();
195 }
196
197 void RunLoopUntil(fit::function<bool()> condition,
198 zx::duration step = zx::msec(10)) {
199 RunLoopWithTimeoutOrUntil(std::move(condition), zx::duration::infinite(),
200 step);
201 }
202
203 void SetUp() override {
204 fuchsia::ui::views::ViewRefControl view_ref_control;
205 fuchsia::ui::views::ViewRef view_ref;
206 auto status = zx::eventpair::create(
207 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
208 ASSERT_EQ(status, ZX_OK);
209 view_ref_control.reference.replace(
210 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
211 &view_ref_control.reference);
212 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
213
214 host_view_ref_ = std::move(view_ref);
215
216 fup_RegistryHandle registry;
217 registry_ = std::make_unique<MockInjectorRegistry>(registry.NewRequest());
218
219 fuv_ViewRef host_view_ref_clone;
220 fidl::Clone(host_view_ref_, &host_view_ref_clone);
221
222 pointer_injector_delegate_ = std::make_unique<PointerInjectorDelegate>(
223 std::move(registry), std::move(host_view_ref_clone));
224 }
225
226 void CreateView(uint64_t view_id,
227 std::optional<fuv_ViewRef> view_ref = std::nullopt) {
228 fuv_ViewRef ref;
229 if (view_ref.has_value()) {
230 ref = std::move(*view_ref);
231 } else {
232 fuchsia::ui::views::ViewRefControl view_ref_control;
233 fuchsia::ui::views::ViewRef view_ref;
234 auto status = zx::eventpair::create(
235 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
236 ASSERT_EQ(status, ZX_OK);
237 view_ref_control.reference.replace(
238 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
239 &view_ref_control.reference);
240 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
241
242 ref = std::move(view_ref);
243 }
244 pointer_injector_delegate_->OnCreateView(view_id, std::move(ref));
245 }
246
247 std::unique_ptr<PointerInjectorDelegate> pointer_injector_delegate_;
248 std::unique_ptr<MockInjectorRegistry> registry_;
250
251 private:
252 async::Loop loop_;
253};
254
255TEST_P(PointerInjectorDelegateTest, IncorrectPlatformMessage_ShouldFail) {
256 const uint64_t view_id = 1;
257
258 // Create a view.
259 CreateView(view_id);
260
261 // A platform message in incorrect JSON format should fail.
262 {
263 auto response = FakePlatformMessageResponse::Create();
264
265 EXPECT_FALSE(pointer_injector_delegate_->HandlePlatformMessage(
266 ParsePlatformMessage("{Incorrect Json}"), response));
267 }
268
269 // |PointerInjectorDelegate| only handles "View.Pointerinjector.inject"
270 // platform messages.
271 {
272 auto response = FakePlatformMessageResponse::Create();
273
274 EXPECT_FALSE(pointer_injector_delegate_->HandlePlatformMessage(
275 ParsePlatformMessage("{\"method\":\"View.focus.getCurrent\"}"),
276 response));
277 }
278
279 // A platform message with no args should fail.
280 {
281 auto response = FakePlatformMessageResponse::Create();
282
283 EXPECT_FALSE(pointer_injector_delegate_->HandlePlatformMessage(
284 ParsePlatformMessage("{\"method\":\"View.Pointerinjector.inject\"}"),
285 response));
286 }
287}
288
289TEST_P(PointerInjectorDelegateTest, ViewsReceiveInjectedEvents) {
290 const uint64_t num_events = 150;
291
292 // Inject |num_events| platform messages for view 1.
293 {
294 const uint64_t view_id = 1;
295
296 CreateView(view_id);
297
298 fuchsia::ui::views::ViewRefControl view_ref_control;
299 fuchsia::ui::views::ViewRef view_ref;
300 auto status = zx::eventpair::create(
301 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
302 ASSERT_EQ(status, ZX_OK);
303 view_ref_control.reference.replace(
304 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
305 &view_ref_control.reference);
306 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
307
308 for (size_t i = 0; i < num_events; i++) {
309 auto response = FakePlatformMessageResponse::Create();
310
311 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
312 PlatformMessageBuilder().SetViewId(view_id).Build(), response));
313
314 response->ExpectCompleted("[0]");
315 }
316 }
317
318 // Inject |num_events| platform messages for view 2.
319 {
320 const uint64_t view_id = 2;
321
322 CreateView(view_id);
323
324 fuchsia::ui::views::ViewRefControl view_ref_control;
325 fuchsia::ui::views::ViewRef view_ref;
326 auto status = zx::eventpair::create(
327 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
328 ASSERT_EQ(status, ZX_OK);
329 view_ref_control.reference.replace(
330 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
331 &view_ref_control.reference);
332 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
333
334 for (size_t i = 0; i < num_events; i++) {
335 auto response = FakePlatformMessageResponse::Create();
336
337 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
338 PlatformMessageBuilder().SetViewId(view_id).Build(), response));
339
340 response->ExpectCompleted("[0]");
341 }
342 }
343
344 // The mock Pointerinjector registry server receives |num_events| pointer
345 // events from |f.u.p.Device.Inject| calls for each view.
346 RunLoopUntil(
347 [this] { return registry_->num_events_received() == 2 * num_events; });
348
349 // The mock Pointerinjector registry server receives a
350 // |f.u.p.Registry.Register| call for each view.
351 EXPECT_TRUE(registry_->num_register_calls() == 2);
352}
353
355 ViewsDontReceivePointerEventsBeforeCreation) {
356 const uint64_t num_events = 150;
357 const uint64_t view_id_1 = 1;
358
359 // Inject |num_events| platform messages for |view_id_1|.
360 {
361 fuchsia::ui::views::ViewRefControl view_ref_control;
362 fuchsia::ui::views::ViewRef view_ref;
363 auto status = zx::eventpair::create(
364 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
365 ASSERT_EQ(status, ZX_OK);
366 view_ref_control.reference.replace(
367 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
368 &view_ref_control.reference);
369 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
370
371 for (size_t i = 0; i < num_events; i++) {
372 auto response = FakePlatformMessageResponse::Create();
373
374 // The platform message is *silently* accepted for non-existent views, in
375 // order to cleanly handle the lifecycle case where the child view is
376 // forcibly killed. By doing so, products avoid "MissingPluginException"
377 // log spam.
378 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
379 PlatformMessageBuilder().SetViewId(view_id_1).Build(), response));
380 }
381 }
382
383 const uint64_t view_id_2 = 2;
384
385 // Inject |num_events| platform messages for |view_id_2|.
386 {
387 fuchsia::ui::views::ViewRefControl view_ref_control;
388 fuchsia::ui::views::ViewRef view_ref;
389 auto status = zx::eventpair::create(
390 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
391 ASSERT_EQ(status, ZX_OK);
392 view_ref_control.reference.replace(
393 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
394 &view_ref_control.reference);
395 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
396
397 for (size_t i = 0; i < num_events; i++) {
398 auto response = FakePlatformMessageResponse::Create();
399
400 // The platform message is *silently* accepted for non-existent views, in
401 // order to cleanly handle the lifecycle case where the child view is
402 // forcibly killed. By doing so, products avoid "MissingPluginException"
403 // log spam.
404 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
405 PlatformMessageBuilder().SetViewId(view_id_2).Build(), response));
406 }
407 }
408
409 RunLoopUntilIdle();
410
411 // The views do not receive any pointer events till they get created.
412 EXPECT_TRUE(registry_->num_events_received() == 0);
413}
414
415// PointerInjectorDelegate should generate a correct |f.u.p.Config| from a
416// platform message.
417TEST_P(PointerInjectorDelegateTest, ValidRegistrationConfigTest) {
418 const uint64_t view_id = 1;
419
420 const float x = 2.f, y = 2.f, width = 5.f, height = 5.f;
421 const int phase = 2, pointer_id = 5, trace_flow_id = 5, timestamp = 10;
422
423 auto response = FakePlatformMessageResponse::Create();
424
425 fuchsia::ui::views::ViewRefControl view_ref_control;
426 fuchsia::ui::views::ViewRef view_ref;
427 auto status = zx::eventpair::create(
428 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
429 ZX_ASSERT(status == ZX_OK);
430 view_ref_control.reference.replace(
431 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
432 &view_ref_control.reference);
433 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
434
435 // Create the view.
436 fuv_ViewRef view_ref_clone;
437 fidl::Clone(view_ref, &view_ref_clone);
438 CreateView(view_id, std::move(view_ref_clone));
439
440 // Inject a platform message.
441 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
442 PlatformMessageBuilder()
443 .SetViewId(view_id)
444 .SetPointerX(x)
445 .SetPointerY(y)
446 .SetPhase(phase)
447 .SetPointerId(pointer_id)
448 .SetTraceFlowId(trace_flow_id)
449 .SetLogicalWidth(width)
450 .SetLogicalHeight(height)
451 .SetTimestamp(timestamp)
452 .Build(),
453 response));
454
455 response->ExpectCompleted("[0]");
456
457 // The mock Pointerinjector registry server receives a pointer event from
458 // |f.u.p.Device.Inject| call for the view.
459 RunLoopUntil([this] { return registry_->num_events_received() == 1; });
460
461 // The mock Pointerinjector registry server receives a
462 // |f.u.p.Registry.Register| call for the view.
463 ASSERT_TRUE(registry_->num_register_calls() == 1);
464
465 const auto& config = registry_->config();
466
467 ASSERT_TRUE(config.has_device_id());
468 EXPECT_EQ(config.device_id(), 1u);
469
470 ASSERT_TRUE(config.has_device_type());
471 EXPECT_EQ(config.device_type(), fup_DeviceType::TOUCH);
472
473 ASSERT_TRUE(config.has_dispatch_policy());
474 EXPECT_EQ(config.dispatch_policy(), fup_DispatchPolicy::EXCLUSIVE_TARGET);
475
476 ASSERT_TRUE(config.has_context());
477 ASSERT_TRUE(config.context().is_view());
478 EXPECT_EQ(ExtractKoid(config.context().view()), ExtractKoid(host_view_ref_));
479
480 ASSERT_TRUE(config.has_target());
481 ASSERT_TRUE(config.target().is_view());
482 EXPECT_EQ(ExtractKoid(config.target().view()), ExtractKoid(view_ref));
483
484 ASSERT_TRUE(config.has_viewport());
485 ASSERT_TRUE(config.viewport().has_viewport_to_context_transform());
486 EXPECT_EQ(config.viewport().viewport_to_context_transform(), kIdentityMatrix);
487
488 std::array<std::array<float, 2>, 2> extents{{{0, 0}, {width, height}}};
489 ASSERT_TRUE(config.viewport().has_extents());
490 EXPECT_EQ(config.viewport().extents(), extents);
491}
492
493// PointerInjectorDelegate generates a correct f.u.p.Event from the platform
494// message.
495TEST_P(PointerInjectorDelegateTest, ValidPointerEventTest) {
496 const uint64_t view_id = 1;
497
498 const float x = 2.f, y = 2.f, width = 5.f, height = 5.f;
499 const int phase = 2, pointer_id = 5, trace_flow_id = 5, timestamp = 10;
500
501 auto response = FakePlatformMessageResponse::Create();
502
503 fuchsia::ui::views::ViewRefControl view_ref_control;
504 fuchsia::ui::views::ViewRef view_ref;
505 auto status = zx::eventpair::create(
506 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
507 ZX_ASSERT(status == ZX_OK);
508 view_ref_control.reference.replace(
509 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
510 &view_ref_control.reference);
511 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
512
513 // Create the view.
514 fuv_ViewRef view_ref_clone;
515 fidl::Clone(view_ref, &view_ref_clone);
516 CreateView(view_id, std::move(view_ref_clone));
517
518 // Inject a platform message.
519 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
520 PlatformMessageBuilder()
521 .SetViewId(view_id)
522 .SetPointerX(x)
523 .SetPointerY(y)
524 .SetPhase(phase)
525 .SetPointerId(pointer_id)
526 .SetTraceFlowId(trace_flow_id)
527 .SetLogicalWidth(width)
528 .SetLogicalHeight(height)
529 .SetTimestamp(timestamp)
530 .Build(),
531 response));
532
533 response->ExpectCompleted("[0]");
534
535 // The mock Pointerinjector registry server receives a pointer event from
536 // |f.u.p.Device.Inject| call for the view.
537 RunLoopUntil([this] { return registry_->num_events_received() == 1; });
538
539 // The mock Pointerinjector registry server receives a
540 // |f.u.p.Registry.Register| call for the view.
541 ASSERT_TRUE(registry_->num_register_calls() == 1);
542
543 const auto& events = registry_->events();
544
545 ASSERT_EQ(events.size(), 1u);
546
547 const auto& event = events[0];
548
549 ASSERT_TRUE(event.has_timestamp());
550 EXPECT_EQ(event.timestamp(), timestamp);
551
552 ASSERT_TRUE(event.has_trace_flow_id());
553 EXPECT_EQ(event.trace_flow_id(), static_cast<uint64_t>(trace_flow_id));
554
555 ASSERT_TRUE(event.has_data());
556 ASSERT_TRUE(event.data().is_pointer_sample());
557
558 const auto& pointer_sample = event.data().pointer_sample();
559
560 ASSERT_TRUE(pointer_sample.has_pointer_id());
561 ASSERT_TRUE(pointer_sample.has_phase());
562 ASSERT_TRUE(pointer_sample.has_position_in_viewport());
563 EXPECT_EQ(pointer_sample.pointer_id(), static_cast<uint32_t>(pointer_id));
564 EXPECT_EQ(pointer_sample.phase(), static_cast<fup_EventPhase>(phase));
565 EXPECT_THAT(pointer_sample.position_in_viewport(),
566 ::testing::ElementsAre(x, y));
567}
568
569TEST_P(PointerInjectorDelegateTest, DestroyedViewsDontGetPointerEvents) {
570 const uint64_t view_id = 1, num_events = 150;
571
572 fuchsia::ui::views::ViewRefControl view_ref_control;
573 fuchsia::ui::views::ViewRef view_ref;
574 auto status = zx::eventpair::create(
575 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
576 ZX_ASSERT(status == ZX_OK);
577 view_ref_control.reference.replace(
578 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
579 &view_ref_control.reference);
580 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
581
582 // Create the view.
583 CreateView(view_id);
584
585 // Inject |num_events| platform messages.
586 for (size_t i = 0; i < num_events; i++) {
587 auto response = FakePlatformMessageResponse::Create();
588
589 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
590 PlatformMessageBuilder().SetViewId(view_id).Build(), response));
591
592 response->ExpectCompleted("[0]");
593 }
594
595 // Destroy the view.
596 pointer_injector_delegate_->OnDestroyView(view_id);
597
598 // The view does not receive |num_events| pointer events as it gets destroyed
599 // before all the pointer events could be dispatched.
600 const zx::duration timeout = zx::sec(1), step = zx::msec(10);
601 EXPECT_FALSE(RunLoopWithTimeoutOrUntil(
602 [this] { return registry_->num_events_received() == num_events; },
603 timeout, step));
604
605 EXPECT_LT(registry_->num_events_received(), num_events);
606}
607
608TEST_P(PointerInjectorDelegateTest, ViewsGetPointerEventsInFIFO) {
609 const uint64_t view_id = 1, num_events = 150;
610
611 fuchsia::ui::views::ViewRefControl view_ref_control;
612 fuchsia::ui::views::ViewRef view_ref;
613 auto status = zx::eventpair::create(
614 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
615 ZX_ASSERT(status == ZX_OK);
616 view_ref_control.reference.replace(
617 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
618 &view_ref_control.reference);
619 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
620
621 // Create the view.
622 CreateView(view_id);
623
624 // Inject |num_events| platform messages.
625 for (size_t i = 0; i < num_events; i++) {
626 auto response = FakePlatformMessageResponse::Create();
627
628 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
629 PlatformMessageBuilder()
630 .SetViewId(view_id)
631 .SetPointerId(static_cast<uint32_t>(i))
632 .Build(),
633 response));
634
635 response->ExpectCompleted("[0]");
636 }
637
638 // The mock Pointerinjector registry server receives |num_events| pointer
639 // events from |f.u.p.Device.Inject| call for the view.
640 RunLoopUntil(
641 [this] { return registry_->num_events_received() == num_events; });
642
643 // The mock Pointerinjector registry server receives a
644 // |f.u.p.Registry.Register| call for the view.
645 ASSERT_TRUE(registry_->num_register_calls() == 1);
646
647 auto& events = registry_->events();
648
649 // The view should receive the pointer events in a FIFO order. As we injected
650 // platform messages with an increasing |pointer_id|, the received pointer
651 // events should also have the |pointer_id| in an increasing order.
652 for (size_t i = 0; i < events.size() - 1; i++) {
653 ASSERT_TRUE(events[i].has_data());
654 ASSERT_TRUE(events[i + 1].has_data());
655 ASSERT_TRUE(events[i].data().is_pointer_sample());
656 ASSERT_TRUE(events[i + 1].data().is_pointer_sample());
657
658 const auto& pointer_sample_1 = events[i].data().pointer_sample();
659 const auto& pointer_sample_2 = events[i + 1].data().pointer_sample();
660
661 ASSERT_TRUE(pointer_sample_1.has_pointer_id());
662 ASSERT_TRUE(pointer_sample_2.has_pointer_id());
663
664 EXPECT_TRUE(pointer_sample_1.pointer_id() < pointer_sample_2.pointer_id());
665 }
666}
667
668TEST_P(PointerInjectorDelegateTest, DeviceRetriesRegisterWhenClosed) {
669 const uint64_t view_id = 1;
670 const int pointer_id = 1;
671 fuchsia::ui::views::ViewRefControl view_ref_control;
672 fuchsia::ui::views::ViewRef view_ref;
673 auto status = zx::eventpair::create(
674 /*options*/ 0u, &view_ref_control.reference, &view_ref.reference);
675 ZX_ASSERT(status == ZX_OK);
676 view_ref_control.reference.replace(
677 ZX_DEFAULT_EVENTPAIR_RIGHTS & (~ZX_RIGHT_DUPLICATE),
678 &view_ref_control.reference);
679 view_ref.reference.replace(ZX_RIGHTS_BASIC, &view_ref.reference);
680
681 auto response = FakePlatformMessageResponse::Create();
682 auto response_2 = FakePlatformMessageResponse::Create();
683
684 // Create the view.
685 fuv_ViewRef view_ref_clone;
686 fidl::Clone(view_ref, &view_ref_clone);
687 CreateView(view_id, std::move(view_ref_clone));
688
689 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
690 PlatformMessageBuilder()
691 .SetViewId(view_id)
692 .SetPointerId(pointer_id)
693 .Build(),
694 response));
695
696 response->ExpectCompleted("[0]");
697
698 // The mock Pointerinjector registry server receives a pointer event from
699 // |f.u.p.Device.Inject| call for the view.
700 RunLoopUntil([this] { return registry_->num_events_received() == 1; });
701
702 // The mock Pointerinjector registry server receives a
703 // |f.u.p.Registry.Register| call for the view.
704 ASSERT_TRUE(registry_->num_register_calls() == 1);
705
706 // Close the device channel.
707 registry_->ClearBindings();
708 RunLoopUntilIdle();
709
710 EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage(
711 PlatformMessageBuilder()
712 .SetViewId(view_id)
713 .SetPointerId(pointer_id)
714 .Build(),
715 response_2));
716
717 response_2->ExpectCompleted("[0]");
718
719 // The mock Pointerinjector registry server receives a pointer event from
720 // |f.u.p.Device.Inject| call for the view.
721 RunLoopUntil([this] { return registry_->num_events_received() == 2; });
722
723 // The device tries to register again as the channel got closed.
724 ASSERT_TRUE(registry_->num_register_calls() == 2);
725}
726
727INSTANTIATE_TEST_SUITE_P(PointerInjectorDelegateParameterizedTest,
729 ::testing::Bool());
730
731} // namespace flutter_runner::testing
static int step(int x, SkScalar min, SkScalar max)
Definition BlurTest.cpp:215
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
void CreateView(uint64_t view_id, std::optional< fuv_ViewRef > view_ref=std::nullopt)
bool RunGivenLoopWithTimeout(async::Loop *loop, zx::duration timeout)
void RunLoopUntil(fit::function< bool()> condition, zx::duration step=zx::msec(10))
bool RunLoopWithTimeoutOrUntil(fit::function< bool()> condition, zx::duration timeout, zx::duration step)
FlKeyEvent * event
#define FML_LOG(severity)
Definition logging.h:82
rapidjson::Value ParsePlatformMessage(std::string json)
Win32Message message
double y
double x
fuchsia::ui::pointer::EventPhase fup_EventPhase
fuchsia::ui::pointerinjector::RegistryHandle fup_RegistryHandle
fuchsia::ui::pointerinjector::DeviceType fup_DeviceType
fuchsia::ui::pointerinjector::DispatchPolicy fup_DispatchPolicy
int32_t height
int32_t width
#define ERROR(message)
#define EXPECT_TRUE(handle)
Definition unit_test.h:685