diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index ae9dd84af7..6269a3c2e3 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -41611,6 +41611,8 @@ ORIGIN: ../../../flutter/shell/platform/android/context/android_context.cc + ../ ORIGIN: ../../../flutter/shell/platform/android/context/android_context.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/android/flutter_main.cc + ../../../flutter/LICENSE @@ -44563,6 +44565,8 @@ FILE: ../../../flutter/shell/platform/android/context/android_context.cc FILE: ../../../flutter/shell/platform/android/context/android_context.h FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder.h +FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc +FILE: ../../../flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.h FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool.cc FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool.h FILE: ../../../flutter/shell/platform/android/flutter_main.cc diff --git a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc index 114861aace..0685018e3a 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/engine/src/flutter/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -115,11 +115,12 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( } SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.width, cull_rect.height); - return impeller::RenderToTarget(aiks_context->GetContentContext(), // - render_target, // - display_list, // - sk_cull_rect, // - /*reset_host_buffer=*/true // + return impeller::RenderToTarget( + aiks_context->GetContentContext(), // + render_target, // + display_list, // + sk_cull_rect, // + /*reset_host_buffer=*/surface_frame.submit_info().frame_boundary // ); }; diff --git a/engine/src/flutter/shell/platform/android/android_shell_holder_unittests.cc b/engine/src/flutter/shell/platform/android/android_shell_holder_unittests.cc index 88fb462305..d5bf555f81 100644 --- a/engine/src/flutter/shell/platform/android/android_shell_holder_unittests.cc +++ b/engine/src/flutter/shell/platform/android/android_shell_holder_unittests.cc @@ -91,6 +91,25 @@ class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI { (), (override)); MOCK_METHOD(void, FlutterViewDestroyOverlaySurfaces, (), (override)); + MOCK_METHOD(ASurfaceTransaction*, createTransaction, (), (override)); + MOCK_METHOD(void, swapTransaction, (), (override)); + MOCK_METHOD(void, applyTransaction, (), (override)); + MOCK_METHOD(void, destroyOverlaySurface2, (), (override)); + MOCK_METHOD(std::unique_ptr, + createOverlaySurface2, + (), + (override)); + MOCK_METHOD(void, + onDisplayPlatformView2, + (int32_t view_id, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + int32_t viewWidth, + int32_t viewHeight, + MutatorsStack mutators_stack), + (override)); MOCK_METHOD(std::unique_ptr>, FlutterViewComputePlatformResolvedLocale, (std::vector supported_locales_data), diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/BUILD.gn b/engine/src/flutter/shell/platform/android/external_view_embedder/BUILD.gn index 44ae1106df..0c85a4d2fd 100644 --- a/engine/src/flutter/shell/platform/android/external_view_embedder/BUILD.gn +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/BUILD.gn @@ -9,6 +9,8 @@ source_set("external_view_embedder") { sources = [ "external_view_embedder.cc", "external_view_embedder.h", + "external_view_embedder_2.cc", + "external_view_embedder_2.h", "surface_pool.cc", "surface_pool.h", ] diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc index a957df9a54..77962bcb3f 100644 --- a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -19,7 +19,8 @@ AndroidExternalViewEmbedder::AndroidExternalViewEmbedder( android_context_(android_context), jni_facade_(std::move(jni_facade)), surface_factory_(std::move(surface_factory)), - surface_pool_(std::make_unique()), + surface_pool_( + std::make_unique(/*use_new_surface_methods=*/false)), task_runners_(task_runners) {} // |ExternalViewEmbedder| diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder.h b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder.h index ab00870276..616eb36c9d 100644 --- a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -74,8 +74,10 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { const fml::RefPtr& raster_thread_merger) override; + // |ExternalViewEmbedder| bool SupportsDynamicThreadMerging() override; + // |ExternalViewEmbedder| void Teardown() override; // Gets the rect based on the device pixel ratio of a platform view displayed diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc new file mode 100644 index 0000000000..cf87cd4f72 --- /dev/null +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.cc @@ -0,0 +1,254 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.h" +#include "flow/view_slicer.h" +#include "flutter/common/constants.h" +#include "flutter/fml/synchronization/waitable_event.h" +#include "flutter/fml/trace_event.h" +#include "fml/make_copyable.h" + +namespace flutter { + +AndroidExternalViewEmbedder2::AndroidExternalViewEmbedder2( + const AndroidContext& android_context, + std::shared_ptr jni_facade, + std::shared_ptr surface_factory, + const TaskRunners& task_runners) + : ExternalViewEmbedder(), + android_context_(android_context), + jni_facade_(std::move(jni_facade)), + surface_factory_(std::move(surface_factory)), + surface_pool_( + std::make_unique(/*use_new_surface_methods=*/true)), + task_runners_(task_runners) {} + +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder2::PrerollCompositeEmbeddedView( + int64_t view_id, + std::unique_ptr params) { + TRACE_EVENT0("flutter", + "AndroidExternalViewEmbedder2::PrerollCompositeEmbeddedView"); + + SkRect view_bounds = SkRect::Make(frame_size_); + std::unique_ptr view; + view = std::make_unique(view_bounds); + slices_.insert_or_assign(view_id, std::move(view)); + + composition_order_.push_back(view_id); + // Update params only if they changed. + if (view_params_.count(view_id) == 1 && + view_params_.at(view_id) == *params.get()) { + return; + } + view_params_.insert_or_assign(view_id, EmbeddedViewParams(*params.get())); +} + +// |ExternalViewEmbedder| +DlCanvas* AndroidExternalViewEmbedder2::CompositeEmbeddedView(int64_t view_id) { + if (slices_.count(view_id) == 1) { + return slices_.at(view_id)->canvas(); + } + return nullptr; +} + +SkRect AndroidExternalViewEmbedder2::GetViewRect( + int64_t view_id, + const std::unordered_map& view_params) { + const EmbeddedViewParams& params = view_params.at(view_id); + // https://github.com/flutter/flutter/issues/59821 + return SkRect::MakeXYWH(params.finalBoundingRect().x(), // + params.finalBoundingRect().y(), // + params.finalBoundingRect().width(), // + params.finalBoundingRect().height() // + ); +} + +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder2::SubmitFlutterView( + int64_t flutter_view_id, + GrDirectContext* context, + const std::shared_ptr& aiks_context, + std::unique_ptr frame) { + TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder2::SubmitFlutterView"); + + if (!FrameHasPlatformLayers()) { + frame->Submit(); + jni_facade_->applyTransaction(); + return; + } + + std::unordered_map view_rects; + for (auto platform_id : composition_order_) { + view_rects[platform_id] = GetViewRect(platform_id, view_params_); + } + + std::unordered_map overlay_layers = + SliceViews(frame->Canvas(), // + composition_order_, // + slices_, // + view_rects // + ); + + // Create Overlay frame. + surface_pool_->TrimLayers(); + std::unique_ptr overlay_frame; + if (surface_pool_->HasLayers()) { + for (int64_t view_id : composition_order_) { + std::unordered_map::const_iterator overlay = + overlay_layers.find(view_id); + + if (overlay == overlay_layers.end()) { + continue; + } + if (overlay_frame == nullptr) { + std::shared_ptr layer = surface_pool_->GetLayer( + context, android_context_, jni_facade_, surface_factory_); + overlay_frame = layer->surface->AcquireFrame(frame_size_); + } + + DlCanvas* overlay_canvas = overlay_frame->Canvas(); + int restore_count = overlay_canvas->GetSaveCount(); + overlay_canvas->Save(); + overlay_canvas->ClipRect(overlay->second); + overlay_canvas->Clear(DlColor::kTransparent()); + slices_[view_id]->render_into(overlay_canvas); + overlay_canvas->RestoreToCount(restore_count); + } + } + if (overlay_frame != nullptr) { + overlay_frame->set_submit_info({.frame_boundary = false}); + overlay_frame->Submit(); + } + frame->Submit(); + + task_runners_.GetPlatformTaskRunner()->PostTask(fml::MakeCopyable( + [&, composition_order = composition_order_, view_params = view_params_, + jni_facade = jni_facade_, device_pixel_ratio = device_pixel_ratio_, + slices = std::move(slices_)]() -> void { + jni_facade->swapTransaction(); + for (int64_t view_id : composition_order) { + SkRect view_rect = GetViewRect(view_id, view_params); + const EmbeddedViewParams& params = view_params.at(view_id); + // Display the platform view. If it's already displayed, then it's + // just positioned and sized. + jni_facade->FlutterViewOnDisplayPlatformView( + view_id, // + view_rect.x(), // + view_rect.y(), // + view_rect.width(), // + view_rect.height(), // + params.sizePoints().width() * device_pixel_ratio, + params.sizePoints().height() * device_pixel_ratio, + params.mutatorsStack() // + ); + } + if (!surface_pool_->HasLayers()) { + surface_pool_->GetLayer(context, android_context_, jni_facade_, + surface_factory_); + } + jni_facade->FlutterViewEndFrame(); + })); +} + +// |ExternalViewEmbedder| +std::unique_ptr +AndroidExternalViewEmbedder2::CreateSurfaceIfNeeded(GrDirectContext* context, + int64_t view_id, + EmbedderViewSlice* slice, + const SkRect& rect) { + std::shared_ptr layer = surface_pool_->GetLayer( + context, android_context_, jni_facade_, surface_factory_); + + std::unique_ptr frame = + layer->surface->AcquireFrame(frame_size_); + + DlCanvas* overlay_canvas = frame->Canvas(); + overlay_canvas->Clear(DlColor::kTransparent()); + // Offset the picture since its absolute position on the scene is determined + // by the position of the overlay view. + slice->render_into(overlay_canvas); + return frame; +} + +// |ExternalViewEmbedder| +PostPrerollResult AndroidExternalViewEmbedder2::PostPrerollAction( + const fml::RefPtr& raster_thread_merger) { + return PostPrerollResult::kSuccess; +} + +bool AndroidExternalViewEmbedder2::FrameHasPlatformLayers() { + return !composition_order_.empty(); +} + +// |ExternalViewEmbedder| +DlCanvas* AndroidExternalViewEmbedder2::GetRootCanvas() { + // On Android, the root surface is created from the on-screen render target. + return nullptr; +} + +void AndroidExternalViewEmbedder2::Reset() { + previous_frame_view_count_ = composition_order_.size(); + + composition_order_.clear(); + slices_.clear(); +} + +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder2::BeginFrame( + GrDirectContext* context, + const fml::RefPtr& raster_thread_merger) {} + +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder2::PrepareFlutterView( + SkISize frame_size, + double device_pixel_ratio) { + Reset(); + + // The surface size changed. Therefore, destroy existing surfaces as + // the existing surfaces in the pool can't be recycled. + if (frame_size_ != frame_size) { + DestroySurfaces(); + } + surface_pool_->SetFrameSize(frame_size); + + frame_size_ = frame_size; + device_pixel_ratio_ = device_pixel_ratio; +} + +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder2::CancelFrame() { + Reset(); +} + +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder2::EndFrame( + bool should_resubmit_frame, + const fml::RefPtr& raster_thread_merger) {} + +// |ExternalViewEmbedder| +bool AndroidExternalViewEmbedder2::SupportsDynamicThreadMerging() { + return false; +} + +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder2::Teardown() { + DestroySurfaces(); +} + +// |ExternalViewEmbedder| +void AndroidExternalViewEmbedder2::DestroySurfaces() { + if (!surface_pool_->HasLayers()) { + return; + } + fml::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask(task_runners_.GetPlatformTaskRunner(), + [&]() { + surface_pool_->DestroyLayers(jni_facade_); + latch.Signal(); + }); + latch.Wait(); +} + +} // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.h b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.h new file mode 100644 index 0000000000..2d8e91ef39 --- /dev/null +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.h @@ -0,0 +1,159 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_EXTERNAL_VIEW_EMBEDDER_2_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_EXTERNAL_VIEW_EMBEDDER_2_H_ + +#include + +#include "flutter/common/task_runners.h" +#include "flutter/flow/embedded_views.h" +#include "flutter/shell/platform/android/context/android_context.h" +#include "flutter/shell/platform/android/external_view_embedder/surface_pool.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" +#include "flutter/shell/platform/android/surface/android_surface.h" + +namespace flutter { + +//------------------------------------------------------------------------------ +/// Allows to embed Android views into a Flutter application. +/// +/// This class calls Java methods via |PlatformViewAndroidJNI| to manage the +/// lifecycle of the Android view corresponding to |flutter::PlatformViewLayer|. +/// +/// It also orchestrates overlay surfaces. These are Android views +/// that render above (by Z order) the Android view corresponding to +/// |flutter::PlatformViewLayer|. +/// +/// This implementation of the external view embedder is designed only to use +/// HC++ mode. Mixing old HC modes is not supported, but either of the texture +/// composition based platform views can be used with either mode. +class AndroidExternalViewEmbedder2 final : public ExternalViewEmbedder { + public: + AndroidExternalViewEmbedder2( + const AndroidContext& android_context, + std::shared_ptr jni_facade, + std::shared_ptr surface_factory, + const TaskRunners& task_runners); + + // |ExternalViewEmbedder| + void PrerollCompositeEmbeddedView( + int64_t view_id, + std::unique_ptr params) override; + + // |ExternalViewEmbedder| + DlCanvas* CompositeEmbeddedView(int64_t view_id) override; + + // |ExternalViewEmbedder| + void SubmitFlutterView( + int64_t flutter_view_id, + GrDirectContext* context, + const std::shared_ptr& aiks_context, + std::unique_ptr frame) override; + + // |ExternalViewEmbedder| + PostPrerollResult PostPrerollAction( + const fml::RefPtr& raster_thread_merger) + override; + + // |ExternalViewEmbedder| + DlCanvas* GetRootCanvas() override; + + // |ExternalViewEmbedder| + void BeginFrame(GrDirectContext* context, + const fml::RefPtr& + raster_thread_merger) override; + + // |ExternalViewEmbedder| + void PrepareFlutterView(SkISize frame_size, + double device_pixel_ratio) override; + + // |ExternalViewEmbedder| + void CancelFrame() override; + + // |ExternalViewEmbedder| + void EndFrame(bool should_resubmit_frame, + const fml::RefPtr& + raster_thread_merger) override; + + // |ExternalViewEmbedder| + bool SupportsDynamicThreadMerging() override; + + // |ExternalViewEmbedder| + void Teardown() override; + + // Gets the rect based on the device pixel ratio of a platform view displayed + // on the screen. + static SkRect GetViewRect( + int64_t view_id, + const std::unordered_map& view_params); + + private: + // The number of frames the rasterizer task runner will continue + // to run on the platform thread after no platform view is rendered. + // + // Note: this is an arbitrary number that attempts to account for cases + // where the platform view might be momentarily off the screen. + static const int kDefaultMergedLeaseDuration = 10; + + // Provides metadata to the Android surfaces. + const AndroidContext& android_context_; + + // Allows to call methods in Java. + const std::shared_ptr jni_facade_; + + // Allows to create surfaces. + const std::shared_ptr surface_factory_; + + // Holds surfaces. Allows to recycle surfaces or allocate new ones. + const std::unique_ptr surface_pool_; + + // The task runners. + const TaskRunners task_runners_; + + // The size of the root canvas. + SkISize frame_size_; + + // The pixel ratio used to determinate the size of a platform view layer + // relative to the device layout system. + double device_pixel_ratio_; + + // The order of composition. Each entry contains a unique id for the platform + // view. + std::vector composition_order_; + + // The |EmbedderViewSlice| implementation keyed off the platform view id, + // which contains any subsequent operations until the next platform view or + // the end of the last leaf node in the layer tree. + std::unordered_map> slices_; + + // The params for a platform view, which contains the size, position and + // mutation stack. + std::unordered_map view_params_; + + // The number of platform views in the previous frame. + int64_t previous_frame_view_count_; + + // Destroys the surfaces created from the surface factory. + // This method schedules a task on the platform thread, and waits for + // the task until it completes. + void DestroySurfaces(); + + // Resets the state. + void Reset(); + + // Whether the layer tree in the current frame has platform layers. + bool FrameHasPlatformLayers(); + + // Creates a Surface when needed or recycles an existing one. + // Finally, draws the picture on the frame's canvas. + std::unique_ptr CreateSurfaceIfNeeded(GrDirectContext* context, + int64_t view_id, + EmbedderViewSlice* slice, + const SkRect& rect); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_EXTERNAL_VIEW_EMBEDDER_EXTERNAL_VIEW_EMBEDDER_2_H_ diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool.cc b/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool.cc index 7290a5816b..ed979c8035 100644 --- a/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool.cc +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool.cc @@ -17,7 +17,8 @@ OverlayLayer::OverlayLayer(int id, OverlayLayer::~OverlayLayer() = default; -SurfacePool::SurfacePool() = default; +SurfacePool::SurfacePool(bool use_new_surface_methods) + : use_new_surface_methods_(use_new_surface_methods) {} SurfacePool::~SurfacePool() = default; @@ -42,7 +43,9 @@ std::shared_ptr SurfacePool::GetLayer( "rendering."; std::unique_ptr java_metadata = - jni_facade->FlutterViewCreateOverlaySurface(); + use_new_surface_methods_ + ? jni_facade->createOverlaySurface2() + : jni_facade->FlutterViewCreateOverlaySurface(); FML_CHECK(java_metadata->window); android_surface->SetNativeWindow(java_metadata->window, jni_facade); @@ -96,7 +99,11 @@ void SurfacePool::DestroyLayersLocked( if (layers_.empty()) { return; } - jni_facade->FlutterViewDestroyOverlaySurfaces(); + if (use_new_surface_methods_) { + jni_facade->destroyOverlaySurface2(); + } else { + jni_facade->FlutterViewDestroyOverlaySurfaces(); + } layers_.clear(); available_layer_index_ = 0; } @@ -115,4 +122,9 @@ void SurfacePool::SetFrameSize(SkISize frame_size) { requested_frame_size_ = frame_size; } +void SurfacePool::TrimLayers() { + std::lock_guard lock(mutex_); + layers_.erase(layers_.begin() + available_layer_index_, layers_.end()); + available_layer_index_ = 0; +} } // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool.h b/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool.h index 5f09d6db91..45719bc138 100644 --- a/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool.h +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool.h @@ -45,7 +45,7 @@ struct OverlayLayer { class SurfacePool { public: - SurfacePool(); + explicit SurfacePool(bool use_new_surface_methods); ~SurfacePool(); @@ -76,6 +76,8 @@ class SurfacePool { // Returns true if the current pool has layers in use. bool HasLayers(); + void TrimLayers(); + private: // The index of the entry in the layers_ vector that determines the beginning // of the unused layers. For example, consider the following vector: @@ -102,6 +104,7 @@ class SurfacePool { // Used to guard public methods. std::mutex mutex_; + bool use_new_surface_methods_ = false; void DestroyLayersLocked( const std::shared_ptr& jni_facade); diff --git a/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool_unittests.cc b/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool_unittests.cc index 09cf54bcfc..98df5f0cb9 100644 --- a/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool_unittests.cc +++ b/engine/src/flutter/shell/platform/android/external_view_embedder/surface_pool_unittests.cc @@ -38,7 +38,7 @@ class TestAndroidSurfaceFactory : public AndroidSurfaceFactory { }; TEST(SurfacePool, GetLayerAllocateOneLayer) { - auto pool = std::make_unique(); + auto pool = std::make_unique(/*use_new_surface_methods=*/false); auto gr_context = GrDirectContext::MakeMock(nullptr); auto android_context = @@ -69,7 +69,7 @@ TEST(SurfacePool, GetLayerAllocateOneLayer) { } TEST(SurfacePool, GetUnusedLayers) { - auto pool = std::make_unique(); + auto pool = std::make_unique(/*use_new_surface_methods=*/false); auto gr_context = GrDirectContext::MakeMock(nullptr); auto android_context = @@ -102,7 +102,7 @@ TEST(SurfacePool, GetUnusedLayers) { } TEST(SurfacePool, GetLayerRecycle) { - auto pool = std::make_unique(); + auto pool = std::make_unique(/*use_new_surface_methods=*/false); auto gr_context_1 = GrDirectContext::MakeMock(nullptr); auto jni_mock = std::make_shared(); @@ -147,7 +147,7 @@ TEST(SurfacePool, GetLayerRecycle) { } TEST(SurfacePool, GetLayerAllocateTwoLayers) { - auto pool = std::make_unique(); + auto pool = std::make_unique(/*use_new_surface_methods=*/false); auto gr_context = GrDirectContext::MakeMock(nullptr); auto android_context = @@ -185,8 +185,45 @@ TEST(SurfacePool, GetLayerAllocateTwoLayers) { ASSERT_EQ(1, layer_2->id); } +TEST(SurfacePool, DestroyLayersNew) { + auto pool = std::make_unique(/*use_new_surface_methods=*/true); + auto jni_mock = std::make_shared(); + + EXPECT_CALL(*jni_mock, destroyOverlaySurface2()).Times(0); + pool->DestroyLayers(jni_mock); + + auto gr_context = GrDirectContext::MakeMock(nullptr); + auto android_context = + std::make_shared(AndroidRenderingAPI::kSoftware); + + auto window = fml::MakeRefCounted(nullptr); + EXPECT_CALL(*jni_mock, createOverlaySurface2()) + .Times(1) + .WillOnce(Return( + ByMove(std::make_unique( + 0, window)))); + + auto surface_factory = + std::make_shared([gr_context, window]() { + auto android_surface_mock = std::make_unique(); + EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get())); + EXPECT_CALL(*android_surface_mock, SetNativeWindow(window, _)); + EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true)); + return android_surface_mock; + }); + pool->GetLayer(gr_context.get(), *android_context, jni_mock, surface_factory); + + EXPECT_CALL(*jni_mock, destroyOverlaySurface2()); + + ASSERT_TRUE(pool->HasLayers()); + pool->DestroyLayers(jni_mock); + + ASSERT_FALSE(pool->HasLayers()); + ASSERT_TRUE(pool->GetUnusedLayers().empty()); +} + TEST(SurfacePool, DestroyLayers) { - auto pool = std::make_unique(); + auto pool = std::make_unique(/*use_new_surface_methods=*/false); auto jni_mock = std::make_shared(); EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0); @@ -223,7 +260,7 @@ TEST(SurfacePool, DestroyLayers) { } TEST(SurfacePool, DestroyLayersFrameSizeChanged) { - auto pool = std::make_unique(); + auto pool = std::make_unique(/*use_new_surface_methods=*/false); auto jni_mock = std::make_shared(); auto gr_context = GrDirectContext::MakeMock(nullptr); @@ -267,5 +304,50 @@ TEST(SurfacePool, DestroyLayersFrameSizeChanged) { ASSERT_TRUE(pool->HasLayers()); } +TEST(SurfacePool, DestroyLayersFrameSizeChangedNew) { + auto pool = std::make_unique(/*use_new_surface_methods=*/true); + auto jni_mock = std::make_shared(); + + auto gr_context = GrDirectContext::MakeMock(nullptr); + auto android_context = + std::make_shared(AndroidRenderingAPI::kSoftware); + + auto window = fml::MakeRefCounted(nullptr); + + auto surface_factory = + std::make_shared([gr_context, window]() { + auto android_surface_mock = std::make_unique(); + EXPECT_CALL(*android_surface_mock, CreateGPUSurface(gr_context.get())); + EXPECT_CALL(*android_surface_mock, SetNativeWindow(window, _)); + EXPECT_CALL(*android_surface_mock, IsValid()).WillOnce(Return(true)); + return android_surface_mock; + }); + pool->SetFrameSize(SkISize::Make(10, 10)); + EXPECT_CALL(*jni_mock, destroyOverlaySurface2()).Times(0); + EXPECT_CALL(*jni_mock, createOverlaySurface2()) + .Times(1) + .WillOnce(Return( + ByMove(std::make_unique( + 0, window)))); + + ASSERT_FALSE(pool->HasLayers()); + + pool->GetLayer(gr_context.get(), *android_context, jni_mock, surface_factory); + + ASSERT_TRUE(pool->HasLayers()); + + pool->SetFrameSize(SkISize::Make(20, 20)); + EXPECT_CALL(*jni_mock, destroyOverlaySurface2()).Times(1); + EXPECT_CALL(*jni_mock, createOverlaySurface2()) + .Times(1) + .WillOnce(Return( + ByMove(std::make_unique( + 1, window)))); + pool->GetLayer(gr_context.get(), *android_context, jni_mock, surface_factory); + + ASSERT_TRUE(pool->GetUnusedLayers().empty()); + ASSERT_TRUE(pool->HasLayers()); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java index fdfd13a3e6..a4e123c977 100644 --- a/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java +++ b/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java @@ -321,7 +321,6 @@ public class FlutterJNI { asyncWaitForVsyncDelegate = delegate; } - // TODO(mattcarroll): add javadocs // Called by native. private static void asyncWaitForVsync(final long cookie) { if (asyncWaitForVsyncDelegate != null) { @@ -596,7 +595,6 @@ public class FlutterJNI { } } - // TODO(mattcarroll): get native to call this when rendering stops. @VisibleForTesting @UiThread void onRenderingStopped() { @@ -810,8 +808,6 @@ public class FlutterJNI { if (accessibilityDelegate != null) { accessibilityDelegate.updateSemantics(buffer, strings, stringAttributeArgs); } - // TODO(mattcarroll): log dropped messages when in debug mode - // (https://github.com/flutter/flutter/issues/25391) } /** @@ -831,8 +827,6 @@ public class FlutterJNI { if (accessibilityDelegate != null) { accessibilityDelegate.updateCustomAccessibilityActions(buffer, strings); } - // TODO(mattcarroll): log dropped messages when in debug mode - // (https://github.com/flutter/flutter/issues/25391) } /** Sends a semantics action to Flutter's engine, without any additional arguments. */ @@ -896,8 +890,6 @@ public class FlutterJNI { private native void nativeSetSemanticsEnabled(long nativeShellHolderId, boolean enabled); - // TODO(mattcarroll): figure out what flags are supported and add javadoc about when/why/where to - // use this. @UiThread public void setAccessibilityFeatures(int flags) { ensureRunningOnMainThread(); @@ -1073,7 +1065,6 @@ public class FlutterJNI { } // Called by native on any thread. - // TODO(mattcarroll): determine if message is nonull or nullable @SuppressWarnings("unused") @VisibleForTesting public void handlePlatformMessage( @@ -1086,19 +1077,14 @@ public class FlutterJNI { } else { nativeCleanupMessageData(messageData); } - // TODO(mattcarroll): log dropped messages when in debug mode - // (https://github.com/flutter/flutter/issues/25391) } // Called by native to respond to a platform message that we sent. - // TODO(mattcarroll): determine if reply is nonull or nullable @SuppressWarnings("unused") private void handlePlatformMessageResponse(int replyId, ByteBuffer reply) { if (platformMessageHandler != null) { platformMessageHandler.handlePlatformMessageResponse(replyId, reply); } - // TODO(mattcarroll): log dropped messages when in debug mode - // (https://github.com/flutter/flutter/issues/25391) } /** @@ -1149,7 +1135,6 @@ public class FlutterJNI { int position, int responseId); - // TODO(mattcarroll): differentiate between channel responses and platform responses. public void invokePlatformMessageEmptyResponseCallback(int responseId) { // Called on any thread. shellHolderLock.readLock().lock(); @@ -1171,7 +1156,6 @@ public class FlutterJNI { private native void nativeInvokePlatformMessageEmptyResponseCallback( long nativeShellHolderId, int responseId); - // TODO(mattcarroll): differentiate between channel responses and platform responses. public void invokePlatformMessageResponseCallback( int responseId, @NonNull ByteBuffer message, int position) { // Called on any thread. @@ -1557,7 +1541,6 @@ public class FlutterJNI { viewId, x, y, width, height, viewWidth, viewHeight, mutatorsStack); } - // TODO(mattcarroll): determine if this is nonull or nullable @UiThread public Bitmap getBitmap() { ensureRunningOnMainThread(); @@ -1565,7 +1548,6 @@ public class FlutterJNI { return nativeGetBitmap(nativeShellHolderId); } - // TODO(mattcarroll): determine if this is nonull or nullable private native Bitmap nativeGetBitmap(long nativeShellHolderId); /** diff --git a/engine/src/flutter/shell/platform/android/jni/jni_mock.h b/engine/src/flutter/shell/platform/android/jni/jni_mock.h index cf5b329256..1dedcf8f85 100644 --- a/engine/src/flutter/shell/platform/android/jni/jni_mock.h +++ b/engine/src/flutter/shell/platform/android/jni/jni_mock.h @@ -114,6 +114,31 @@ class JNIMock final : public PlatformViewAndroidJNI { MOCK_METHOD(void, FlutterViewDestroyOverlaySurfaces, (), (override)); + MOCK_METHOD(ASurfaceTransaction*, createTransaction, (), (override)); + + MOCK_METHOD(void, swapTransaction, (), (override)); + + MOCK_METHOD(void, applyTransaction, (), (override)); + + MOCK_METHOD(void, destroyOverlaySurface2, (), (override)); + + MOCK_METHOD(std::unique_ptr, + createOverlaySurface2, + (), + (override)); + + MOCK_METHOD(void, + onDisplayPlatformView2, + (int32_t view_id, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + int32_t viewWidth, + int32_t viewHeight, + MutatorsStack mutators_stack), + (override)); + MOCK_METHOD(std::unique_ptr>, FlutterViewComputePlatformResolvedLocale, (std::vector supported_locales_data), diff --git a/engine/src/flutter/shell/platform/android/jni/platform_view_android_jni.h b/engine/src/flutter/shell/platform/android/jni/platform_view_android_jni.h index 356b6776fc..68e3b4205c 100644 --- a/engine/src/flutter/shell/platform/android/jni/platform_view_android_jni.h +++ b/engine/src/flutter/shell/platform/android/jni/platform_view_android_jni.h @@ -19,6 +19,8 @@ #include "flutter/fml/platform/android/scoped_java_ref.h" #endif +struct ASurfaceTransaction; + namespace flutter { #if FML_OS_ANDROID @@ -214,6 +216,27 @@ class PlatformViewAndroidJNI { /// virtual void FlutterViewDestroyOverlaySurfaces() = 0; + // New Platform View Support. + virtual ASurfaceTransaction* createTransaction() = 0; + + virtual void swapTransaction() = 0; + + virtual void applyTransaction() = 0; + + virtual std::unique_ptr + createOverlaySurface2() = 0; + + virtual void destroyOverlaySurface2() = 0; + + virtual void onDisplayPlatformView2(int32_t view_id, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + int32_t viewWidth, + int32_t viewHeight, + MutatorsStack mutators_stack) = 0; + //---------------------------------------------------------------------------- /// @brief Computes the locale Android would select. /// diff --git a/engine/src/flutter/shell/platform/android/platform_view_android.cc b/engine/src/flutter/shell/platform/android/platform_view_android.cc index 694b3ebc13..db8de490bf 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android.cc +++ b/engine/src/flutter/shell/platform/android/platform_view_android.cc @@ -30,6 +30,7 @@ #endif #include "flutter/shell/platform/android/context/android_context.h" #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h" +#include "flutter/shell/platform/android/external_view_embedder/external_view_embedder_2.h" #include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "flutter/shell/platform/android/platform_message_response_android.h" #include "flutter/shell/platform/android/surface/android_surface.h" @@ -366,6 +367,10 @@ std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { // |PlatformView| std::shared_ptr PlatformViewAndroid::CreateExternalViewEmbedder() { + if (android_use_new_platform_view_) { + return std::make_shared( + *android_context_, jni_facade_, surface_factory_, task_runners_); + } return std::make_shared( *android_context_, jni_facade_, surface_factory_, task_runners_); } diff --git a/engine/src/flutter/shell/platform/android/platform_view_android.h b/engine/src/flutter/shell/platform/android/platform_view_android.h index 5310826c52..5d0b630a38 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android.h +++ b/engine/src/flutter/shell/platform/android/platform_view_android.h @@ -128,6 +128,7 @@ class PlatformViewAndroid final : public PlatformView { std::unique_ptr android_surface_; std::shared_ptr platform_message_handler_; + bool android_use_new_platform_view_ = false; // |PlatformView| void UpdateSemantics( diff --git a/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc b/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc index 8977d21ffb..18c34ae86f 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc +++ b/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.cc @@ -33,6 +33,7 @@ #include "flutter/shell/platform/android/image_external_texture_gl.h" #include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "flutter/shell/platform/android/platform_view_android.h" +#include "impeller/toolkit/android/proc_table.h" #define ANDROID_SHELL_HOLDER \ (reinterpret_cast(shell_holder)) @@ -132,8 +133,6 @@ static jmethodID g_request_dart_deferred_library_method = nullptr; // Called By Java static jmethodID g_on_display_platform_view_method = nullptr; -// static jmethodID g_on_composite_platform_view_method = nullptr; - static jmethodID g_on_display_overlay_surface_method = nullptr; static jmethodID g_overlay_surface_id_method = nullptr; @@ -146,6 +145,19 @@ static jmethodID g_bitmap_copy_pixels_from_buffer_method = nullptr; static jmethodID g_bitmap_config_value_of = nullptr; +// New platform Views +static jmethodID g_create_transaction_method = nullptr; + +static jmethodID g_swap_transaction_method = nullptr; + +static jmethodID g_apply_transaction_method = nullptr; + +static jmethodID g_create_overlay_surface2_method = nullptr; + +static jmethodID g_destroy_overlay_surface2_method = nullptr; + +static jmethodID g_on_display_platform_view2_method = nullptr; + // Mutators static fml::jni::ScopedJavaGlobalRef* g_mutators_stack_class = nullptr; static jmethodID g_mutators_stack_init_method = nullptr; @@ -968,6 +980,60 @@ bool RegisterApi(JNIEnv* env) { return false; } + // new platform views + g_create_transaction_method = + env->GetMethodID(g_flutter_jni_class->obj(), "createTransaction", + "()Landroid/view/SurfaceControl$Transaction;"); + + if (g_create_transaction_method == nullptr) { + FML_LOG(ERROR) << "Could not locate createTransaction method"; + return false; + } + + g_swap_transaction_method = + env->GetMethodID(g_flutter_jni_class->obj(), "swapTransactions", "()V"); + + if (g_swap_transaction_method == nullptr) { + FML_LOG(ERROR) << "Could not locate swapTransactions method"; + return false; + } + + g_apply_transaction_method = + env->GetMethodID(g_flutter_jni_class->obj(), "applyTransactions", "()V"); + + if (g_apply_transaction_method == nullptr) { + FML_LOG(ERROR) << "Could not locate applyTransactions method"; + return false; + } + + g_create_overlay_surface2_method = + env->GetMethodID(g_flutter_jni_class->obj(), "createOverlaySurface2", + "()Lio/flutter/embedding/engine/FlutterOverlaySurface;"); + + if (g_create_overlay_surface2_method == nullptr) { + FML_LOG(ERROR) << "Could not locate createOverlaySurface2 method"; + return false; + } + + g_destroy_overlay_surface2_method = env->GetMethodID( + g_flutter_jni_class->obj(), "destroyOverlaySurface2", "()V"); + + if (g_destroy_overlay_surface2_method == nullptr) { + FML_LOG(ERROR) << "Could not locate destroyOverlaySurface2 method"; + return false; + } + + g_on_display_platform_view2_method = + env->GetMethodID(g_flutter_jni_class->obj(), "onDisplayPlatformView2", + "(IIIIIIILio/flutter/embedding/engine/mutatorsstack/" + "FlutterMutatorsStack;)V"); + + if (g_on_display_platform_view2_method == nullptr) { + FML_LOG(ERROR) << "Could not locate onDisplayPlatformView2 method"; + return false; + } + // + fml::jni::ScopedJavaLocalRef overlay_surface_class( env, env->FindClass("io/flutter/embedding/engine/FlutterOverlaySurface")); if (overlay_surface_class.is_null()) { @@ -1913,4 +1979,176 @@ bool PlatformViewAndroidJNIImpl::RequestDartDeferredLibrary( return true; } +// New Platform View Support. + +ASurfaceTransaction* PlatformViewAndroidJNIImpl::createTransaction() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + + fml::jni::ScopedJavaLocalRef transaction( + env, + env->CallObjectMethod(java_object.obj(), g_create_transaction_method)); + + if (transaction.is_null()) { + return nullptr; + } + + FML_CHECK(fml::jni::CheckException(env)); + return impeller::android::GetProcTable().ASurfaceTransaction_fromJava( + env, transaction.obj()); +} + +void PlatformViewAndroidJNIImpl::swapTransaction() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + env->CallVoidMethod(java_object.obj(), g_swap_transaction_method); + + FML_CHECK(fml::jni::CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::applyTransaction() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + env->CallVoidMethod(java_object.obj(), g_apply_transaction_method); + + FML_CHECK(fml::jni::CheckException(env)); +} + +std::unique_ptr +PlatformViewAndroidJNIImpl::createOverlaySurface2() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return nullptr; + } + + fml::jni::ScopedJavaLocalRef overlay( + env, env->CallObjectMethod(java_object.obj(), + g_create_overlay_surface2_method)); + FML_CHECK(fml::jni::CheckException(env)); + + if (overlay.is_null()) { + return std::make_unique(0, + nullptr); + } + + jint overlay_id = + env->CallIntMethod(overlay.obj(), g_overlay_surface_id_method); + + jobject overlay_surface = + env->CallObjectMethod(overlay.obj(), g_overlay_surface_surface_method); + + auto overlay_window = fml::MakeRefCounted( + ANativeWindow_fromSurface(env, overlay_surface)); + + return std::make_unique( + overlay_id, std::move(overlay_window)); +} + +void PlatformViewAndroidJNIImpl::destroyOverlaySurface2() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + env->CallVoidMethod(java_object.obj(), g_destroy_overlay_surface2_method); + + FML_CHECK(fml::jni::CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::onDisplayPlatformView2( + int32_t view_id, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + int32_t viewWidth, + int32_t viewHeight, + MutatorsStack mutators_stack) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + jobject mutatorsStack = env->NewObject(g_mutators_stack_class->obj(), + g_mutators_stack_init_method); + + std::vector>::const_iterator iter = + mutators_stack.Begin(); + while (iter != mutators_stack.End()) { + switch ((*iter)->GetType()) { + case kTransform: { + const SkMatrix& matrix = (*iter)->GetMatrix(); + SkScalar matrix_array[9]; + matrix.get9(matrix_array); + fml::jni::ScopedJavaLocalRef transformMatrix( + env, env->NewFloatArray(9)); + + env->SetFloatArrayRegion(transformMatrix.obj(), 0, 9, matrix_array); + env->CallVoidMethod(mutatorsStack, + g_mutators_stack_push_transform_method, + transformMatrix.obj()); + break; + } + case kClipRect: { + const SkRect& rect = (*iter)->GetRect(); + env->CallVoidMethod( + mutatorsStack, g_mutators_stack_push_cliprect_method, + static_cast(rect.left()), static_cast(rect.top()), + static_cast(rect.right()), static_cast(rect.bottom())); + break; + } + case kClipRRect: { + const SkRRect& rrect = (*iter)->GetRRect(); + const SkRect& rect = rrect.rect(); + const SkVector& upper_left = rrect.radii(SkRRect::kUpperLeft_Corner); + const SkVector& upper_right = rrect.radii(SkRRect::kUpperRight_Corner); + const SkVector& lower_right = rrect.radii(SkRRect::kLowerRight_Corner); + const SkVector& lower_left = rrect.radii(SkRRect::kLowerLeft_Corner); + SkScalar radiis[8] = { + upper_left.x(), upper_left.y(), upper_right.x(), upper_right.y(), + lower_right.x(), lower_right.y(), lower_left.x(), lower_left.y(), + }; + fml::jni::ScopedJavaLocalRef radiisArray( + env, env->NewFloatArray(8)); + env->SetFloatArrayRegion(radiisArray.obj(), 0, 8, radiis); + env->CallVoidMethod( + mutatorsStack, g_mutators_stack_push_cliprrect_method, + static_cast(rect.left()), static_cast(rect.top()), + static_cast(rect.right()), static_cast(rect.bottom()), + radiisArray.obj()); + break; + } + // TODO(cyanglaz): Implement other mutators. + // https://github.com/flutter/flutter/issues/58426 + case kClipPath: + case kOpacity: + case kBackdropFilter: + break; + } + ++iter; + } + + env->CallVoidMethod(java_object.obj(), g_on_display_platform_view2_method, + view_id, x, y, width, height, viewWidth, viewHeight, + mutatorsStack); + + FML_CHECK(fml::jni::CheckException(env)); +} + } // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.h b/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.h index 73cb6a43cf..d05ee131f4 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.h +++ b/engine/src/flutter/shell/platform/android/platform_view_android_jni_impl.h @@ -103,6 +103,27 @@ class PlatformViewAndroidJNIImpl final : public PlatformViewAndroidJNI { double FlutterViewGetScaledFontSize(double unscaled_font_size, int configuration_id) const override; + // New Platform View Support. + ASurfaceTransaction* createTransaction() override; + + void swapTransaction() override; + + void applyTransaction() override; + + std::unique_ptr + createOverlaySurface2() override; + + void destroyOverlaySurface2() override; + + void onDisplayPlatformView2(int32_t view_id, + int32_t x, + int32_t y, + int32_t width, + int32_t height, + int32_t viewWidth, + int32_t viewHeight, + MutatorsStack mutators_stack) override; + private: // Reference to FlutterJNI object. const fml::jni::JavaObjectWeakGlobalRef java_object_;