diff --git a/engine/src/flutter/flow/scene_update_context.cc b/engine/src/flutter/flow/scene_update_context.cc index b2eeae6ba8a..3edd9c4d9fe 100644 --- a/engine/src/flutter/flow/scene_update_context.cc +++ b/engine/src/flutter/flow/scene_update_context.cc @@ -201,6 +201,16 @@ void SceneUpdateContext::CreateView(int64_t view_id, view_holder->set_focusable(focusable); } +void SceneUpdateContext::UpdateView(int64_t view_id, + bool hit_testable, + bool focusable) { + auto* view_holder = ViewHolder::FromId(view_id); + FML_DCHECK(view_holder); + + view_holder->set_hit_testable(hit_testable); + view_holder->set_focusable(focusable); +} + void SceneUpdateContext::DestroyView(int64_t view_id) { ViewHolder::Destroy(view_id); } diff --git a/engine/src/flutter/flow/scene_update_context.h b/engine/src/flutter/flow/scene_update_context.h index 9ca6c7dde4c..f15c59fa7f6 100644 --- a/engine/src/flutter/flow/scene_update_context.h +++ b/engine/src/flutter/flow/scene_update_context.h @@ -167,6 +167,7 @@ class SceneUpdateContext : public flutter::ExternalViewEmbedder { } void CreateView(int64_t view_id, bool hit_testable, bool focusable); + void UpdateView(int64_t view_id, bool hit_testable, bool focusable); void DestroyView(int64_t view_id); void UpdateView(int64_t view_id, const SkPoint& offset, diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/engine.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/engine.cc index f05e4c7904c..9470f3aae8b 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/engine.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/engine.cc @@ -7,6 +7,8 @@ #include #include +#include "../runtime/dart/utils/files.h" +#include "compositor_context.h" #include "flutter/common/task_runners.h" #include "flutter/fml/make_copyable.h" #include "flutter/fml/synchronization/waitable_event.h" @@ -14,14 +16,11 @@ #include "flutter/runtime/dart_vm_lifecycle.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/run_configuration.h" -#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h" - -#include "../runtime/dart/utils/files.h" -#include "compositor_context.h" #include "flutter_runner_product_configuration.h" #include "fuchsia_intl.h" #include "platform_view.h" #include "task_runner_adapter.h" +#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h" #include "thread.h" namespace flutter_runner { @@ -146,6 +145,10 @@ Engine::Engine(Delegate& delegate, std::bind(&Engine::CreateView, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + OnUpdateView on_update_view_callback = + std::bind(&Engine::UpdateView, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3); + OnDestroyView on_destroy_view_callback = std::bind(&Engine::DestroyView, this, std::placeholders::_1); @@ -182,6 +185,7 @@ Engine::Engine(Delegate& delegate, on_enable_wireframe_callback = std::move(on_enable_wireframe_callback), on_create_view_callback = std::move(on_create_view_callback), + on_update_view_callback = std::move(on_update_view_callback), on_destroy_view_callback = std::move(on_destroy_view_callback), on_get_view_embedder_callback = std::move(on_get_view_embedder_callback), @@ -200,6 +204,7 @@ Engine::Engine(Delegate& delegate, std::move(on_session_listener_error_callback), std::move(on_enable_wireframe_callback), std::move(on_create_view_callback), + std::move(on_update_view_callback), std::move(on_destroy_view_callback), std::move(on_get_view_embedder_callback), std::move(on_get_gr_context_callback), @@ -493,6 +498,17 @@ void Engine::CreateView(int64_t view_id, bool hit_testable, bool focusable) { }); } +void Engine::UpdateView(int64_t view_id, bool hit_testable, bool focusable) { + if (!shell_ || !scene_update_context_) { + return; + } + + shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask( + [this, view_id, hit_testable, focusable]() { + scene_update_context_->UpdateView(view_id, hit_testable, focusable); + }); +} + void Engine::DestroyView(int64_t view_id) { if (!shell_ || !scene_update_context_) { return; diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/engine.h b/engine/src/flutter/shell/platform/fuchsia/flutter/engine.h index dfd0026608d..410ff63151b 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/engine.h +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/engine.h @@ -84,6 +84,7 @@ class Engine final { void DebugWireframeSettingsChanged(bool enabled); void CreateView(int64_t view_id, bool hit_testable, bool focusable); + void UpdateView(int64_t view_id, bool hit_testable, bool focusable); void DestroyView(int64_t view_id); flutter::ExternalViewEmbedder* GetViewEmbedder(); diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.cc index ac7e2635bb5..5359c1e809c 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.cc @@ -58,6 +58,7 @@ PlatformView::PlatformView( 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, OnGetViewEmbedder on_get_view_embedder_callback, OnGetGrContext on_get_gr_context_callback, @@ -72,6 +73,7 @@ PlatformView::PlatformView( std::move(session_listener_error_callback)), wireframe_enabled_callback_(std::move(wireframe_enabled_callback)), on_create_view_callback_(std::move(on_create_view_callback)), + on_update_view_callback_(std::move(on_update_view_callback)), on_destroy_view_callback_(std::move(on_destroy_view_callback)), on_get_view_embedder_callback_(std::move(on_get_view_embedder_callback)), on_get_gr_context_callback_(std::move(on_get_gr_context_callback)), @@ -762,6 +764,35 @@ void PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage( message->response()->Complete( std::make_unique((const uint8_t*)"[0]", 3u)); } + } else if (method->value == "View.update") { + auto args_it = root.FindMember("args"); + if (args_it == root.MemberEnd() || !args_it->value.IsObject()) { + FML_LOG(ERROR) << "No arguments found."; + return; + } + const auto& args = args_it->value; + + auto view_id = args.FindMember("viewId"); + if (!view_id->value.IsUint64()) { + FML_LOG(ERROR) << "Argument 'viewId' is not a int64"; + return; + } + + auto hit_testable = args.FindMember("hitTestable"); + if (!hit_testable->value.IsBool()) { + FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool"; + return; + } + + auto focusable = args.FindMember("focusable"); + if (!focusable->value.IsBool()) { + FML_LOG(ERROR) << "Argument 'focusable' is not a bool"; + return; + } + + on_update_view_callback_(view_id->value.GetUint64(), + hit_testable->value.GetBool(), + focusable->value.GetBool()); } else if (method->value == "View.dispose") { auto args_it = root.FindMember("args"); if (args_it == root.MemberEnd() || !args_it->value.IsObject()) { diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.h b/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.h index 0e45b8d7712..35275b3b84c 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.h +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view.h @@ -24,6 +24,7 @@ namespace flutter_runner { using OnEnableWireframe = fit::function; using OnCreateView = fit::function; +using OnUpdateView = fit::function; using OnDestroyView = fit::function; using OnGetViewEmbedder = fit::function; using OnGetGrContext = fit::function; @@ -52,6 +53,7 @@ class PlatformView final : public flutter::PlatformView, fit::closure on_session_listener_error_callback, OnEnableWireframe wireframe_enabled_callback, OnCreateView on_create_view_callback, + OnUpdateView on_update_view_callback, OnDestroyView on_destroy_view_callback, OnGetViewEmbedder on_get_view_embedder_callback, OnGetGrContext on_get_gr_context_callback, @@ -83,6 +85,7 @@ class PlatformView final : public flutter::PlatformView, 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_; OnGetViewEmbedder on_get_view_embedder_callback_; OnGetGrContext on_get_gr_context_callback_; diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view_unittest.cc index 731a0c55e13..6d236e8c8a3 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -168,6 +168,7 @@ TEST_F(PlatformViewTests, ChangesAccessibilitySettings) { 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_get_view_embedder_callback, nullptr, // on_get_gr_context_callback, @@ -224,6 +225,7 @@ TEST_F(PlatformViewTests, EnableWireframeTest) { nullptr, // on_session_listener_error_callback EnableWireframeCallback, // on_enable_wireframe_callback, nullptr, // on_create_view_callback, + nullptr, // on_update_view_callback, nullptr, // on_destroy_view_callback, nullptr, // on_get_view_embedder_callback, nullptr, // on_get_gr_context_callback, @@ -291,6 +293,7 @@ TEST_F(PlatformViewTests, CreateViewTest) { nullptr, // on_session_listener_error_callback nullptr, // on_enable_wireframe_callback, CreateViewCallback, // on_create_view_callback, + nullptr, // on_update_view_callback, nullptr, // on_destroy_view_callback, nullptr, // on_get_view_embedder_callback, nullptr, // on_get_gr_context_callback, @@ -326,6 +329,76 @@ 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. +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); + + // Test wireframe callback function. If the message sent to the platform + // view was properly handled and parsed, this function should be called, + // setting |wireframe_enabled| to true. + int64_t update_view_called = false; + auto UpdateViewCallback = [&update_view_called]( + int64_t view_id, bool hit_testable, + bool focusable) { update_view_called = true; }; + + 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, + UpdateViewCallback, // on_update_view_callback, + nullptr, // on_destroy_view_callback, + nullptr, // on_get_view_embedder_callback, + nullptr, // on_get_gr_context_callback, + 0u, // vsync_event_handle + {} // product_config + ); + + // Cast platform_view to its base view so we can have access to the public + // "HandlePlatformMessage" function. + auto base_view = dynamic_cast(&platform_view); + EXPECT_TRUE(base_view); + + // JSON for the message to be passed into the PlatformView. + const uint8_t txt[] = + "{" + " \"method\":\"View.update\"," + " \"args\": {" + " \"viewId\":42," + " \"hitTestable\":true," + " \"focusable\":true" + " }" + "}"; + + fml::RefPtr message = + fml::MakeRefCounted( + "flutter/platform_views", + std::vector(txt, txt + sizeof(txt)), + fml::RefPtr()); + base_view->HandlePlatformMessage(message); + + RunLoopUntilIdle(); + + 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. @@ -360,6 +433,7 @@ TEST_F(PlatformViewTests, DestroyViewTest) { nullptr, // on_session_listener_error_callback nullptr, // on_enable_wireframe_callback, nullptr, // on_create_view_callback, + nullptr, // on_update_view_callback, DestroyViewCallback, // on_destroy_view_callback, nullptr, // on_get_view_embedder_callback, nullptr, // on_get_gr_context_callback, @@ -423,6 +497,7 @@ TEST_F(PlatformViewTests, RequestFocusTest) { 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_get_gr_context_callback, nullptr, // on_get_view_embedder_callback, @@ -493,6 +568,7 @@ TEST_F(PlatformViewTests, GetViewEmbedderTest) { 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, GetViewEmbedderCallback, // on_get_view_embedder_callback, nullptr, // on_get_gr_context_callback, @@ -547,6 +623,7 @@ TEST_F(PlatformViewTests, GetGrContextTest) { 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_get_view_embedder_callback, GetGrContextCallback, // on_get_gr_context_callback,