[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...
This commit is contained in:
parent
b68321a45d
commit
8c11026d3f
@ -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
|
||||
|
@ -115,11 +115,12 @@ std::unique_ptr<SurfaceFrame> 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 //
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -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<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),
|
||||
|
@ -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",
|
||||
]
|
||||
|
@ -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<SurfacePool>()),
|
||||
surface_pool_(
|
||||
std::make_unique<SurfacePool>(/*use_new_surface_methods=*/false)),
|
||||
task_runners_(task_runners) {}
|
||||
|
||||
// |ExternalViewEmbedder|
|
||||
|
@ -74,8 +74,10 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder {
|
||||
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
|
||||
|
@ -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
|
@ -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_
|
@ -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<OverlayLayer> SurfacePool::GetLayer(
|
||||
"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 @@ 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
|
||||
|
@ -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<PlatformViewAndroidJNI>& jni_facade);
|
||||
|
@ -38,7 +38,7 @@ class TestAndroidSurfaceFactory : public AndroidSurfaceFactory {
|
||||
};
|
||||
|
||||
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, GetLayerAllocateOneLayer) {
|
||||
}
|
||||
|
||||
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, GetUnusedLayers) {
|
||||
}
|
||||
|
||||
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, GetLayerRecycle) {
|
||||
}
|
||||
|
||||
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 @@ TEST(SurfacePool, GetLayerAllocateTwoLayers) {
|
||||
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, DestroyLayers) {
|
||||
}
|
||||
|
||||
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 @@ TEST(SurfacePool, DestroyLayersFrameSizeChanged) {
|
||||
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
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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<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),
|
||||
|
@ -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<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.
|
||||
///
|
||||
|
@ -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<Surface> PlatformViewAndroid::CreateRenderingSurface() {
|
||||
// |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_);
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ class PlatformViewAndroid final : public PlatformView {
|
||||
|
||||
std::unique_ptr<AndroidSurface> android_surface_;
|
||||
std::shared_ptr<PlatformMessageHandlerAndroid> platform_message_handler_;
|
||||
bool android_use_new_platform_view_ = false;
|
||||
|
||||
// |PlatformView|
|
||||
void UpdateSemantics(
|
||||
|
@ -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 @@ 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<jclass>* 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<jclass> 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<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
|
||||
|
@ -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<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_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user