From d5dddf32e77dd12db470fcefd37b686dd1f50696 Mon Sep 17 00:00:00 2001 From: David Worsham Date: Tue, 6 Oct 2020 17:57:28 -0700 Subject: [PATCH] fuchsia: Don't send ViewportMetrics w/ 0 DPR (#21392) --- lib/ui/window/viewport_metrics.cc | 50 +- lib/ui/window/viewport_metrics.h | 31 +- .../platform/fuchsia/flutter/platform_view.cc | 94 ++- .../platform/fuchsia/flutter/platform_view.h | 117 ++-- .../fuchsia/flutter/platform_view_unittest.cc | 615 ++++++++++-------- 5 files changed, 539 insertions(+), 368 deletions(-) diff --git a/lib/ui/window/viewport_metrics.cc b/lib/ui/window/viewport_metrics.cc index 8db0996ab..d52bfb837 100644 --- a/lib/ui/window/viewport_metrics.cc +++ b/lib/ui/window/viewport_metrics.cc @@ -10,6 +10,13 @@ namespace flutter { ViewportMetrics::ViewportMetrics() = default; +ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, + double p_physical_width, + double p_physical_height) + : device_pixel_ratio(p_device_pixel_ratio), + physical_width(p_physical_width), + physical_height(p_physical_height) {} + ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, double p_physical_width, double p_physical_height, @@ -44,11 +51,42 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, physical_system_gesture_inset_left(p_physical_system_gesture_inset_left) { } -ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio, - double p_physical_width, - double p_physical_height) - : device_pixel_ratio(p_device_pixel_ratio), - physical_width(p_physical_width), - physical_height(p_physical_height) {} +bool operator==(const ViewportMetrics& a, const ViewportMetrics& b) { + return a.device_pixel_ratio == b.device_pixel_ratio && + a.physical_width == b.physical_width && + a.physical_height == b.physical_height && + a.physical_padding_top == b.physical_padding_top && + a.physical_padding_right == b.physical_padding_right && + a.physical_padding_bottom == b.physical_padding_bottom && + a.physical_padding_left == b.physical_padding_left && + a.physical_view_inset_top == b.physical_view_inset_top && + a.physical_view_inset_right == b.physical_view_inset_right && + a.physical_view_inset_bottom == b.physical_view_inset_bottom && + a.physical_view_inset_left == b.physical_view_inset_left && + a.physical_system_gesture_inset_top == + b.physical_system_gesture_inset_top && + a.physical_system_gesture_inset_right == + b.physical_system_gesture_inset_right && + a.physical_system_gesture_inset_bottom == + b.physical_system_gesture_inset_bottom && + a.physical_system_gesture_inset_left == + b.physical_system_gesture_inset_left; +} + +std::ostream& operator<<(std::ostream& os, const ViewportMetrics& a) { + os << "DPR: " << a.device_pixel_ratio << " " + << "Size: [" << a.physical_width << "W " << a.physical_height << "H] " + << "Padding: [" << a.physical_padding_top << "T " + << a.physical_padding_right << "R " << a.physical_padding_bottom << "B " + << a.physical_padding_left << "L] " + << "Insets: [" << a.physical_view_inset_top << "T " + << a.physical_view_inset_right << "R " << a.physical_view_inset_bottom + << "B " << a.physical_view_inset_left << "L] " + << "Gesture Insets: [" << a.physical_system_gesture_inset_top << "T " + << a.physical_system_gesture_inset_right << "R " + << a.physical_system_gesture_inset_bottom << "B " + << a.physical_system_gesture_inset_left << "L]"; + return os; +} } // namespace flutter diff --git a/lib/ui/window/viewport_metrics.h b/lib/ui/window/viewport_metrics.h index 01081e3f3..adce20a91 100644 --- a/lib/ui/window/viewport_metrics.h +++ b/lib/ui/window/viewport_metrics.h @@ -5,10 +5,15 @@ #ifndef FLUTTER_LIB_UI_WINDOW_VIEWPORT_METRICS_H_ #define FLUTTER_LIB_UI_WINDOW_VIEWPORT_METRICS_H_ +#include + namespace flutter { struct ViewportMetrics { ViewportMetrics(); + ViewportMetrics(double p_device_pixel_ratio, + double p_physical_width, + double p_physical_height); ViewportMetrics(double p_device_pixel_ratio, double p_physical_width, double p_physical_height, @@ -25,12 +30,6 @@ struct ViewportMetrics { double p_physical_system_gesture_inset_bottom, double p_physical_system_gesture_inset_left); - // Create a ViewportMetrics instance that doesn't include depth, padding, or - // insets. - ViewportMetrics(double p_device_pixel_ratio, - double p_physical_width, - double p_physical_height); - double device_pixel_ratio = 1.0; double physical_width = 0; double physical_height = 0; @@ -48,24 +47,8 @@ struct ViewportMetrics { double physical_system_gesture_inset_left = 0; }; -struct LogicalSize { - double width = 0.0; - double height = 0.0; -}; - -struct LogicalInset { - double left = 0.0; - double top = 0.0; - double right = 0.0; - double bottom = 0.0; -}; - -struct LogicalMetrics { - LogicalSize size; - double scale = 1.0; - LogicalInset padding; - LogicalInset view_inset; -}; +bool operator==(const ViewportMetrics& a, const ViewportMetrics& b); +std::ostream& operator<<(std::ostream& os, const ViewportMetrics& a); } // namespace flutter diff --git a/shell/platform/fuchsia/flutter/platform_view.cc b/shell/platform/fuchsia/flutter/platform_view.cc index 60ffb5b92..db227ffd3 100644 --- a/shell/platform/fuchsia/flutter/platform_view.cc +++ b/shell/platform/fuchsia/flutter/platform_view.cc @@ -14,10 +14,11 @@ #include "flutter/fml/logging.h" #include "flutter/lib/ui/window/pointer_data.h" #include "flutter/lib/ui/window/window.h" +#include "third_party/rapidjson/include/rapidjson/document.h" +#include "third_party/rapidjson/include/rapidjson/stringbuffer.h" +#include "third_party/rapidjson/include/rapidjson/writer.h" + #include "logging.h" -#include "rapidjson/document.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/writer.h" #include "runtime/dart/utils/inlines.h" #include "vsync_waiter.h" @@ -214,7 +215,8 @@ void PlatformView::OnScenicError(std::string error) { void PlatformView::OnScenicEvent( std::vector events) { TRACE_EVENT0("flutter", "PlatformView::OnScenicEvent"); - bool should_update_metrics = false; + + bool metrics_changed = false; for (const auto& event : events) { switch (event.Which()) { case fuchsia::ui::scenic::Event::Tag::kGfx: @@ -223,31 +225,52 @@ void PlatformView::OnScenicEvent( const fuchsia::ui::gfx::Metrics& metrics = event.gfx().metrics().metrics; const float new_view_pixel_ratio = metrics.scale_x; + if (new_view_pixel_ratio <= 0.f) { + FML_DLOG(ERROR) + << "Got an invalid pixel ratio from Scenic; ignoring: " + << new_view_pixel_ratio; + break; + } // Avoid metrics update when possible -- it is computationally // expensive. - if (view_pixel_ratio_ != new_view_pixel_ratio) { - view_pixel_ratio_ = new_view_pixel_ratio; - should_update_metrics = true; + if (view_pixel_ratio_.has_value() && + *view_pixel_ratio_ == new_view_pixel_ratio) { + FML_DLOG(ERROR) + << "Got an identical pixel ratio from Scenic; ignoring: " + << new_view_pixel_ratio; + break; } + + view_pixel_ratio_ = new_view_pixel_ratio; + metrics_changed = true; break; } case fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged: { const fuchsia::ui::gfx::BoundingBox& bounding_box = event.gfx().view_properties_changed().properties.bounding_box; - const float new_view_width = - std::max(bounding_box.max.x - bounding_box.min.x, 0.0f); - const float new_view_height = - std::max(bounding_box.max.y - bounding_box.min.y, 0.0f); + const std::pair new_view_size = { + std::max(bounding_box.max.x - bounding_box.min.x, 0.0f), + std::max(bounding_box.max.y - bounding_box.min.y, 0.0f)}; + if (new_view_size.first <= 0.f || new_view_size.second <= 0.f) { + FML_DLOG(ERROR) + << "Got an invalid view size from Scenic; ignoring: " + << new_view_size.first << " " << new_view_size.second; + break; + } // Avoid metrics update when possible -- it is computationally // expensive. - if (view_width_ != new_view_width || - view_height_ != new_view_width) { - view_width_ = new_view_width; - view_height_ = new_view_height; - should_update_metrics = true; + if (view_logical_size_.has_value() && + *view_logical_size_ == new_view_size) { + FML_DLOG(ERROR) + << "Got an identical view size from Scenic; ignoring: " + << new_view_size.first << " " << new_view_size.second; + break; } + + view_logical_size_ = new_view_size; + metrics_changed = true; break; } case fuchsia::ui::gfx::Event::Tag::kViewConnected: @@ -298,19 +321,22 @@ void PlatformView::OnScenicEvent( } } - if (should_update_metrics) { + if (view_pixel_ratio_.has_value() && view_logical_size_.has_value() && + metrics_changed) { + const float pixel_ratio = *view_pixel_ratio_; + const std::pair logical_size = *view_logical_size_; SetViewportMetrics({ - view_pixel_ratio_, // device_pixel_ratio - view_width_ * view_pixel_ratio_, // physical_width - view_height_ * view_pixel_ratio_, // physical_height - 0.0f, // physical_padding_top - 0.0f, // physical_padding_right - 0.0f, // physical_padding_bottom - 0.0f, // physical_padding_left - 0.0f, // physical_view_inset_top - 0.0f, // physical_view_inset_right - 0.0f, // physical_view_inset_bottom - 0.0f, // physical_view_inset_left + pixel_ratio, // device_pixel_ratio + logical_size.first * pixel_ratio, // physical_width + logical_size.second * pixel_ratio, // physical_height + 0.0f, // physical_padding_top + 0.0f, // physical_padding_right + 0.0f, // physical_padding_bottom + 0.0f, // physical_padding_left + 0.0f, // physical_view_inset_top + 0.0f, // physical_view_inset_right + 0.0f, // physical_view_inset_bottom + 0.0f, // physical_view_inset_left 0.0f, // p_physical_system_gesture_inset_top 0.0f, // p_physical_system_gesture_inset_right 0.0f, // p_physical_system_gesture_inset_bottom @@ -421,6 +447,9 @@ bool PlatformView::OnHandlePointerEvent( PointerTraceHACK(pointer.radius_major, pointer.radius_minor); TRACE_FLOW_END("input", "dispatch_event_to_client", trace_id); + const float pixel_ratio = + view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f; + flutter::PointerData pointer_data; pointer_data.Clear(); pointer_data.time_stamp = pointer.event_time / 1000; @@ -428,8 +457,8 @@ bool PlatformView::OnHandlePointerEvent( pointer_data.kind = GetKindFromPointerType(pointer.type); pointer_data.device = pointer.pointer_id; // Pointer events are in logical pixels, so scale to physical. - pointer_data.physical_x = pointer.x * view_pixel_ratio_; - pointer_data.physical_y = pointer.y * view_pixel_ratio_; + pointer_data.physical_x = pointer.x * pixel_ratio; + pointer_data.physical_y = pointer.y * pixel_ratio; // Buttons are single bit values starting with kMousePrimaryButton = 1. pointer_data.buttons = static_cast(pointer.buttons); @@ -601,7 +630,10 @@ void PlatformView::DispatchSemanticsAction(int32_t node_id, void PlatformView::UpdateSemantics( flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { - accessibility_bridge_->AddSemanticsNodeUpdate(update, view_pixel_ratio_); + const float pixel_ratio = + view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f; + + accessibility_bridge_->AddSemanticsNodeUpdate(update, pixel_ratio); } // Channel handler for kAccessibilityChannel diff --git a/shell/platform/fuchsia/flutter/platform_view.h b/shell/platform/fuchsia/flutter/platform_view.h index 7b9c20582..a888298f9 100644 --- a/shell/platform/fuchsia/flutter/platform_view.h +++ b/shell/platform/fuchsia/flutter/platform_view.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -19,8 +20,6 @@ #include "accessibility_bridge.h" -#include // nogncheck - namespace flutter_runner { using OnEnableWireframe = fit::function; @@ -29,16 +28,22 @@ using OnUpdateView = fit::function; using OnDestroyView = fit::function; using OnCreateSurface = fit::function()>; -// The per engine component residing on the platform thread is responsible for -// all platform specific integrations. +// PlatformView is the per-engine component residing on the platform thread that +// is responsible for all platform specific integrations -- particularly +// integration with the platform's accessibility, input, and windowing features. +// +// PlatformView communicates with the Dart code via "platform messages" handled +// in HandlePlatformMessage. This communication is bidirectional. Platform +// messages are notably responsible for communication related to input and +// external views / windowing. // // The PlatformView implements SessionListener and gets Session events but it -// does *not* actually own the Session itself; that is owned by the Compositor -// thread. +// does *not* actually own the Session itself; that is owned by the +// FuchsiaExternalViewEmbedder on the raster thread. class PlatformView final : public flutter::PlatformView, + public AccessibilityBridge::Delegate, private fuchsia::ui::scenic::SessionListener, - public fuchsia::ui::input::InputMethodEditorClient, - public AccessibilityBridge::Delegate { + private fuchsia::ui::input::InputMethodEditorClient { public: PlatformView(flutter::PlatformView::Delegate& delegate, std::string debug_label, @@ -73,51 +78,6 @@ class PlatformView final : public flutter::PlatformView, flutter::PointerDataDispatcherMaker GetDispatcherMaker() override; private: - const std::string debug_label_; - // TODO(MI4-2490): remove once ViewRefControl is passed to Scenic and kept - // alive there - const fuchsia::ui::views::ViewRef view_ref_; - fuchsia::ui::views::FocuserPtr focuser_; - std::unique_ptr accessibility_bridge_; - - fidl::Binding session_listener_binding_; - fit::closure session_listener_error_callback_; - OnEnableWireframe wireframe_enabled_callback_; - OnCreateView on_create_view_callback_; - OnUpdateView on_update_view_callback_; - OnDestroyView on_destroy_view_callback_; - OnCreateSurface on_create_surface_callback_; - - int current_text_input_client_ = 0; - fidl::Binding ime_client_; - fuchsia::ui::input::InputMethodEditorPtr ime_; - fuchsia::ui::input::ImeServicePtr text_sync_service_; - - fuchsia::sys::ServiceProviderPtr parent_environment_service_provider_; - - // last_text_state_ is the last state of the text input as reported by the IME - // or initialized by Flutter. We set it to null if Flutter doesn't want any - // input, since then there is no text input state at all. - std::unique_ptr last_text_state_; - - std::set down_pointers_; - std::map< - std::string /* channel */, - fit::function /* message */)> /* handler */> - platform_message_handlers_; - // These are the channels that aren't registered and have been notified as - // such. Notifying via logs multiple times results in log-spam. See: - // https://github.com/flutter/flutter/issues/55966 - std::set unregistered_channels_; - - fml::TimeDelta vsync_offset_; - zx_handle_t vsync_event_handle_ = 0; - - float view_width_ = 0.0f; // Width in logical pixels. - float view_height_ = 0.0f; // Height in logical pixels. - float view_pixel_ratio_ = 0.0f; // Logical / physical pixel ratio. - void RegisterPlatformMessageHandlers(); // |fuchsia::ui::input::InputMethodEditorClient| @@ -185,6 +145,57 @@ class PlatformView final : public flutter::PlatformView, void HandleFlutterPlatformViewsChannelPlatformMessage( fml::RefPtr message); + const std::string debug_label_; + // TODO(MI4-2490): remove once ViewRefControl is passed to Scenic and kept + // alive there + const fuchsia::ui::views::ViewRef view_ref_; + fuchsia::ui::views::FocuserPtr focuser_; + std::unique_ptr accessibility_bridge_; + + // Logical size and logical->physical ratio. These are optional to provide + // an "unset" state during program startup, before Scenic has sent any + // metrics-related events to provide initial values for these. + // + // The engine internally uses a default size of (0.f 0.f) with a default 1.f + // ratio, so there is no need to emit events until Scenic has actually sent a + // valid size and ratio. + std::optional> view_logical_size_; + std::optional view_pixel_ratio_; + + fidl::Binding session_listener_binding_; + fit::closure session_listener_error_callback_; + OnEnableWireframe wireframe_enabled_callback_; + OnCreateView on_create_view_callback_; + OnUpdateView on_update_view_callback_; + OnDestroyView on_destroy_view_callback_; + OnCreateSurface on_create_surface_callback_; + + int current_text_input_client_ = 0; + fidl::Binding ime_client_; + fuchsia::ui::input::InputMethodEditorPtr ime_; + fuchsia::ui::input::ImeServicePtr text_sync_service_; + + fuchsia::sys::ServiceProviderPtr parent_environment_service_provider_; + + // last_text_state_ is the last state of the text input as reported by the IME + // or initialized by Flutter. We set it to null if Flutter doesn't want any + // input, since then there is no text input state at all. + std::unique_ptr last_text_state_; + + std::set down_pointers_; + std::map< + std::string /* channel */, + fit::function /* message */)> /* handler */> + platform_message_handlers_; + // These are the channels that aren't registered and have been notified as + // such. Notifying via logs multiple times results in log-spam. See: + // https://github.com/flutter/flutter/issues/55966 + std::set unregistered_channels_; + + fml::TimeDelta vsync_offset_; + zx_handle_t vsync_event_handle_ = 0; + FML_DISALLOW_COPY_AND_ASSIGN(PlatformView); }; diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index c3c4c46ed..63f010ed6 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -4,50 +4,35 @@ #include "flutter/shell/platform/fuchsia/flutter/platform_view.h" +#include +#include #include #include #include #include #include -#include #include +#include #include +#include +#include #include #include "flutter/flow/embedded_views.h" #include "flutter/lib/ui/window/platform_message.h" -#include "flutter/lib/ui/window/window.h" +#include "flutter/lib/ui/window/viewport_metrics.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "surface.h" #include "task_runner_adapter.h" -namespace flutter_runner_test::flutter_runner_a11y_test { - -class PlatformViewTests : public testing::Test { - protected: - PlatformViewTests() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {} - - async_dispatcher_t* dispatcher() { return loop_.dispatcher(); } - - void RunLoopUntilIdle() { - loop_.RunUntilIdle(); - loop_.ResetQuit(); - } - - private: - async::Loop loop_; - - FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewTests); -}; +namespace flutter_runner::testing { +namespace { class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder { public: - MockExternalViewEmbedder() = default; - ~MockExternalViewEmbedder() override = default; - SkCanvas* GetRootCanvas() override { return nullptr; } std::vector GetCurrentCanvases() override { return std::vector(); @@ -82,7 +67,9 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { void OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {} // |flutter::PlatformView::Delegate| void OnPlatformViewSetViewportMetrics( - const flutter::ViewportMetrics& metrics) {} + const flutter::ViewportMetrics& metrics) { + metrics_ = metrics; + } // |flutter::PlatformView::Delegate| void OnPlatformViewDispatchPlatformMessage( fml::RefPtr message) { @@ -113,43 +100,45 @@ class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { // |flutter::PlatformView::Delegate| std::unique_ptr> ComputePlatformViewResolvedLocale( const std::vector& supported_locale_data) { - std::unique_ptr> out = - std::make_unique>(); - return out; + return nullptr; } - bool SemanticsEnabled() const { return semantics_enabled_; } - int32_t SemanticsFeatures() const { return semantics_features_; } flutter::Surface* surface() const { return surface_.get(); } - fml::RefPtr& message() { return message_; } + flutter::PlatformMessage* message() const { return message_.get(); } + const flutter::ViewportMetrics& metrics() const { return metrics_; } + int32_t semantics_features() const { return semantics_features_; } + bool semantics_enabled() const { return semantics_enabled_; } private: std::unique_ptr surface_; - bool semantics_enabled_ = false; - int32_t semantics_features_ = 0; fml::RefPtr message_; + flutter::ViewportMetrics metrics_; + int32_t semantics_features_ = 0; + bool semantics_enabled_ = false; }; class MockFocuser : public fuchsia::ui::views::Focuser { public: - MockFocuser() = default; - ~MockFocuser() override = default; + MockFocuser(bool fail_request_focus = false) + : fail_request_focus_(fail_request_focus) {} - bool request_focus_called = false; - bool fail_request_focus = false; + bool request_focus_called() const { return request_focus_called_; } private: void RequestFocus(fuchsia::ui::views::ViewRef view_ref, RequestFocusCallback callback) override { - request_focus_called = true; + request_focus_called_ = true; auto result = - fail_request_focus + fail_request_focus_ ? fuchsia::ui::views::Focuser_RequestFocus_Result::WithErr( fuchsia::ui::views::Error::DENIED) : fuchsia::ui::views::Focuser_RequestFocus_Result::WithResponse( fuchsia::ui::views::Focuser_RequestFocus_Response()); callback(std::move(result)); } + + bool request_focus_called_ = false; + bool fail_request_focus_ = false; }; class MockResponse : public flutter::PlatformMessageResponse { @@ -158,25 +147,228 @@ class MockResponse : public flutter::PlatformMessageResponse { MOCK_METHOD0(CompleteEmpty, void()); }; +} // namespace + +class PlatformViewTests : public ::testing::Test { + protected: + PlatformViewTests() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {} + + async_dispatcher_t* dispatcher() { return loop_.dispatcher(); } + + void RunLoopUntilIdle() { + loop_.RunUntilIdle(); + loop_.ResetQuit(); + } + + private: + async::Loop loop_; + + FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewTests); +}; + +// This test makes sure that the PlatformView correctly returns a Surface +// instance that can surface the provided gr_context and view_embedder. +TEST_F(PlatformViewTests, CreateSurfaceTest) { + sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); + MockPlatformViewDelegate delegate; + + flutter::TaskRunners task_runners = + flutter::TaskRunners("test_runners", // label + nullptr, // platform + flutter_runner::CreateFMLTaskRunner( + async_get_default_dispatcher()), // raster + nullptr, // ui + nullptr // io + ); + + // Test create surface callback function. + sk_sp gr_context = + GrDirectContext::MakeMock(nullptr, GrContextOptions()); + MockExternalViewEmbedder view_embedder; + auto CreateSurfaceCallback = [&view_embedder, gr_context]() { + return std::make_unique( + "PlatformViewTest", &view_embedder, gr_context.get()); + }; + + auto platform_view = flutter_runner::PlatformView( + delegate, // delegate + "test_platform_view", // label + fuchsia::ui::views::ViewRef(), // view_ref + std::move(task_runners), // task_runners + services_provider.service_directory(), // runner_services + nullptr, // parent_environment_service_provider_handle + nullptr, // session_listener_request + nullptr, // focuser, + nullptr, // on_session_listener_error_callback + nullptr, // on_enable_wireframe_callback, + nullptr, // on_create_view_callback, + nullptr, // on_update_view_callback, + nullptr, // on_destroy_view_callback, + CreateSurfaceCallback, // on_create_surface_callback, + fml::TimeDelta::Zero(), // vsync_offset + ZX_HANDLE_INVALID // vsync_event_handle + ); + platform_view.NotifyCreated(); + + RunLoopUntilIdle(); + + EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext()); + EXPECT_EQ(&view_embedder, delegate.surface()->GetExternalViewEmbedder()); +} + +// This test makes sure that the PlatformView correctly registers Scenic +// MetricsEvents sent to it via FIDL, correctly parses the metrics it receives, +// and calls the SetViewportMetrics callback with the appropriate parameters. +TEST_F(PlatformViewTests, SetViewportMetrics) { + constexpr float invalid_pixel_ratio = -0.75f; + constexpr float valid_pixel_ratio = 0.75f; + constexpr float invalid_max_bound = -0.75f; + constexpr float valid_max_bound = 0.75f; + + MockPlatformViewDelegate delegate; + EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics()); + + fuchsia::ui::scenic::SessionListenerPtr session_listener; + std::vector events; + sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); + flutter::TaskRunners task_runners("test_runners", nullptr, nullptr, nullptr, + nullptr); + flutter_runner::PlatformView platform_view( + delegate, // delegate + "test_platform_view", // label + fuchsia::ui::views::ViewRef(), // view_ref + std::move(task_runners), // task_runners + services_provider.service_directory(), // runner_services + nullptr, // parent_environment_service_provider_handle + session_listener.NewRequest(), // session_listener_request + nullptr, // focuser, + nullptr, // on_session_listener_error_callback + nullptr, // on_enable_wireframe_callback, + nullptr, // on_create_view_callback, + nullptr, // on_update_view_callback, + nullptr, // on_destroy_view_callback, + nullptr, // on_create_surface_callback, + fml::TimeDelta::Zero(), // vsync_offset + ZX_HANDLE_INVALID // vsync_event_handle + ); + RunLoopUntilIdle(); + EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics()); + + // Test updating with an invalid pixel ratio. The final metrics should be + // unchanged. + events.clear(); + events.emplace_back(fuchsia::ui::scenic::Event::WithGfx( + fuchsia::ui::gfx::Event::WithMetrics(fuchsia::ui::gfx::MetricsEvent{ + .node_id = 0, + .metrics = + fuchsia::ui::gfx::Metrics{ + .scale_x = invalid_pixel_ratio, + .scale_y = 1.f, + .scale_z = 1.f, + }, + }))); + session_listener->OnScenicEvent(std::move(events)); + RunLoopUntilIdle(); + EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics()); + + // Test updating with an invalid size. The final metrics should be unchanged. + events.clear(); + events.emplace_back( + fuchsia::ui::scenic::Event::WithGfx( + fuchsia::ui::gfx::Event::WithViewPropertiesChanged( + fuchsia::ui::gfx::ViewPropertiesChangedEvent{ + .view_id = 0, + .properties = + fuchsia::ui::gfx::ViewProperties{ + .bounding_box = + fuchsia::ui::gfx::BoundingBox{ + .min = + fuchsia::ui::gfx::vec3{ + .x = 0.f, + .y = 0.f, + .z = 0.f, + }, + .max = + fuchsia::ui::gfx::vec3{ + .x = invalid_max_bound, + .y = invalid_max_bound, + .z = invalid_max_bound, + }, + }, + }, + }))); + session_listener->OnScenicEvent(std::move(events)); + RunLoopUntilIdle(); + EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics()); + + // Test updating the size only. The final metrics should be unchanged until + // both pixel ratio and size are updated. + events.clear(); + events.emplace_back( + fuchsia::ui::scenic::Event::WithGfx( + fuchsia::ui::gfx::Event::WithViewPropertiesChanged( + fuchsia::ui::gfx::ViewPropertiesChangedEvent{ + .view_id = 0, + .properties = + fuchsia::ui::gfx::ViewProperties{ + .bounding_box = + fuchsia::ui::gfx::BoundingBox{ + .min = + fuchsia::ui::gfx::vec3{ + .x = 0.f, + .y = 0.f, + .z = 0.f, + }, + .max = + fuchsia::ui::gfx::vec3{ + .x = valid_max_bound, + .y = valid_max_bound, + .z = valid_max_bound, + }, + }, + }, + }))); + session_listener->OnScenicEvent(std::move(events)); + RunLoopUntilIdle(); + EXPECT_EQ(delegate.metrics(), flutter::ViewportMetrics()); + + // Test updating the pixel ratio only. The final metrics should change now. + events.clear(); + events.emplace_back(fuchsia::ui::scenic::Event::WithGfx( + fuchsia::ui::gfx::Event::WithMetrics(fuchsia::ui::gfx::MetricsEvent{ + .node_id = 0, + .metrics = + fuchsia::ui::gfx::Metrics{ + .scale_x = valid_pixel_ratio, + .scale_y = 1.f, + .scale_z = 1.f, + }, + }))); + session_listener->OnScenicEvent(std::move(events)); + RunLoopUntilIdle(); + EXPECT_EQ(delegate.metrics(), + flutter::ViewportMetrics(valid_pixel_ratio, + valid_pixel_ratio * valid_max_bound, + valid_pixel_ratio * valid_max_bound)); +} + +// This test makes sure that the PlatformView correctly registers semantics +// settings changes applied to it and calls the SetSemanticsEnabled / +// SetAccessibilityFeatures callbacks with the appropriate parameters. TEST_F(PlatformViewTests, ChangesAccessibilitySettings) { sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); MockPlatformViewDelegate delegate; - zx::eventpair a, b; - zx::eventpair::create(/* flags */ 0u, &a, &b); - auto view_ref = fuchsia::ui::views::ViewRef({ - .reference = std::move(a), - }); flutter::TaskRunners task_runners = flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr); - EXPECT_FALSE(delegate.SemanticsEnabled()); - EXPECT_EQ(delegate.SemanticsFeatures(), 0); + EXPECT_FALSE(delegate.semantics_enabled()); + EXPECT_EQ(delegate.semantics_features(), 0); auto platform_view = flutter_runner::PlatformView( delegate, // delegate "test_platform_view", // label - std::move(view_ref), // view_ref + fuchsia::ui::views::ViewRef(), // view_ref std::move(task_runners), // task_runners services_provider.service_directory(), // runner_services nullptr, // parent_environment_service_provider_handle @@ -196,28 +388,22 @@ TEST_F(PlatformViewTests, ChangesAccessibilitySettings) { platform_view.SetSemanticsEnabled(true); - EXPECT_TRUE(delegate.SemanticsEnabled()); - EXPECT_EQ(delegate.SemanticsFeatures(), + EXPECT_TRUE(delegate.semantics_enabled()); + EXPECT_EQ(delegate.semantics_features(), static_cast( flutter::AccessibilityFeatureFlag::kAccessibleNavigation)); platform_view.SetSemanticsEnabled(false); - EXPECT_FALSE(delegate.SemanticsEnabled()); - EXPECT_EQ(delegate.SemanticsFeatures(), 0); + EXPECT_FALSE(delegate.semantics_enabled()); + EXPECT_EQ(delegate.semantics_features(), 0); } -// Test to make sure that PlatformView correctly registers messages sent on -// the "flutter/platform_views" channel, correctly parses the JSON it receives -// and calls the EnableWireframeCallback with the appropriate args. +// This test makes sure that the PlatformView forwards messages on the +// "flutter/platform_views" channel for EnableWireframe. TEST_F(PlatformViewTests, EnableWireframeTest) { sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); MockPlatformViewDelegate delegate; - zx::eventpair a, b; - zx::eventpair::create(/* flags */ 0u, &a, &b); - auto view_ref = fuchsia::ui::views::ViewRef({ - .reference = std::move(a), - }); flutter::TaskRunners task_runners = flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr); @@ -232,7 +418,7 @@ TEST_F(PlatformViewTests, EnableWireframeTest) { auto platform_view = flutter_runner::PlatformView( delegate, // delegate "test_platform_view", // label - std::move(view_ref), // view_refs + fuchsia::ui::views::ViewRef(), // view_ref std::move(task_runners), // task_runners services_provider.service_directory(), // runner_services nullptr, // parent_environment_service_provider_handle @@ -274,17 +460,11 @@ TEST_F(PlatformViewTests, EnableWireframeTest) { EXPECT_TRUE(wireframe_enabled); } -// Test to make sure that PlatformView correctly registers messages sent on -// the "flutter/platform_views" channel, correctly parses the JSON it receives -// and calls the CreateViewCallback with the appropriate args. +// This test makes sure that the PlatformView forwards messages on the +// "flutter/platform_views" channel for Createview. TEST_F(PlatformViewTests, CreateViewTest) { sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); MockPlatformViewDelegate delegate; - zx::eventpair a, b; - zx::eventpair::create(/* flags */ 0u, &a, &b); - auto view_ref = fuchsia::ui::views::ViewRef({ - .reference = std::move(a), - }); flutter::TaskRunners task_runners = flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr); @@ -299,7 +479,7 @@ TEST_F(PlatformViewTests, CreateViewTest) { auto platform_view = flutter_runner::PlatformView( delegate, // delegate "test_platform_view", // label - std::move(view_ref), // view_refs + fuchsia::ui::views::ViewRef(), // view_ref std::move(task_runners), // task_runners services_provider.service_directory(), // runner_services nullptr, // parent_environment_service_provider_handle @@ -343,17 +523,11 @@ TEST_F(PlatformViewTests, CreateViewTest) { EXPECT_TRUE(create_view_called); } -// Test to make sure that PlatformView correctly registers messages sent on -// the "flutter/platform_views" channel, correctly parses the JSON it receives -// and calls the UdpateViewCallback with the appropriate args. +// This test makes sure that the PlatformView forwards messages on the +// "flutter/platform_views" channel for UpdateView. TEST_F(PlatformViewTests, UpdateViewTest) { sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); MockPlatformViewDelegate delegate; - zx::eventpair a, b; - zx::eventpair::create(/* flags */ 0u, &a, &b); - auto view_ref = fuchsia::ui::views::ViewRef({ - .reference = std::move(a), - }); flutter::TaskRunners task_runners = flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr); @@ -368,7 +542,7 @@ TEST_F(PlatformViewTests, UpdateViewTest) { auto platform_view = flutter_runner::PlatformView( delegate, // delegate "test_platform_view", // label - std::move(view_ref), // view_refs + fuchsia::ui::views::ViewRef(), // view_ref std::move(task_runners), // task_runners services_provider.service_directory(), // runner_services nullptr, // parent_environment_service_provider_handle @@ -412,17 +586,11 @@ TEST_F(PlatformViewTests, UpdateViewTest) { EXPECT_TRUE(update_view_called); } -// Test to make sure that PlatformView correctly registers messages sent on -// the "flutter/platform_views" channel, correctly parses the JSON it receives -// and calls the DestroyViewCallback with the appropriate args. +// This test makes sure that the PlatformView forwards messages on the +// "flutter/platform_views" channel for DestroyView. TEST_F(PlatformViewTests, DestroyViewTest) { sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); MockPlatformViewDelegate delegate; - zx::eventpair a, b; - zx::eventpair::create(/* flags */ 0u, &a, &b); - auto view_ref = fuchsia::ui::views::ViewRef({ - .reference = std::move(a), - }); flutter::TaskRunners task_runners = flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr); @@ -437,7 +605,7 @@ TEST_F(PlatformViewTests, DestroyViewTest) { auto platform_view = flutter_runner::PlatformView( delegate, // delegate "test_platform_view", // label - std::move(view_ref), // view_refs + fuchsia::ui::views::ViewRef(), // view_ref std::move(task_runners), // task_runners services_provider.service_directory(), // runner_services nullptr, // parent_environment_service_provider_handle @@ -479,17 +647,96 @@ TEST_F(PlatformViewTests, DestroyViewTest) { EXPECT_TRUE(destroy_view_called); } -// Test to make sure that PlatformView correctly registers messages sent on -// the "flutter/platform_views" channel, correctly parses the JSON it receives -// and calls the focuser's RequestFocus with the appropriate args. +// This test makes sure that the PlatformView forwards messages on the +// "flutter/platform_views" channel for ViewConnected, ViewDisconnected, and +// ViewStateChanged events. +TEST_F(PlatformViewTests, ViewEventsTest) { + MockPlatformViewDelegate delegate; + + fuchsia::ui::scenic::SessionListenerPtr session_listener; + std::vector events; + sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); + + flutter::TaskRunners task_runners = flutter::TaskRunners( + "test_runners", nullptr, nullptr, + flutter_runner::CreateFMLTaskRunner(async_get_default_dispatcher()), + nullptr); + + auto platform_view = flutter_runner::PlatformView( + delegate, // delegate + "test_platform_view", // label + fuchsia::ui::views::ViewRef(), // view_ref + std::move(task_runners), // task_runners + services_provider.service_directory(), // runner_services + nullptr, // parent_environment_service_provider_handle + session_listener.NewRequest(), // session_listener_request + nullptr, // focuser, + nullptr, // on_session_listener_error_callback + nullptr, // on_enable_wireframe_callback, + nullptr, // on_create_view_callback, + nullptr, // on_update_view_callback, + nullptr, // on_destroy_view_callback, + nullptr, // on_create_surface_callback, + fml::TimeDelta::Zero(), // vsync_offset + ZX_HANDLE_INVALID // vsync_event_handle + ); + RunLoopUntilIdle(); + + // ViewConnected event. + events.clear(); + events.emplace_back(fuchsia::ui::scenic::Event::WithGfx( + fuchsia::ui::gfx::Event::WithViewConnected( + fuchsia::ui::gfx::ViewConnectedEvent{ + .view_holder_id = 0, + }))); + session_listener->OnScenicEvent(std::move(events)); + RunLoopUntilIdle(); + + auto data = delegate.message()->data(); + auto call = std::string(data.begin(), data.end()); + std::string expected = "{\"method\":\"View.viewConnected\",\"args\":null}"; + EXPECT_EQ(expected, call); + + // ViewDisconnected event. + events.clear(); + events.emplace_back(fuchsia::ui::scenic::Event::WithGfx( + fuchsia::ui::gfx::Event::WithViewDisconnected( + fuchsia::ui::gfx::ViewDisconnectedEvent{ + .view_holder_id = 0, + }))); + session_listener->OnScenicEvent(std::move(events)); + RunLoopUntilIdle(); + + data = delegate.message()->data(); + call = std::string(data.begin(), data.end()); + expected = "{\"method\":\"View.viewDisconnected\",\"args\":null}"; + EXPECT_EQ(expected, call); + + // ViewStateChanged event. + events.clear(); + events.emplace_back(fuchsia::ui::scenic::Event::WithGfx( + fuchsia::ui::gfx::Event::WithViewStateChanged( + fuchsia::ui::gfx::ViewStateChangedEvent{ + .view_holder_id = 0, + .state = + fuchsia::ui::gfx::ViewState{ + .is_rendering = true, + }, + }))); + session_listener->OnScenicEvent(std::move(events)); + RunLoopUntilIdle(); + + data = delegate.message()->data(); + call = std::string(data.begin(), data.end()); + expected = "{\"method\":\"View.viewStateChanged\",\"args\":{\"state\":true}}"; + EXPECT_EQ(expected, call); +} + +// This test makes sure that the PlatformView forwards messages on the +// "flutter/platform_views" channel for RequestFocus. TEST_F(PlatformViewTests, RequestFocusTest) { sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); MockPlatformViewDelegate delegate; - zx::eventpair a, b; - zx::eventpair::create(/* flags */ 0u, &a, &b); - auto view_ref = fuchsia::ui::views::ViewRef({ - .reference = std::move(a), - }); flutter::TaskRunners task_runners = flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr); @@ -500,7 +747,7 @@ TEST_F(PlatformViewTests, RequestFocusTest) { auto platform_view = flutter_runner::PlatformView( delegate, // delegate "test_platform_view", // label - std::move(view_ref), // view_refs + fuchsia::ui::views::ViewRef(), // view_ref std::move(task_runners), // task_runners services_provider.service_directory(), // runner_services nullptr, // parent_environment_service_provider_handle @@ -521,6 +768,9 @@ TEST_F(PlatformViewTests, RequestFocusTest) { auto base_view = dynamic_cast(&platform_view); EXPECT_TRUE(base_view); + // This "Mock" ViewRef serves as the target for the RequestFocus operation. + auto mock_view_ref_pair = scenic::ViewRefPair::New(); + // JSON for the message to be passed into the PlatformView. char buff[254]; snprintf(buff, sizeof(buff), @@ -530,7 +780,7 @@ TEST_F(PlatformViewTests, RequestFocusTest) { " \"viewRef\":%u" " }" "}", - b.get()); + mock_view_ref_pair.view_ref.reference.get()); // Define a custom gmock matcher to capture the response to platform message. struct DataArg { @@ -541,8 +791,8 @@ TEST_F(PlatformViewTests, RequestFocusTest) { }; DataArg data_arg; fml::RefPtr response = fml::MakeRefCounted(); - EXPECT_CALL(*response, Complete(testing::_)) - .WillOnce(testing::Invoke(&data_arg, &DataArg::Complete)); + EXPECT_CALL(*response, Complete(::testing::_)) + .WillOnce(::testing::Invoke(&data_arg, &DataArg::Complete)); fml::RefPtr message = fml::MakeRefCounted( @@ -552,35 +802,28 @@ TEST_F(PlatformViewTests, RequestFocusTest) { RunLoopUntilIdle(); - EXPECT_TRUE(mock_focuser.request_focus_called); + EXPECT_TRUE(mock_focuser.request_focus_called()); auto result = std::string((const char*)data_arg.data->GetMapping(), data_arg.data->GetSize()); EXPECT_EQ(std::string("[0]"), result); } -// Test to make sure that PlatformView correctly registers messages sent on -// the "flutter/platform_views" channel, correctly parses the JSON it receives -// and calls the focuser's RequestFocus with the appropriate args. +// This test makes sure that the PlatformView correctly replies with an error +// response when a RequestFocus call fails. TEST_F(PlatformViewTests, RequestFocusFailTest) { sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); MockPlatformViewDelegate delegate; - zx::eventpair a, b; - zx::eventpair::create(/* flags */ 0u, &a, &b); - auto view_ref = fuchsia::ui::views::ViewRef({ - .reference = std::move(a), - }); flutter::TaskRunners task_runners = flutter::TaskRunners("test_runners", nullptr, nullptr, nullptr, nullptr); - MockFocuser mock_focuser; - mock_focuser.fail_request_focus = true; + MockFocuser mock_focuser(true /*fail_request_focus*/); fidl::BindingSet focuser_bindings; auto focuser_handle = focuser_bindings.AddBinding(&mock_focuser); auto platform_view = flutter_runner::PlatformView( delegate, // delegate "test_platform_view", // label - std::move(view_ref), // view_refs + fuchsia::ui::views::ViewRef(), // view_ref std::move(task_runners), // task_runners services_provider.service_directory(), // runner_services nullptr, // parent_environment_service_provider_handle @@ -601,6 +844,9 @@ TEST_F(PlatformViewTests, RequestFocusFailTest) { auto base_view = dynamic_cast(&platform_view); EXPECT_TRUE(base_view); + // This "Mock" ViewRef serves as the target for the RequestFocus operation. + auto mock_view_ref_pair = scenic::ViewRefPair::New(); + // JSON for the message to be passed into the PlatformView. char buff[254]; snprintf(buff, sizeof(buff), @@ -610,7 +856,7 @@ TEST_F(PlatformViewTests, RequestFocusFailTest) { " \"viewRef\":%u" " }" "}", - b.get()); + mock_view_ref_pair.view_ref.reference.get()); // Define a custom gmock matcher to capture the response to platform message. struct DataArg { @@ -621,8 +867,8 @@ TEST_F(PlatformViewTests, RequestFocusFailTest) { }; DataArg data_arg; fml::RefPtr response = fml::MakeRefCounted(); - EXPECT_CALL(*response, Complete(testing::_)) - .WillOnce(testing::Invoke(&data_arg, &DataArg::Complete)); + EXPECT_CALL(*response, Complete(::testing::_)) + .WillOnce(::testing::Invoke(&data_arg, &DataArg::Complete)); fml::RefPtr message = fml::MakeRefCounted( @@ -632,7 +878,7 @@ TEST_F(PlatformViewTests, RequestFocusFailTest) { RunLoopUntilIdle(); - EXPECT_TRUE(mock_focuser.request_focus_called); + EXPECT_TRUE(mock_focuser.request_focus_called()); auto result = std::string((const char*)data_arg.data->GetMapping(), data_arg.data->GetSize()); std::ostringstream out; @@ -643,143 +889,4 @@ TEST_F(PlatformViewTests, RequestFocusFailTest) { EXPECT_EQ(out.str(), result); } -// Test to make sure that PlatformView forward messages on the -// "flutter/platform_views" channel, for viewConnected/viewDisconnected and -// viewStateChanged events. -TEST_F(PlatformViewTests, ViewEventsTest) { - MockPlatformViewDelegate delegate; - - fuchsia::ui::scenic::SessionListenerPtr session_listener; - std::vector events; - sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); - - flutter::TaskRunners task_runners = flutter::TaskRunners( - "test_runners", nullptr, nullptr, - flutter_runner::CreateFMLTaskRunner(async_get_default_dispatcher()), - nullptr); - - auto platform_view = flutter_runner::PlatformView( - delegate, // delegate - "test_platform_view", // label - fuchsia::ui::views::ViewRef{}, // view_ref - std::move(task_runners), // task_runners - services_provider.service_directory(), // runner_services - nullptr, // parent_environment_service_provider_handle - session_listener.NewRequest(), // session_listener_request - nullptr, // focuser, - nullptr, // on_session_listener_error_callback - nullptr, // on_enable_wireframe_callback, - nullptr, // on_create_view_callback, - nullptr, // on_update_view_callback, - nullptr, // on_destroy_view_callback, - nullptr, // on_create_surface_callback, - fml::TimeDelta::Zero(), // vsync_offset - ZX_HANDLE_INVALID // vsync_event_handle - ); - RunLoopUntilIdle(); - - // ViewConnected event. - events.clear(); - events.emplace_back(fuchsia::ui::scenic::Event::WithGfx( - fuchsia::ui::gfx::Event::WithViewConnected( - fuchsia::ui::gfx::ViewConnectedEvent{ - .view_holder_id = 0, - }))); - session_listener->OnScenicEvent(std::move(events)); - RunLoopUntilIdle(); - - auto data = delegate.message()->data(); - auto call = std::string(data.begin(), data.end()); - std::string expected = "{\"method\":\"View.viewConnected\",\"args\":null}"; - EXPECT_EQ(expected, call); - - // ViewDisconnected event. - events.clear(); - events.emplace_back(fuchsia::ui::scenic::Event::WithGfx( - fuchsia::ui::gfx::Event::WithViewDisconnected( - fuchsia::ui::gfx::ViewDisconnectedEvent{ - .view_holder_id = 0, - }))); - session_listener->OnScenicEvent(std::move(events)); - RunLoopUntilIdle(); - - data = delegate.message()->data(); - call = std::string(data.begin(), data.end()); - expected = "{\"method\":\"View.viewDisconnected\",\"args\":null}"; - EXPECT_EQ(expected, call); - - // ViewStateChanged event. - events.clear(); - events.emplace_back(fuchsia::ui::scenic::Event::WithGfx( - fuchsia::ui::gfx::Event::WithViewStateChanged( - fuchsia::ui::gfx::ViewStateChangedEvent{ - .view_holder_id = 0, - .state = - fuchsia::ui::gfx::ViewState{ - .is_rendering = true, - }, - }))); - session_listener->OnScenicEvent(std::move(events)); - RunLoopUntilIdle(); - - data = delegate.message()->data(); - call = std::string(data.begin(), data.end()); - expected = "{\"method\":\"View.viewStateChanged\",\"args\":{\"state\":true}}"; - EXPECT_EQ(expected, call); -} - -// Test to make sure that PlatformView correctly returns a Surface instance -// that can surface the provided gr_context and view_embedder. -TEST_F(PlatformViewTests, CreateSurfaceTest) { - sys::testing::ServiceDirectoryProvider services_provider(dispatcher()); - MockPlatformViewDelegate delegate; - zx::eventpair a, b; - zx::eventpair::create(/* flags */ 0u, &a, &b); - auto view_ref = fuchsia::ui::views::ViewRef({ - .reference = std::move(a), - }); - flutter::TaskRunners task_runners = - flutter::TaskRunners("test_runners", // label - nullptr, // platform - flutter_runner::CreateFMLTaskRunner( - async_get_default_dispatcher()), // raster - nullptr, // ui - nullptr // io - ); - - // Test create surface callback function. - sk_sp gr_context = - GrDirectContext::MakeMock(nullptr, GrContextOptions()); - MockExternalViewEmbedder view_embedder; - auto CreateSurfaceCallback = [&view_embedder, gr_context]() { - return std::make_unique( - "PlatformViewTest", &view_embedder, gr_context.get()); - }; - - auto platform_view = flutter_runner::PlatformView( - delegate, // delegate - "test_platform_view", // label - std::move(view_ref), // view_refs - std::move(task_runners), // task_runners - services_provider.service_directory(), // runner_services - nullptr, // parent_environment_service_provider_handle - nullptr, // session_listener_request - nullptr, // focuser, - nullptr, // on_session_listener_error_callback - nullptr, // on_enable_wireframe_callback, - nullptr, // on_create_view_callback, - nullptr, // on_update_view_callback, - nullptr, // on_destroy_view_callback, - CreateSurfaceCallback, // on_create_surface_callback, - fml::TimeDelta::Zero(), // vsync_offset - ZX_HANDLE_INVALID // vsync_event_handle - ); - platform_view.NotifyCreated(); - - RunLoopUntilIdle(); - - EXPECT_EQ(gr_context.get(), delegate.surface()->GetContext()); - EXPECT_EQ(&view_embedder, delegate.surface()->GetExternalViewEmbedder()); -} - -} // namespace flutter_runner_test::flutter_runner_a11y_test +} // namespace flutter_runner::testing -- GitLab