Flutter Engine
platform_view_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 "flutter/shell/platform/fuchsia/flutter/platform_view.h"
6 
7 #include <fuchsia/ui/gfx/cpp/fidl.h>
8 #include <fuchsia/ui/scenic/cpp/fidl.h>
9 #include <fuchsia/ui/views/cpp/fidl.h>
10 #include <lib/async-loop/cpp/loop.h>
11 #include <lib/async-loop/default.h>
12 #include <lib/async/default.h>
13 #include <lib/fidl/cpp/binding_set.h>
14 #include <lib/sys/cpp/testing/service_directory_provider.h>
15 #include <lib/ui/scenic/cpp/view_ref_pair.h>
16 
17 #include <memory>
18 #include <ostream>
19 #include <string>
20 #include <vector>
21 
22 #include "flutter/flow/embedded_views.h"
23 #include "flutter/lib/ui/window/platform_message.h"
24 #include "flutter/lib/ui/window/viewport_metrics.h"
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 
28 #include "surface.h"
29 #include "task_runner_adapter.h"
30 
32 namespace {
33 
34 class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder {
35  public:
36  SkCanvas* GetRootCanvas() override { return nullptr; }
37  std::vector<SkCanvas*> GetCurrentCanvases() override {
38  return std::vector<SkCanvas*>();
39  }
40 
41  void CancelFrame() override {}
42  void BeginFrame(
43  SkISize frame_size,
44  GrDirectContext* context,
45  double device_pixel_ratio,
46  fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override {}
47  void SubmitFrame(GrDirectContext* context,
48  std::unique_ptr<flutter::SurfaceFrame> frame) override {
49  return;
50  }
51 
52  void PrerollCompositeEmbeddedView(
53  int view_id,
54  std::unique_ptr<flutter::EmbeddedViewParams> params) override {}
55  SkCanvas* CompositeEmbeddedView(int view_id) override { return nullptr; }
56 };
57 
58 class MockPlatformViewDelegate : public flutter::PlatformView::Delegate {
59  public:
60  // |flutter::PlatformView::Delegate|
61  void OnPlatformViewCreated(std::unique_ptr<flutter::Surface> surface) {
62  surface_ = std::move(surface);
63  }
64  // |flutter::PlatformView::Delegate|
65  void OnPlatformViewDestroyed() {}
66  // |flutter::PlatformView::Delegate|
67  void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {}
68  // |flutter::PlatformView::Delegate|
69  void OnPlatformViewSetViewportMetrics(
70  const flutter::ViewportMetrics& metrics) {
71  metrics_ = metrics;
72  }
73  // |flutter::PlatformView::Delegate|
74  void OnPlatformViewDispatchPlatformMessage(
76  message_ = std::move(message);
77  }
78  // |flutter::PlatformView::Delegate|
79  void OnPlatformViewDispatchPointerDataPacket(
80  std::unique_ptr<flutter::PointerDataPacket> packet) {}
81  // |flutter::PlatformView::Delegate|
82  void OnPlatformViewDispatchSemanticsAction(int32_t id,
84  std::vector<uint8_t> args) {}
85  // |flutter::PlatformView::Delegate|
86  void OnPlatformViewSetSemanticsEnabled(bool enabled) {
87  semantics_enabled_ = enabled;
88  }
89  // |flutter::PlatformView::Delegate|
90  void OnPlatformViewSetAccessibilityFeatures(int32_t flags) {
91  semantics_features_ = flags;
92  }
93  // |flutter::PlatformView::Delegate|
94  void OnPlatformViewRegisterTexture(
95  std::shared_ptr<flutter::Texture> texture) {}
96  // |flutter::PlatformView::Delegate|
97  void OnPlatformViewUnregisterTexture(int64_t texture_id) {}
98  // |flutter::PlatformView::Delegate|
99  void OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) {}
100  // |flutter::PlatformView::Delegate|
101  std::unique_ptr<std::vector<std::string>> ComputePlatformViewResolvedLocale(
102  const std::vector<std::string>& supported_locale_data) {
103  return nullptr;
104  }
105 
106  flutter::Surface* surface() const { return surface_.get(); }
107  flutter::PlatformMessage* message() const { return message_.get(); }
108  const flutter::ViewportMetrics& metrics() const { return metrics_; }
109  int32_t semantics_features() const { return semantics_features_; }
110  bool semantics_enabled() const { return semantics_enabled_; }
111 
112  private:
113  std::unique_ptr<flutter::Surface> surface_;
115  flutter::ViewportMetrics metrics_;
116  int32_t semantics_features_ = 0;
117  bool semantics_enabled_ = false;
118 };
119 
120 class MockFocuser : public fuchsia::ui::views::Focuser {
121  public:
122  MockFocuser(bool fail_request_focus = false)
123  : fail_request_focus_(fail_request_focus) {}
124 
125  bool request_focus_called() const { return request_focus_called_; }
126 
127  private:
128  void RequestFocus(fuchsia::ui::views::ViewRef view_ref,
129  RequestFocusCallback callback) override {
130  request_focus_called_ = true;
131  auto result =
132  fail_request_focus_
133  ? fuchsia::ui::views::Focuser_RequestFocus_Result::WithErr(
134  fuchsia::ui::views::Error::DENIED)
135  : fuchsia::ui::views::Focuser_RequestFocus_Result::WithResponse(
136  fuchsia::ui::views::Focuser_RequestFocus_Response());
137  callback(std::move(result));
138  }
139 
140  bool request_focus_called_ = false;
141  bool fail_request_focus_ = false;
142 };
143 
144 class MockResponse : public flutter::PlatformMessageResponse {
145  public:
146  MOCK_METHOD1(Complete, void(std::unique_ptr<fml::Mapping> data));
147  MOCK_METHOD0(CompleteEmpty, void());
148 };
149 
150 } // namespace
151 
152 class PlatformViewTests : public ::testing::Test {
153  protected:
154  PlatformViewTests() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {}
155 
156  async_dispatcher_t* dispatcher() { return loop_.dispatcher(); }
157 
159  loop_.RunUntilIdle();
160  loop_.ResetQuit();
161  }
162 
163  private:
164  async::Loop loop_;
165 
167 };
168 
169 // This test makes sure that the PlatformView correctly returns a Surface
170 // instance that can surface the provided gr_context and view_embedder.
171 TEST_F(PlatformViewTests, CreateSurfaceTest) {
172  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
173  MockPlatformViewDelegate delegate;
174 
175  flutter::TaskRunners task_runners =
176  flutter::TaskRunners("test_runners", // label
177  nullptr, // platform
179  async_get_default_dispatcher()), // raster
180  nullptr, // ui
181  nullptr // io
182  );
183 
184  // Test create surface callback function.
185  sk_sp<GrDirectContext> gr_context =
186  GrDirectContext::MakeMock(nullptr, GrContextOptions());
187  std::shared_ptr<MockExternalViewEmbedder> view_embedder =
188  std::make_shared<MockExternalViewEmbedder>();
189  auto CreateSurfaceCallback = [&view_embedder, gr_context]() {
190  return std::make_unique<flutter_runner::Surface>(
191  "PlatformViewTest", view_embedder, gr_context.get());
192  };
193 
194  auto platform_view = flutter_runner::PlatformView(
195  delegate, // delegate
196  "test_platform_view", // label
197  fuchsia::ui::views::ViewRef(), // view_ref
198  std::move(task_runners), // task_runners
199  services_provider.service_directory(), // runner_services
200  nullptr, // parent_environment_service_provider_handle
201  nullptr, // session_listener_request
202  nullptr, // focuser,
203  nullptr, // on_session_listener_error_callback
204  nullptr, // on_enable_wireframe_callback,
205  nullptr, // on_create_view_callback,
206  nullptr, // on_update_view_callback,
207  nullptr, // on_destroy_view_callback,
208  CreateSurfaceCallback, // on_create_surface_callback,
209  view_embedder, // external_view_embedder,
210  fml::TimeDelta::Zero(), // vsync_offset
211  ZX_HANDLE_INVALID // vsync_event_handle
212  );
213  platform_view.NotifyCreated();
214 
215  RunLoopUntilIdle();
216 
217  EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext());
218  EXPECT_EQ(view_embedder.get(), delegate.surface()->GetExternalViewEmbedder());
219 }
220 
221 // This test makes sure that the PlatformView correctly registers Scenic
222 // MetricsEvents sent to it via FIDL, correctly parses the metrics it receives,
223 // and calls the SetViewportMetrics callback with the appropriate parameters.
225  constexpr float invalid_pixel_ratio = -0.75f;
226  constexpr float valid_pixel_ratio = 0.75f;
227  constexpr float invalid_max_bound = -0.75f;
228  constexpr float valid_max_bound = 0.75f;
229 
230  MockPlatformViewDelegate delegate;
231  EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
232 
233  fuchsia::ui::scenic::SessionListenerPtr session_listener;
234  std::vector<fuchsia::ui::scenic::Event> events;
235  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
236  flutter::TaskRunners task_runners("test_runners", nullptr, nullptr, nullptr,
237  nullptr);
238  flutter_runner::PlatformView platform_view(
239  delegate, // delegate
240  "test_platform_view", // label
241  fuchsia::ui::views::ViewRef(), // view_ref
242  std::move(task_runners), // task_runners
243  services_provider.service_directory(), // runner_services
244  nullptr, // parent_environment_service_provider_handle
245  session_listener.NewRequest(), // session_listener_request
246  nullptr, // focuser,
247  nullptr, // on_session_listener_error_callback
248  nullptr, // on_enable_wireframe_callback,
249  nullptr, // on_create_view_callback,
250  nullptr, // on_update_view_callback,
251  nullptr, // on_destroy_view_callback,
252  nullptr, // on_create_surface_callback,
253  nullptr, // external_view_embedder,
254  fml::TimeDelta::Zero(), // vsync_offset
255  ZX_HANDLE_INVALID // vsync_event_handle
256  );
257  RunLoopUntilIdle();
258  EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
259 
260  // Test updating with an invalid pixel ratio. The final metrics should be
261  // unchanged.
262  events.clear();
263  events.emplace_back(fuchsia::ui::scenic::Event::WithGfx(
264  fuchsia::ui::gfx::Event::WithMetrics(fuchsia::ui::gfx::MetricsEvent{
265  .node_id = 0,
266  .metrics =
267  fuchsia::ui::gfx::Metrics{
268  .scale_x = invalid_pixel_ratio,
269  .scale_y = 1.f,
270  .scale_z = 1.f,
271  },
272  })));
273  session_listener->OnScenicEvent(std::move(events));
274  RunLoopUntilIdle();
275  EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
276 
277  // Test updating with an invalid size. The final metrics should be unchanged.
278  events.clear();
279  events.emplace_back(
280  fuchsia::ui::scenic::Event::WithGfx(
281  fuchsia::ui::gfx::Event::WithViewPropertiesChanged(
282  fuchsia::ui::gfx::ViewPropertiesChangedEvent{
283  .view_id = 0,
284  .properties =
285  fuchsia::ui::gfx::ViewProperties{
286  .bounding_box =
287  fuchsia::ui::gfx::BoundingBox{
288  .min =
289  fuchsia::ui::gfx::vec3{
290  .x = 0.f,
291  .y = 0.f,
292  .z = 0.f,
293  },
294  .max =
295  fuchsia::ui::gfx::vec3{
296  .x = invalid_max_bound,
297  .y = invalid_max_bound,
298  .z = invalid_max_bound,
299  },
300  },
301  },
302  })));
303  session_listener->OnScenicEvent(std::move(events));
304  RunLoopUntilIdle();
305  EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
306 
307  // Test updating the size only. The final metrics should be unchanged until
308  // both pixel ratio and size are updated.
309  events.clear();
310  events.emplace_back(
311  fuchsia::ui::scenic::Event::WithGfx(
312  fuchsia::ui::gfx::Event::WithViewPropertiesChanged(
313  fuchsia::ui::gfx::ViewPropertiesChangedEvent{
314  .view_id = 0,
315  .properties =
316  fuchsia::ui::gfx::ViewProperties{
317  .bounding_box =
318  fuchsia::ui::gfx::BoundingBox{
319  .min =
320  fuchsia::ui::gfx::vec3{
321  .x = 0.f,
322  .y = 0.f,
323  .z = 0.f,
324  },
325  .max =
326  fuchsia::ui::gfx::vec3{
327  .x = valid_max_bound,
328  .y = valid_max_bound,
329  .z = valid_max_bound,
330  },
331  },
332  },
333  })));
334  session_listener->OnScenicEvent(std::move(events));
335  RunLoopUntilIdle();
336  EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics());
337 
338  // Test updating the pixel ratio only. The final metrics should change now.
339  events.clear();
340  events.emplace_back(fuchsia::ui::scenic::Event::WithGfx(
341  fuchsia::ui::gfx::Event::WithMetrics(fuchsia::ui::gfx::MetricsEvent{
342  .node_id = 0,
343  .metrics =
344  fuchsia::ui::gfx::Metrics{
345  .scale_x = valid_pixel_ratio,
346  .scale_y = 1.f,
347  .scale_z = 1.f,
348  },
349  })));
350  session_listener->OnScenicEvent(std::move(events));
351  RunLoopUntilIdle();
352  EXPECT_EQ(delegate.metrics(),
353  flutter::ViewportMetrics(valid_pixel_ratio,
354  valid_pixel_ratio * valid_max_bound,
355  valid_pixel_ratio * valid_max_bound));
356 }
357 
358 // This test makes sure that the PlatformView correctly registers semantics
359 // settings changes applied to it and calls the SetSemanticsEnabled /
360 // SetAccessibilityFeatures callbacks with the appropriate parameters.
361 TEST_F(PlatformViewTests, ChangesAccessibilitySettings) {
362  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
363 
364  MockPlatformViewDelegate delegate;
365  flutter::TaskRunners task_runners =
366  flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
367 
368  EXPECT_FALSE(delegate.semantics_enabled());
369  EXPECT_EQ(delegate.semantics_features(), 0);
370 
371  auto platform_view = flutter_runner::PlatformView(
372  delegate, // delegate
373  "test_platform_view", // label
374  fuchsia::ui::views::ViewRef(), // view_ref
375  std::move(task_runners), // task_runners
376  services_provider.service_directory(), // runner_services
377  nullptr, // parent_environment_service_provider_handle
378  nullptr, // session_listener_request
379  nullptr, // focuser,
380  nullptr, // on_session_listener_error_callback
381  nullptr, // on_enable_wireframe_callback,
382  nullptr, // on_create_view_callback,
383  nullptr, // on_update_view_callback,
384  nullptr, // on_destroy_view_callback,
385  nullptr, // on_create_surface_callback,
386  nullptr, // external_view_embedder,
387  fml::TimeDelta::Zero(), // vsync_offset
388  ZX_HANDLE_INVALID // vsync_event_handle
389  );
390 
391  RunLoopUntilIdle();
392 
393  platform_view.SetSemanticsEnabled(true);
394 
395  EXPECT_TRUE(delegate.semantics_enabled());
396  EXPECT_EQ(delegate.semantics_features(),
397  static_cast<int32_t>(
399 
400  platform_view.SetSemanticsEnabled(false);
401 
402  EXPECT_FALSE(delegate.semantics_enabled());
403  EXPECT_EQ(delegate.semantics_features(), 0);
404 }
405 
406 // This test makes sure that the PlatformView forwards messages on the
407 // "flutter/platform_views" channel for EnableWireframe.
408 TEST_F(PlatformViewTests, EnableWireframeTest) {
409  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
410  MockPlatformViewDelegate delegate;
411  flutter::TaskRunners task_runners =
412  flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
413 
414  // Test wireframe callback function. If the message sent to the platform
415  // view was properly handled and parsed, this function should be called,
416  // setting |wireframe_enabled| to true.
417  bool wireframe_enabled = false;
418  auto EnableWireframeCallback = [&wireframe_enabled](bool should_enable) {
419  wireframe_enabled = should_enable;
420  };
421 
422  auto platform_view = flutter_runner::PlatformView(
423  delegate, // delegate
424  "test_platform_view", // label
425  fuchsia::ui::views::ViewRef(), // view_ref
426  std::move(task_runners), // task_runners
427  services_provider.service_directory(), // runner_services
428  nullptr, // parent_environment_service_provider_handle
429  nullptr, // session_listener_request
430  nullptr, // focuser,
431  nullptr, // on_session_listener_error_callback
432  EnableWireframeCallback, // on_enable_wireframe_callback,
433  nullptr, // on_create_view_callback,
434  nullptr, // on_update_view_callback,
435  nullptr, // on_destroy_view_callback,
436  nullptr, // on_create_surface_callback,
437  nullptr, // external_view_embedder,
438  fml::TimeDelta::Zero(), // vsync_offset
439  ZX_HANDLE_INVALID // vsync_event_handle
440  );
441 
442  // Cast platform_view to its base view so we can have access to the public
443  // "HandlePlatformMessage" function.
444  auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
445  EXPECT_TRUE(base_view);
446 
447  // JSON for the message to be passed into the PlatformView.
448  const uint8_t txt[] =
449  "{"
450  " \"method\":\"View.enableWireframe\","
451  " \"args\": {"
452  " \"enable\":true"
453  " }"
454  "}";
455 
457  fml::MakeRefCounted<flutter::PlatformMessage>(
458  "flutter/platform_views",
459  std::vector<uint8_t>(txt, txt + sizeof(txt)),
461  base_view->HandlePlatformMessage(message);
462 
463  RunLoopUntilIdle();
464 
465  EXPECT_TRUE(wireframe_enabled);
466 }
467 
468 // This test makes sure that the PlatformView forwards messages on the
469 // "flutter/platform_views" channel for Createview.
470 TEST_F(PlatformViewTests, CreateViewTest) {
471  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
472  MockPlatformViewDelegate delegate;
473  flutter::TaskRunners task_runners =
474  flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
475 
476  // Test wireframe callback function. If the message sent to the platform
477  // view was properly handled and parsed, this function should be called,
478  // setting |wireframe_enabled| to true.
479  int64_t create_view_called = false;
480  auto CreateViewCallback = [&create_view_called](
481  int64_t view_id, bool hit_testable,
482  bool focusable) { create_view_called = true; };
483 
484  auto platform_view = flutter_runner::PlatformView(
485  delegate, // delegate
486  "test_platform_view", // label
487  fuchsia::ui::views::ViewRef(), // view_ref
488  std::move(task_runners), // task_runners
489  services_provider.service_directory(), // runner_services
490  nullptr, // parent_environment_service_provider_handle
491  nullptr, // session_listener_request
492  nullptr, // focuser,
493  nullptr, // on_session_listener_error_callback
494  nullptr, // on_enable_wireframe_callback,
495  CreateViewCallback, // on_create_view_callback,
496  nullptr, // on_update_view_callback,
497  nullptr, // on_destroy_view_callback,
498  nullptr, // on_create_surface_callback,
499  nullptr, // external_view_embedder,
500  fml::TimeDelta::Zero(), // vsync_offset
501  ZX_HANDLE_INVALID // vsync_event_handle
502  );
503 
504  // Cast platform_view to its base view so we can have access to the public
505  // "HandlePlatformMessage" function.
506  auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
507  EXPECT_TRUE(base_view);
508 
509  // JSON for the message to be passed into the PlatformView.
510  const uint8_t txt[] =
511  "{"
512  " \"method\":\"View.create\","
513  " \"args\": {"
514  " \"viewId\":42,"
515  " \"hitTestable\":true,"
516  " \"focusable\":true"
517  " }"
518  "}";
519 
521  fml::MakeRefCounted<flutter::PlatformMessage>(
522  "flutter/platform_views",
523  std::vector<uint8_t>(txt, txt + sizeof(txt)),
525  base_view->HandlePlatformMessage(message);
526 
527  RunLoopUntilIdle();
528 
529  EXPECT_TRUE(create_view_called);
530 }
531 
532 // This test makes sure that the PlatformView forwards messages on the
533 // "flutter/platform_views" channel for UpdateView.
534 TEST_F(PlatformViewTests, UpdateViewTest) {
535  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
536  MockPlatformViewDelegate delegate;
537  flutter::TaskRunners task_runners =
538  flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
539 
540  // Test wireframe callback function. If the message sent to the platform
541  // view was properly handled and parsed, this function should be called,
542  // setting |wireframe_enabled| to true.
543  int64_t update_view_called = false;
544  auto UpdateViewCallback = [&update_view_called](
545  int64_t view_id, bool hit_testable,
546  bool focusable) { update_view_called = true; };
547 
548  auto platform_view = flutter_runner::PlatformView(
549  delegate, // delegate
550  "test_platform_view", // label
551  fuchsia::ui::views::ViewRef(), // view_ref
552  std::move(task_runners), // task_runners
553  services_provider.service_directory(), // runner_services
554  nullptr, // parent_environment_service_provider_handle
555  nullptr, // session_listener_request
556  nullptr, // focuser,
557  nullptr, // on_session_listener_error_callback
558  nullptr, // on_enable_wireframe_callback,
559  nullptr, // on_create_view_callback,
560  UpdateViewCallback, // on_update_view_callback,
561  nullptr, // on_destroy_view_callback,
562  nullptr, // on_create_surface_callback,
563  nullptr, // external_view_embedder,
564  fml::TimeDelta::Zero(), // vsync_offset
565  ZX_HANDLE_INVALID // vsync_event_handle
566  );
567 
568  // Cast platform_view to its base view so we can have access to the public
569  // "HandlePlatformMessage" function.
570  auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
571  EXPECT_TRUE(base_view);
572 
573  // JSON for the message to be passed into the PlatformView.
574  const uint8_t txt[] =
575  "{"
576  " \"method\":\"View.update\","
577  " \"args\": {"
578  " \"viewId\":42,"
579  " \"hitTestable\":true,"
580  " \"focusable\":true"
581  " }"
582  "}";
583 
585  fml::MakeRefCounted<flutter::PlatformMessage>(
586  "flutter/platform_views",
587  std::vector<uint8_t>(txt, txt + sizeof(txt)),
589  base_view->HandlePlatformMessage(message);
590 
591  RunLoopUntilIdle();
592 
593  EXPECT_TRUE(update_view_called);
594 }
595 
596 // This test makes sure that the PlatformView forwards messages on the
597 // "flutter/platform_views" channel for DestroyView.
598 TEST_F(PlatformViewTests, DestroyViewTest) {
599  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
600  MockPlatformViewDelegate delegate;
601  flutter::TaskRunners task_runners =
602  flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
603 
604  // Test wireframe callback function. If the message sent to the platform
605  // view was properly handled and parsed, this function should be called,
606  // setting |wireframe_enabled| to true.
607  int64_t destroy_view_called = false;
608  auto DestroyViewCallback = [&destroy_view_called](int64_t view_id) {
609  destroy_view_called = true;
610  };
611 
612  auto platform_view = flutter_runner::PlatformView(
613  delegate, // delegate
614  "test_platform_view", // label
615  fuchsia::ui::views::ViewRef(), // view_ref
616  std::move(task_runners), // task_runners
617  services_provider.service_directory(), // runner_services
618  nullptr, // parent_environment_service_provider_handle
619  nullptr, // session_listener_request
620  nullptr, // focuser,
621  nullptr, // on_session_listener_error_callback
622  nullptr, // on_enable_wireframe_callback,
623  nullptr, // on_create_view_callback,
624  nullptr, // on_update_view_callback,
625  DestroyViewCallback, // on_destroy_view_callback,
626  nullptr, // on_create_surface_callback,
627  nullptr, // external_view_embedder,
628  fml::TimeDelta::Zero(), // vsync_offset
629  ZX_HANDLE_INVALID // vsync_event_handle
630  );
631 
632  // Cast platform_view to its base view so we can have access to the public
633  // "HandlePlatformMessage" function.
634  auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
635  EXPECT_TRUE(base_view);
636 
637  // JSON for the message to be passed into the PlatformView.
638  const uint8_t txt[] =
639  "{"
640  " \"method\":\"View.dispose\","
641  " \"args\": {"
642  " \"viewId\":42"
643  " }"
644  "}";
645 
647  fml::MakeRefCounted<flutter::PlatformMessage>(
648  "flutter/platform_views",
649  std::vector<uint8_t>(txt, txt + sizeof(txt)),
651  base_view->HandlePlatformMessage(message);
652 
653  RunLoopUntilIdle();
654 
655  EXPECT_TRUE(destroy_view_called);
656 }
657 
658 // This test makes sure that the PlatformView forwards messages on the
659 // "flutter/platform_views" channel for ViewConnected, ViewDisconnected, and
660 // ViewStateChanged events.
661 TEST_F(PlatformViewTests, ViewEventsTest) {
662  MockPlatformViewDelegate delegate;
663 
664  fuchsia::ui::scenic::SessionListenerPtr session_listener;
665  std::vector<fuchsia::ui::scenic::Event> events;
666  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
667 
669  "test_runners", nullptr, nullptr,
670  flutter_runner::CreateFMLTaskRunner(async_get_default_dispatcher()),
671  nullptr);
672 
673  auto platform_view = flutter_runner::PlatformView(
674  delegate, // delegate
675  "test_platform_view", // label
676  fuchsia::ui::views::ViewRef(), // view_ref
677  std::move(task_runners), // task_runners
678  services_provider.service_directory(), // runner_services
679  nullptr, // parent_environment_service_provider_handle
680  session_listener.NewRequest(), // session_listener_request
681  nullptr, // focuser,
682  nullptr, // on_session_listener_error_callback
683  nullptr, // on_enable_wireframe_callback,
684  nullptr, // on_create_view_callback,
685  nullptr, // on_update_view_callback,
686  nullptr, // on_destroy_view_callback,
687  nullptr, // on_create_surface_callback,
688  nullptr, // external_view_embedder,
689  fml::TimeDelta::Zero(), // vsync_offset
690  ZX_HANDLE_INVALID // vsync_event_handle
691  );
692  RunLoopUntilIdle();
693 
694  // ViewConnected event.
695  events.clear();
696  events.emplace_back(fuchsia::ui::scenic::Event::WithGfx(
697  fuchsia::ui::gfx::Event::WithViewConnected(
698  fuchsia::ui::gfx::ViewConnectedEvent{
699  .view_holder_id = 0,
700  })));
701  session_listener->OnScenicEvent(std::move(events));
702  RunLoopUntilIdle();
703 
704  auto data = delegate.message()->data();
705  auto call = std::string(data.begin(), data.end());
706  std::string expected = "{\"method\":\"View.viewConnected\",\"args\":null}";
707  EXPECT_EQ(expected, call);
708 
709  // ViewDisconnected event.
710  events.clear();
711  events.emplace_back(fuchsia::ui::scenic::Event::WithGfx(
712  fuchsia::ui::gfx::Event::WithViewDisconnected(
713  fuchsia::ui::gfx::ViewDisconnectedEvent{
714  .view_holder_id = 0,
715  })));
716  session_listener->OnScenicEvent(std::move(events));
717  RunLoopUntilIdle();
718 
719  data = delegate.message()->data();
720  call = std::string(data.begin(), data.end());
721  expected = "{\"method\":\"View.viewDisconnected\",\"args\":null}";
722  EXPECT_EQ(expected, call);
723 
724  // ViewStateChanged event.
725  events.clear();
726  events.emplace_back(fuchsia::ui::scenic::Event::WithGfx(
727  fuchsia::ui::gfx::Event::WithViewStateChanged(
728  fuchsia::ui::gfx::ViewStateChangedEvent{
729  .view_holder_id = 0,
730  .state =
731  fuchsia::ui::gfx::ViewState{
732  .is_rendering = true,
733  },
734  })));
735  session_listener->OnScenicEvent(std::move(events));
736  RunLoopUntilIdle();
737 
738  data = delegate.message()->data();
739  call = std::string(data.begin(), data.end());
740  expected = "{\"method\":\"View.viewStateChanged\",\"args\":{\"state\":true}}";
741  EXPECT_EQ(expected, call);
742 }
743 
744 // This test makes sure that the PlatformView forwards messages on the
745 // "flutter/platform_views" channel for RequestFocus.
746 TEST_F(PlatformViewTests, RequestFocusTest) {
747  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
748  MockPlatformViewDelegate delegate;
749  flutter::TaskRunners task_runners =
750  flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
751 
752  MockFocuser mock_focuser;
753  fidl::BindingSet<fuchsia::ui::views::Focuser> focuser_bindings;
754  auto focuser_handle = focuser_bindings.AddBinding(&mock_focuser);
755 
756  auto platform_view = flutter_runner::PlatformView(
757  delegate, // delegate
758  "test_platform_view", // label
759  fuchsia::ui::views::ViewRef(), // view_ref
760  std::move(task_runners), // task_runners
761  services_provider.service_directory(), // runner_services
762  nullptr, // parent_environment_service_provider_handle
763  nullptr, // session_listener_request
764  std::move(focuser_handle), // focuser,
765  nullptr, // on_session_listener_error_callback
766  nullptr, // on_enable_wireframe_callback,
767  nullptr, // on_create_view_callback,
768  nullptr, // on_update_view_callback,
769  nullptr, // on_destroy_view_callback,
770  nullptr, // on_create_surface_callback,
771  nullptr, // external_view_embedder,
772  fml::TimeDelta::Zero(), // vsync_offset
773  ZX_HANDLE_INVALID // vsync_event_handle
774  );
775 
776  // Cast platform_view to its base view so we can have access to the public
777  // "HandlePlatformMessage" function.
778  auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
779  EXPECT_TRUE(base_view);
780 
781  // This "Mock" ViewRef serves as the target for the RequestFocus operation.
782  auto mock_view_ref_pair = scenic::ViewRefPair::New();
783 
784  // JSON for the message to be passed into the PlatformView.
785  char buff[254];
786  snprintf(buff, sizeof(buff),
787  "{"
788  " \"method\":\"View.requestFocus\","
789  " \"args\": {"
790  " \"viewRef\":%u"
791  " }"
792  "}",
793  mock_view_ref_pair.view_ref.reference.get());
794 
795  // Define a custom gmock matcher to capture the response to platform message.
796  struct DataArg {
797  void Complete(std::unique_ptr<fml::Mapping> data) {
798  this->data = std::move(data);
799  }
800  std::unique_ptr<fml::Mapping> data;
801  };
802  DataArg data_arg;
803  fml::RefPtr<MockResponse> response = fml::MakeRefCounted<MockResponse>();
804  EXPECT_CALL(*response, Complete(::testing::_))
805  .WillOnce(::testing::Invoke(&data_arg, &DataArg::Complete));
806 
808  fml::MakeRefCounted<flutter::PlatformMessage>(
809  "flutter/platform_views",
810  std::vector<uint8_t>(buff, buff + sizeof(buff)), response);
811  base_view->HandlePlatformMessage(message);
812 
813  RunLoopUntilIdle();
814 
815  EXPECT_TRUE(mock_focuser.request_focus_called());
816  auto result = std::string((const char*)data_arg.data->GetMapping(),
817  data_arg.data->GetSize());
818  EXPECT_EQ(std::string("[0]"), result);
819 }
820 
821 // This test makes sure that the PlatformView correctly replies with an error
822 // response when a RequestFocus call fails.
823 TEST_F(PlatformViewTests, RequestFocusFailTest) {
824  sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
825  MockPlatformViewDelegate delegate;
826  flutter::TaskRunners task_runners =
827  flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr);
828 
829  MockFocuser mock_focuser(true /*fail_request_focus*/);
830  fidl::BindingSet<fuchsia::ui::views::Focuser> focuser_bindings;
831  auto focuser_handle = focuser_bindings.AddBinding(&mock_focuser);
832 
833  auto platform_view = flutter_runner::PlatformView(
834  delegate, // delegate
835  "test_platform_view", // label
836  fuchsia::ui::views::ViewRef(), // view_ref
837  std::move(task_runners), // task_runners
838  services_provider.service_directory(), // runner_services
839  nullptr, // parent_environment_service_provider_handle
840  nullptr, // session_listener_request
841  std::move(focuser_handle), // focuser,
842  nullptr, // on_session_listener_error_callback
843  nullptr, // on_enable_wireframe_callback,
844  nullptr, // on_create_view_callback,
845  nullptr, // on_update_view_callback,
846  nullptr, // on_destroy_view_callback,
847  nullptr, // on_create_surface_callback,
848  nullptr, // external_view_embedder,
849  fml::TimeDelta::Zero(), // vsync_offset
850  ZX_HANDLE_INVALID // vsync_event_handle
851  );
852 
853  // Cast platform_view to its base view so we can have access to the public
854  // "HandlePlatformMessage" function.
855  auto base_view = dynamic_cast<flutter::PlatformView*>(&platform_view);
856  EXPECT_TRUE(base_view);
857 
858  // This "Mock" ViewRef serves as the target for the RequestFocus operation.
859  auto mock_view_ref_pair = scenic::ViewRefPair::New();
860 
861  // JSON for the message to be passed into the PlatformView.
862  char buff[254];
863  snprintf(buff, sizeof(buff),
864  "{"
865  " \"method\":\"View.requestFocus\","
866  " \"args\": {"
867  " \"viewRef\":%u"
868  " }"
869  "}",
870  mock_view_ref_pair.view_ref.reference.get());
871 
872  // Define a custom gmock matcher to capture the response to platform message.
873  struct DataArg {
874  void Complete(std::unique_ptr<fml::Mapping> data) {
875  this->data = std::move(data);
876  }
877  std::unique_ptr<fml::Mapping> data;
878  };
879  DataArg data_arg;
880  fml::RefPtr<MockResponse> response = fml::MakeRefCounted<MockResponse>();
881  EXPECT_CALL(*response, Complete(::testing::_))
882  .WillOnce(::testing::Invoke(&data_arg, &DataArg::Complete));
883 
885  fml::MakeRefCounted<flutter::PlatformMessage>(
886  "flutter/platform_views",
887  std::vector<uint8_t>(buff, buff + sizeof(buff)), response);
888  base_view->HandlePlatformMessage(message);
889 
890  RunLoopUntilIdle();
891 
892  EXPECT_TRUE(mock_focuser.request_focus_called());
893  auto result = std::string((const char*)data_arg.data->GetMapping(),
894  data_arg.data->GetSize());
895  std::ostringstream out;
896  out << "["
897  << static_cast<std::underlying_type_t<fuchsia::ui::views::Error>>(
898  fuchsia::ui::views::Error::DENIED)
899  << "]";
900  EXPECT_EQ(out.str(), result);
901 }
902 
903 } // namespace flutter_runner::testing
G_BEGIN_DECLS FlValue * args
TEST_F(PlatformViewTests, CreateSurfaceTest)
fml::RefPtr< fml::TaskRunner > CreateFMLTaskRunner(async_dispatcher_t *dispatcher)
static constexpr TimeDelta Zero()
Definition: time_delta.h:33
Platform views are created by the shell on the platform task runner. Unless explicitly specified...
Definition: platform_view.h:44
std::function< void()> closure
Definition: closure.h:14
Abstract Base Class that represents where we will be rendering content.
Definition: surface.h:18
static void SetViewportMetrics(JNIEnv *env, jobject jcaller, jlong shell_holder, jfloat devicePixelRatio, jint physicalWidth, jint physicalHeight, jint physicalPaddingTop, jint physicalPaddingRight, jint physicalPaddingBottom, jint physicalPaddingLeft, jint physicalViewInsetTop, jint physicalViewInsetRight, jint physicalViewInsetBottom, jint physicalViewInsetLeft, jint systemGestureInsetTop, jint systemGestureInsetRight, jint systemGestureInsetBottom, jint systemGestureInsetLeft)
SemanticsAction action
T * get() const
Definition: ref_ptr.h:112
void NotifyCreated()
Used by embedders to notify the shell that a platform view has been created. This notification is use...
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:27
Used to forward events from the platform view to interested subsystems. This forwarding is done by th...
Definition: platform_view.h:51
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart flags
Definition: switches.h:66