[Android] HC++ external view embedder and JNI plumbing. (#162493)
Part of HC++ work. still not wired up end to end, but only requires a
few more swapchain changes and a runtime flag...
diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter
index ae9dd84..6269a3c 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.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.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 114861a..0685018 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 @@
}
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 88fb462..d5bf555 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 @@
(),
(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<PlatformViewAndroidJNI::OverlayMetadata>,
+ 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<std::vector<std::string>>,
FlutterViewComputePlatformResolvedLocale,
(std::vector<std::string> 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 44ae110..0c85a4d 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 @@
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 a957df9..77962bc 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 @@
android_context_(android_context),
jni_facade_(std::move(jni_facade)),
surface_factory_(std::move(surface_factory)),
- surface_pool_(std::make_unique<SurfacePool>()),
+ surface_pool_(
+ std::make_unique<SurfacePool>(/*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 ab00870..616eb36 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 @@
const fml::RefPtr<fml::RasterThreadMerger>&
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 0000000..cf87cd4
--- /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<PlatformViewAndroidJNI> jni_facade,
+ std::shared_ptr<AndroidSurfaceFactory> 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<SurfacePool>(/*use_new_surface_methods=*/true)),
+ task_runners_(task_runners) {}
+
+// |ExternalViewEmbedder|
+void AndroidExternalViewEmbedder2::PrerollCompositeEmbeddedView(
+ int64_t view_id,
+ std::unique_ptr<EmbeddedViewParams> params) {
+ TRACE_EVENT0("flutter",
+ "AndroidExternalViewEmbedder2::PrerollCompositeEmbeddedView");
+
+ SkRect view_bounds = SkRect::Make(frame_size_);
+ std::unique_ptr<EmbedderViewSlice> view;
+ view = std::make_unique<DisplayListEmbedderViewSlice>(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<int64_t, EmbeddedViewParams>& 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<impeller::AiksContext>& aiks_context,
+ std::unique_ptr<SurfaceFrame> frame) {
+ TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder2::SubmitFlutterView");
+
+ if (!FrameHasPlatformLayers()) {
+ frame->Submit();
+ jni_facade_->applyTransaction();
+ return;
+ }
+
+ std::unordered_map<int64_t, SkRect> view_rects;
+ for (auto platform_id : composition_order_) {
+ view_rects[platform_id] = GetViewRect(platform_id, view_params_);
+ }
+
+ std::unordered_map<int64_t, SkRect> overlay_layers =
+ SliceViews(frame->Canvas(), //
+ composition_order_, //
+ slices_, //
+ view_rects //
+ );
+
+ // Create Overlay frame.
+ surface_pool_->TrimLayers();
+ std::unique_ptr<SurfaceFrame> overlay_frame;
+ if (surface_pool_->HasLayers()) {
+ for (int64_t view_id : composition_order_) {
+ std::unordered_map<int64_t, SkRect>::const_iterator overlay =
+ overlay_layers.find(view_id);
+
+ if (overlay == overlay_layers.end()) {
+ continue;
+ }
+ if (overlay_frame == nullptr) {
+ std::shared_ptr<OverlayLayer> 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<SurfaceFrame>
+AndroidExternalViewEmbedder2::CreateSurfaceIfNeeded(GrDirectContext* context,
+ int64_t view_id,
+ EmbedderViewSlice* slice,
+ const SkRect& rect) {
+ std::shared_ptr<OverlayLayer> layer = surface_pool_->GetLayer(
+ context, android_context_, jni_facade_, surface_factory_);
+
+ std::unique_ptr<SurfaceFrame> 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<fml::RasterThreadMerger>& 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<fml::RasterThreadMerger>& 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<fml::RasterThreadMerger>& 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 0000000..2d8e91e
--- /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 <unordered_map>
+
+#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<PlatformViewAndroidJNI> jni_facade,
+ std::shared_ptr<AndroidSurfaceFactory> surface_factory,
+ const TaskRunners& task_runners);
+
+ // |ExternalViewEmbedder|
+ void PrerollCompositeEmbeddedView(
+ int64_t view_id,
+ std::unique_ptr<flutter::EmbeddedViewParams> params) override;
+
+ // |ExternalViewEmbedder|
+ DlCanvas* CompositeEmbeddedView(int64_t view_id) override;
+
+ // |ExternalViewEmbedder|
+ void SubmitFlutterView(
+ int64_t flutter_view_id,
+ GrDirectContext* context,
+ const std::shared_ptr<impeller::AiksContext>& aiks_context,
+ std::unique_ptr<SurfaceFrame> frame) override;
+
+ // |ExternalViewEmbedder|
+ PostPrerollResult PostPrerollAction(
+ const fml::RefPtr<fml::RasterThreadMerger>& raster_thread_merger)
+ override;
+
+ // |ExternalViewEmbedder|
+ DlCanvas* GetRootCanvas() override;
+
+ // |ExternalViewEmbedder|
+ void BeginFrame(GrDirectContext* context,
+ const fml::RefPtr<fml::RasterThreadMerger>&
+ 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<fml::RasterThreadMerger>&
+ 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<int64_t, EmbeddedViewParams>& 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<PlatformViewAndroidJNI> jni_facade_;
+
+ // Allows to create surfaces.
+ const std::shared_ptr<AndroidSurfaceFactory> surface_factory_;
+
+ // Holds surfaces. Allows to recycle surfaces or allocate new ones.
+ const std::unique_ptr<SurfacePool> 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<int64_t> 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<int64_t, std::unique_ptr<EmbedderViewSlice>> slices_;
+
+ // The params for a platform view, which contains the size, position and
+ // mutation stack.
+ std::unordered_map<int64_t, EmbeddedViewParams> 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<SurfaceFrame> 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 7290a58..ed979c8 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() = 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 @@
"rendering.";
std::unique_ptr<PlatformViewAndroidJNI::OverlayMetadata> 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 @@
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 @@
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 5f09d6d..45719bc 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 @@
class SurfacePool {
public:
- SurfacePool();
+ explicit SurfacePool(bool use_new_surface_methods);
~SurfacePool();
@@ -76,6 +76,8 @@
// 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 @@
// Used to guard public methods.
std::mutex mutex_;
+ bool use_new_surface_methods_ = false;
void DestroyLayersLocked(
const std::shared_ptr<PlatformViewAndroidJNI>& 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 09cf54b..98df5f0 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 @@
};
TEST(SurfacePool, GetLayerAllocateOneLayer) {
- auto pool = std::make_unique<SurfacePool>();
+ auto pool = std::make_unique<SurfacePool>(/*use_new_surface_methods=*/false);
auto gr_context = GrDirectContext::MakeMock(nullptr);
auto android_context =
@@ -69,7 +69,7 @@
}
TEST(SurfacePool, GetUnusedLayers) {
- auto pool = std::make_unique<SurfacePool>();
+ auto pool = std::make_unique<SurfacePool>(/*use_new_surface_methods=*/false);
auto gr_context = GrDirectContext::MakeMock(nullptr);
auto android_context =
@@ -102,7 +102,7 @@
}
TEST(SurfacePool, GetLayerRecycle) {
- auto pool = std::make_unique<SurfacePool>();
+ auto pool = std::make_unique<SurfacePool>(/*use_new_surface_methods=*/false);
auto gr_context_1 = GrDirectContext::MakeMock(nullptr);
auto jni_mock = std::make_shared<JNIMock>();
@@ -147,7 +147,7 @@
}
TEST(SurfacePool, GetLayerAllocateTwoLayers) {
- auto pool = std::make_unique<SurfacePool>();
+ auto pool = std::make_unique<SurfacePool>(/*use_new_surface_methods=*/false);
auto gr_context = GrDirectContext::MakeMock(nullptr);
auto android_context =
@@ -185,8 +185,45 @@
ASSERT_EQ(1, layer_2->id);
}
+TEST(SurfacePool, DestroyLayersNew) {
+ auto pool = std::make_unique<SurfacePool>(/*use_new_surface_methods=*/true);
+ auto jni_mock = std::make_shared<JNIMock>();
+
+ EXPECT_CALL(*jni_mock, destroyOverlaySurface2()).Times(0);
+ pool->DestroyLayers(jni_mock);
+
+ auto gr_context = GrDirectContext::MakeMock(nullptr);
+ auto android_context =
+ std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
+
+ auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
+ EXPECT_CALL(*jni_mock, createOverlaySurface2())
+ .Times(1)
+ .WillOnce(Return(
+ ByMove(std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
+ 0, window))));
+
+ auto surface_factory =
+ std::make_shared<TestAndroidSurfaceFactory>([gr_context, window]() {
+ auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
+ 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<SurfacePool>();
+ auto pool = std::make_unique<SurfacePool>(/*use_new_surface_methods=*/false);
auto jni_mock = std::make_shared<JNIMock>();
EXPECT_CALL(*jni_mock, FlutterViewDestroyOverlaySurfaces()).Times(0);
@@ -223,7 +260,7 @@
}
TEST(SurfacePool, DestroyLayersFrameSizeChanged) {
- auto pool = std::make_unique<SurfacePool>();
+ auto pool = std::make_unique<SurfacePool>(/*use_new_surface_methods=*/false);
auto jni_mock = std::make_shared<JNIMock>();
auto gr_context = GrDirectContext::MakeMock(nullptr);
@@ -267,5 +304,50 @@
ASSERT_TRUE(pool->HasLayers());
}
+TEST(SurfacePool, DestroyLayersFrameSizeChangedNew) {
+ auto pool = std::make_unique<SurfacePool>(/*use_new_surface_methods=*/true);
+ auto jni_mock = std::make_shared<JNIMock>();
+
+ auto gr_context = GrDirectContext::MakeMock(nullptr);
+ auto android_context =
+ std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
+
+ auto window = fml::MakeRefCounted<AndroidNativeWindow>(nullptr);
+
+ auto surface_factory =
+ std::make_shared<TestAndroidSurfaceFactory>([gr_context, window]() {
+ auto android_surface_mock = std::make_unique<AndroidSurfaceMock>();
+ 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<PlatformViewAndroidJNI::OverlayMetadata>(
+ 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<PlatformViewAndroidJNI::OverlayMetadata>(
+ 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 fdfd13a..a4e123c 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 @@
asyncWaitForVsyncDelegate = delegate;
}
- // TODO(mattcarroll): add javadocs
// Called by native.
private static void asyncWaitForVsync(final long cookie) {
if (asyncWaitForVsyncDelegate != null) {
@@ -596,7 +595,6 @@
}
}
- // TODO(mattcarroll): get native to call this when rendering stops.
@VisibleForTesting
@UiThread
void onRenderingStopped() {
@@ -810,8 +808,6 @@
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 @@
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 @@
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 @@
}
// 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 @@
} 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 @@
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 @@
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 @@
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 @@
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 cf5b329..1dedcf8 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 @@
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<PlatformViewAndroidJNI::OverlayMetadata>,
+ 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<std::vector<std::string>>,
FlutterViewComputePlatformResolvedLocale,
(std::vector<std::string> 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 356b677..68e3b42 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 @@
///
virtual void FlutterViewDestroyOverlaySurfaces() = 0;
+ // New Platform View Support.
+ virtual ASurfaceTransaction* createTransaction() = 0;
+
+ virtual void swapTransaction() = 0;
+
+ virtual void applyTransaction() = 0;
+
+ virtual std::unique_ptr<PlatformViewAndroidJNI::OverlayMetadata>
+ 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 694b3eb..db8de49 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 @@
// |PlatformView|
std::shared_ptr<ExternalViewEmbedder>
PlatformViewAndroid::CreateExternalViewEmbedder() {
+ if (android_use_new_platform_view_) {
+ return std::make_shared<AndroidExternalViewEmbedder2>(
+ *android_context_, jni_facade_, surface_factory_, task_runners_);
+ }
return std::make_shared<AndroidExternalViewEmbedder>(
*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 5310826..5d0b630 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 @@
std::unique_ptr<AndroidSurface> android_surface_;
std::shared_ptr<PlatformMessageHandlerAndroid> 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 8977d21..18c34ae 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<AndroidShellHolder*>(shell_holder))
@@ -132,8 +133,6 @@
// 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_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<jclass>* g_mutators_stack_class = nullptr;
static jmethodID g_mutators_stack_init_method = nullptr;
@@ -968,6 +980,60 @@
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<jclass> overlay_surface_class(
env, env->FindClass("io/flutter/embedding/engine/FlutterOverlaySurface"));
if (overlay_surface_class.is_null()) {
@@ -1913,4 +1979,176 @@
return true;
}
+// New Platform View Support.
+
+ASurfaceTransaction* PlatformViewAndroidJNIImpl::createTransaction() {
+ JNIEnv* env = fml::jni::AttachCurrentThread();
+
+ auto java_object = java_object_.get(env);
+
+ fml::jni::ScopedJavaLocalRef<jobject> 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<PlatformViewAndroidJNI::OverlayMetadata>
+PlatformViewAndroidJNIImpl::createOverlaySurface2() {
+ JNIEnv* env = fml::jni::AttachCurrentThread();
+
+ auto java_object = java_object_.get(env);
+ if (java_object.is_null()) {
+ return nullptr;
+ }
+
+ fml::jni::ScopedJavaLocalRef<jobject> 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<PlatformViewAndroidJNI::OverlayMetadata>(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<AndroidNativeWindow>(
+ ANativeWindow_fromSurface(env, overlay_surface));
+
+ return std::make_unique<PlatformViewAndroidJNI::OverlayMetadata>(
+ 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<std::shared_ptr<Mutator>>::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<jfloatArray> 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<int>(rect.left()), static_cast<int>(rect.top()),
+ static_cast<int>(rect.right()), static_cast<int>(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<jfloatArray> radiisArray(
+ env, env->NewFloatArray(8));
+ env->SetFloatArrayRegion(radiisArray.obj(), 0, 8, radiis);
+ env->CallVoidMethod(
+ mutatorsStack, g_mutators_stack_push_cliprrect_method,
+ static_cast<int>(rect.left()), static_cast<int>(rect.top()),
+ static_cast<int>(rect.right()), static_cast<int>(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 73cb6a4..d05ee13 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 @@
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<PlatformViewAndroidJNI::OverlayMetadata>
+ 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_;