diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 07d1c4b73c346..c92af1d5b02b9 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -782,13 +782,15 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArgument FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java +FILE: ../../../flutter/shell/platform/android/jni/platform_view_android_jni.cc +FILE: ../../../flutter/shell/platform/android/jni/platform_view_android_jni.h FILE: ../../../flutter/shell/platform/android/library_loader.cc FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h FILE: ../../../flutter/shell/platform/android/platform_view_android.cc FILE: ../../../flutter/shell/platform/android/platform_view_android.h -FILE: ../../../flutter/shell/platform/android/platform_view_android_jni.cc -FILE: ../../../flutter/shell/platform/android/platform_view_android_jni.h +FILE: ../../../flutter/shell/platform/android/platform_view_android_jni_impl.cc +FILE: ../../../flutter/shell/platform/android/platform_view_android_jni_impl.h FILE: ../../../flutter/shell/platform/android/robolectric.properties FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 0b8195863e4e6..f68249194b751 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -50,8 +50,8 @@ shared_library("flutter_shell_native") { "platform_message_response_android.h", "platform_view_android.cc", "platform_view_android.h", - "platform_view_android_jni.cc", - "platform_view_android_jni.h", + "platform_view_android_jni_impl.cc", + "platform_view_android_jni_impl.h", "vsync_waiter_android.cc", "vsync_waiter_android.h", ] @@ -68,6 +68,7 @@ shared_library("flutter_shell_native") { "//flutter/runtime:libdart", "//flutter/shell/common", "//flutter/shell/platform/android/external_view_embedder", + "//flutter/shell/platform/android/jni", "//third_party/skia", ] diff --git a/shell/platform/android/android_external_texture_gl.cc b/shell/platform/android/android_external_texture_gl.cc index 8c4f960b0f232..01822b2329bff 100644 --- a/shell/platform/android/android_external_texture_gl.cc +++ b/shell/platform/android/android_external_texture_gl.cc @@ -6,15 +6,18 @@ #include -#include "flutter/shell/platform/android/platform_view_android_jni.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" namespace flutter { AndroidExternalTextureGL::AndroidExternalTextureGL( int64_t id, - const fml::jni::JavaObjectWeakGlobalRef& surfaceTexture) - : Texture(id), surface_texture_(surfaceTexture), transform(SkMatrix::I()) {} + const fml::jni::JavaObjectWeakGlobalRef& surface_texture, + std::shared_ptr jni_facade) + : Texture(id), + jni_facade_(jni_facade), + surface_texture_(surface_texture), + transform(SkMatrix::I()) {} AndroidExternalTextureGL::~AndroidExternalTextureGL() { if (state_ == AttachmentState::attached) { @@ -68,36 +71,8 @@ void AndroidExternalTextureGL::Paint(SkCanvas& canvas, } } -// The bounds we set for the canvas are post composition. -// To fill the canvas we need to ensure that the transformation matrix -// on the `SurfaceTexture` will be scaled to fill. We rescale and preseve -// the scaled aspect ratio. -SkSize ScaleToFill(float scaleX, float scaleY) { - const double epsilon = std::numeric_limits::epsilon(); - // scaleY is negative. - const double minScale = fmin(scaleX, fabs(scaleY)); - const double rescale = 1.0f / (minScale + epsilon); - return SkSize::Make(scaleX * rescale, scaleY * rescale); -} - void AndroidExternalTextureGL::UpdateTransform() { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef surfaceTexture = - surface_texture_.get(env); - fml::jni::ScopedJavaLocalRef transformMatrix( - env, env->NewFloatArray(16)); - SurfaceTextureGetTransformMatrix(env, surfaceTexture.obj(), - transformMatrix.obj()); - float* m = env->GetFloatArrayElements(transformMatrix.obj(), nullptr); - float scaleX = m[0], scaleY = m[5]; - const SkSize scaled = ScaleToFill(scaleX, scaleY); - SkScalar matrix3[] = { - scaled.fWidth, m[1], m[2], // - m[4], scaled.fHeight, m[6], // - m[8], m[9], m[10], // - }; - env->ReleaseFloatArrayElements(transformMatrix.obj(), m, JNI_ABORT); - transform.set9(matrix3); + jni_facade_->SurfaceTextureGetTransformMatrix(surface_texture_, transform); } void AndroidExternalTextureGL::OnGrContextDestroyed() { @@ -108,31 +83,16 @@ void AndroidExternalTextureGL::OnGrContextDestroyed() { } void AndroidExternalTextureGL::Attach(jint textureName) { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef surfaceTexture = - surface_texture_.get(env); - if (!surfaceTexture.is_null()) { - SurfaceTextureAttachToGLContext(env, surfaceTexture.obj(), textureName); - } + jni_facade_->SurfaceTextureAttachToGLContext(surface_texture_, textureName); } void AndroidExternalTextureGL::Update() { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef surfaceTexture = - surface_texture_.get(env); - if (!surfaceTexture.is_null()) { - SurfaceTextureUpdateTexImage(env, surfaceTexture.obj()); - UpdateTransform(); - } + jni_facade_->SurfaceTextureUpdateTexImage(surface_texture_); + UpdateTransform(); } void AndroidExternalTextureGL::Detach() { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef surfaceTexture = - surface_texture_.get(env); - if (!surfaceTexture.is_null()) { - SurfaceTextureDetachFromGLContext(env, surfaceTexture.obj()); - } + jni_facade_->SurfaceTextureDetachFromGLContext(surface_texture_); } void AndroidExternalTextureGL::OnTextureUnregistered() {} diff --git a/shell/platform/android/android_external_texture_gl.h b/shell/platform/android/android_external_texture_gl.h index 4e2b187eb3f61..c8268be8a4689 100644 --- a/shell/platform/android/android_external_texture_gl.h +++ b/shell/platform/android/android_external_texture_gl.h @@ -8,6 +8,7 @@ #include #include "flutter/flow/texture.h" #include "flutter/fml/platform/android/jni_weak_ref.h" +#include "flutter/shell/platform/android/platform_view_android_jni_impl.h" namespace flutter { @@ -15,7 +16,8 @@ class AndroidExternalTextureGL : public flutter::Texture { public: AndroidExternalTextureGL( int64_t id, - const fml::jni::JavaObjectWeakGlobalRef& surfaceTexture); + const fml::jni::JavaObjectWeakGlobalRef& surface_texture, + std::shared_ptr jni_facade); ~AndroidExternalTextureGL() override; @@ -43,6 +45,8 @@ class AndroidExternalTextureGL : public flutter::Texture { enum class AttachmentState { uninitialized, attached, detached }; + std::shared_ptr jni_facade_; + fml::jni::JavaObjectWeakGlobalRef surface_texture_; AttachmentState state_ = AttachmentState::uninitialized; diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index 4f7e78a2812cb..e99c76e961ed1 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -29,9 +29,9 @@ static WindowData GetDefaultWindowData() { AndroidShellHolder::AndroidShellHolder( flutter::Settings settings, - fml::jni::JavaObjectWeakGlobalRef java_object, + std::shared_ptr jni_facade, bool is_background_view) - : settings_(std::move(settings)), java_object_(java_object) { + : settings_(std::move(settings)), jni_facade_(jni_facade) { static size_t shell_count = 1; auto thread_label = std::to_string(shell_count++); @@ -56,20 +56,19 @@ AndroidShellHolder::AndroidShellHolder( fml::WeakPtr weak_platform_view; Shell::CreateCallback on_create_platform_view = - [is_background_view, java_object, &weak_platform_view](Shell& shell) { + [is_background_view, &jni_facade, &weak_platform_view](Shell& shell) { std::unique_ptr platform_view_android; if (is_background_view) { platform_view_android = std::make_unique( shell, // delegate shell.GetTaskRunners(), // task runners - java_object // java object handle for JNI interop + jni_facade // JNI interop ); - } else { platform_view_android = std::make_unique( shell, // delegate shell.GetTaskRunners(), // task runners - java_object, // java object handle for JNI interop + jni_facade, // JNI interop shell.GetSettings() .enable_software_rendering // use software rendering ); diff --git a/shell/platform/android/android_shell_holder.h b/shell/platform/android/android_shell_holder.h index 3a0f1410f0978..107e93f18672a 100644 --- a/shell/platform/android/android_shell_holder.h +++ b/shell/platform/android/android_shell_holder.h @@ -8,13 +8,13 @@ #include #include "flutter/fml/macros.h" -#include "flutter/fml/platform/android/jni_weak_ref.h" #include "flutter/fml/unique_fd.h" #include "flutter/lib/ui/window/viewport_metrics.h" #include "flutter/runtime/window_data.h" #include "flutter/shell/common/run_configuration.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/thread_host.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "flutter/shell/platform/android/platform_view_android.h" namespace flutter { @@ -22,7 +22,7 @@ namespace flutter { class AndroidShellHolder { public: AndroidShellHolder(flutter::Settings settings, - fml::jni::JavaObjectWeakGlobalRef java_object, + std::shared_ptr jni_facade, bool is_background_view); ~AndroidShellHolder(); @@ -44,7 +44,7 @@ class AndroidShellHolder { private: const flutter::Settings settings_; - const fml::jni::JavaObjectWeakGlobalRef java_object_; + const std::shared_ptr jni_facade_; fml::WeakPtr platform_view_; ThreadHost thread_host_; std::unique_ptr shell_; diff --git a/shell/platform/android/android_surface.cc b/shell/platform/android/android_surface.cc index 711a1e0571002..e50f79180b78b 100644 --- a/shell/platform/android/android_surface.cc +++ b/shell/platform/android/android_surface.cc @@ -15,18 +15,19 @@ namespace flutter { std::unique_ptr AndroidSurface::Create( - std::shared_ptr android_context) { + std::shared_ptr android_context, + std::shared_ptr jni_facade) { std::unique_ptr surface; switch (android_context->RenderingApi()) { case AndroidRenderingAPI::kSoftware: - surface = std::make_unique(); + surface = std::make_unique(jni_facade); break; case AndroidRenderingAPI::kOpenGLES: - surface = std::make_unique(android_context); + surface = std::make_unique(android_context, jni_facade); break; case AndroidRenderingAPI::kVulkan: #if SHELL_ENABLE_VULKAN - surface = std::make_unique(); + surface = std::make_unique(jni_facade); #endif // SHELL_ENABLE_VULKAN break; } diff --git a/shell/platform/android/android_surface.h b/shell/platform/android/android_surface.h index 329b971adee24..4997588b6a649 100644 --- a/shell/platform/android/android_surface.h +++ b/shell/platform/android/android_surface.h @@ -14,6 +14,7 @@ #include "flutter/shell/common/platform_view.h" #include "flutter/shell/platform/android/android_context.h" #include "flutter/shell/platform/android/android_native_window.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "third_party/skia/include/core/SkSize.h" namespace flutter { @@ -21,7 +22,8 @@ namespace flutter { class AndroidSurface { public: static std::unique_ptr Create( - std::shared_ptr android_context); + std::shared_ptr android_context, + std::shared_ptr jni_facade); virtual ~AndroidSurface(); diff --git a/shell/platform/android/android_surface_gl.cc b/shell/platform/android/android_surface_gl.cc index 28011c99abae8..434ad08dda268 100644 --- a/shell/platform/android/android_surface_gl.cc +++ b/shell/platform/android/android_surface_gl.cc @@ -12,7 +12,8 @@ namespace flutter { AndroidSurfaceGL::AndroidSurfaceGL( - std::shared_ptr android_context) + std::shared_ptr android_context, + std::shared_ptr jni_facade) : native_window_(nullptr), onscreen_surface_(nullptr), offscreen_surface_(nullptr) { @@ -23,7 +24,8 @@ AndroidSurfaceGL::AndroidSurfaceGL( if (!offscreen_surface_->IsValid()) { offscreen_surface_ = nullptr; } - external_view_embedder_ = std::make_unique(); + external_view_embedder_ = + std::make_unique(jni_facade); } AndroidSurfaceGL::~AndroidSurfaceGL() = default; diff --git a/shell/platform/android/android_surface_gl.h b/shell/platform/android/android_surface_gl.h index 1db19d115c489..faf30e0b8afc8 100644 --- a/shell/platform/android/android_surface_gl.h +++ b/shell/platform/android/android_surface_gl.h @@ -14,13 +14,15 @@ #include "flutter/shell/platform/android/android_environment_gl.h" #include "flutter/shell/platform/android/android_surface.h" #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" namespace flutter { class AndroidSurfaceGL final : public GPUSurfaceGLDelegate, public AndroidSurface { public: - AndroidSurfaceGL(std::shared_ptr android_context); + AndroidSurfaceGL(std::shared_ptr android_context, + std::shared_ptr jni_facade); ~AndroidSurfaceGL() override; diff --git a/shell/platform/android/android_surface_software.cc b/shell/platform/android/android_surface_software.cc index 562bd0937f10b..56d9e3bc542fd 100644 --- a/shell/platform/android/android_surface_software.cc +++ b/shell/platform/android/android_surface_software.cc @@ -11,7 +11,7 @@ #include "flutter/fml/platform/android/jni_weak_ref.h" #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/platform/android/platform_view_android_jni.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" namespace flutter { @@ -36,10 +36,12 @@ bool GetSkColorType(int32_t buffer_format, } // anonymous namespace -AndroidSurfaceSoftware::AndroidSurfaceSoftware() { +AndroidSurfaceSoftware::AndroidSurfaceSoftware( + std::shared_ptr jni_facade) { GetSkColorType(WINDOW_FORMAT_RGBA_8888, &target_color_type_, &target_alpha_type_); - external_view_embedder_ = std::make_unique(); + external_view_embedder_ = + std::make_unique(jni_facade); } AndroidSurfaceSoftware::~AndroidSurfaceSoftware() = default; diff --git a/shell/platform/android/android_surface_software.h b/shell/platform/android/android_surface_software.h index dfe3de9fb6738..00a4b245af7d2 100644 --- a/shell/platform/android/android_surface_software.h +++ b/shell/platform/android/android_surface_software.h @@ -11,13 +11,14 @@ #include "flutter/shell/gpu/gpu_surface_software.h" #include "flutter/shell/platform/android/android_surface.h" #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" namespace flutter { class AndroidSurfaceSoftware final : public AndroidSurface, public GPUSurfaceSoftwareDelegate { public: - AndroidSurfaceSoftware(); + AndroidSurfaceSoftware(std::shared_ptr jni_facade); ~AndroidSurfaceSoftware() override; diff --git a/shell/platform/android/android_surface_vulkan.cc b/shell/platform/android/android_surface_vulkan.cc index 1ed814ff539a4..3d802a1f1ba42 100644 --- a/shell/platform/android/android_surface_vulkan.cc +++ b/shell/platform/android/android_surface_vulkan.cc @@ -12,9 +12,11 @@ namespace flutter { -AndroidSurfaceVulkan::AndroidSurfaceVulkan() +AndroidSurfaceVulkan::AndroidSurfaceVulkan( + std::shared_ptr jni_facade) : proc_table_(fml::MakeRefCounted()) { - external_view_embedder_ = std::make_unique(); + external_view_embedder_ = + std::make_unique(jni_facade); } AndroidSurfaceVulkan::~AndroidSurfaceVulkan() = default; diff --git a/shell/platform/android/android_surface_vulkan.h b/shell/platform/android/android_surface_vulkan.h index d73addf5bdf8e..2778a7ec10003 100644 --- a/shell/platform/android/android_surface_vulkan.h +++ b/shell/platform/android/android_surface_vulkan.h @@ -12,6 +12,7 @@ #include "flutter/shell/platform/android/android_native_window.h" #include "flutter/shell/platform/android/android_surface.h" #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "flutter/vulkan/vulkan_window.h" namespace flutter { @@ -19,7 +20,7 @@ namespace flutter { class AndroidSurfaceVulkan : public AndroidSurface, public GPUSurfaceVulkanDelegate { public: - AndroidSurfaceVulkan(); + AndroidSurfaceVulkan(std::shared_ptr jni_facade); ~AndroidSurfaceVulkan() override; diff --git a/shell/platform/android/external_view_embedder/BUILD.gn b/shell/platform/android/external_view_embedder/BUILD.gn index a3ff4df4ec47e..5145e00fa8972 100644 --- a/shell/platform/android/external_view_embedder/BUILD.gn +++ b/shell/platform/android/external_view_embedder/BUILD.gn @@ -22,6 +22,7 @@ source_set("external_view_embedder") { "//flutter/common", "//flutter/flow", "//flutter/fml", + "//flutter/shell/platform/android/jni", "//third_party/skia", ] } diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.cc b/shell/platform/android/external_view_embedder/external_view_embedder.cc index 469404dc2ca6a..4e42ac662f77f 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -8,6 +8,10 @@ namespace flutter { +AndroidExternalViewEmbedder::AndroidExternalViewEmbedder( + std::shared_ptr jni_facade) + : ExternalViewEmbedder(), jni_facade_(jni_facade) {} + // |ExternalViewEmbedder| void AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView( int view_id, diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.h b/shell/platform/android/external_view_embedder/external_view_embedder.h index 8d8e8093de8c9..6cfa82a8d58e1 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -7,12 +7,16 @@ #include "flutter/flow/embedded_views.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" #include "third_party/skia/include/core/SkPictureRecorder.h" namespace flutter { -class AndroidExternalViewEmbedder : public ExternalViewEmbedder { +class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { public: + AndroidExternalViewEmbedder( + std::shared_ptr jni_facade); + // |ExternalViewEmbedder| void PrerollCompositeEmbeddedView( int view_id, @@ -48,6 +52,9 @@ class AndroidExternalViewEmbedder : public ExternalViewEmbedder { fml::RefPtr raster_thread_merger) override; private: + // Allows to call methods in Java. + const std::shared_ptr jni_facade_; + // The number of frames the rasterizer task runner will continue // to run on the platform thread after no platform view is rendered. // diff --git a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc index beb84db8d0e40..d0ef824cb6724 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc @@ -11,7 +11,7 @@ namespace flutter { namespace testing { TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) { - auto embedder = new AndroidExternalViewEmbedder(); + auto embedder = new AndroidExternalViewEmbedder(nullptr); embedder->BeginFrame(SkISize::Make(10, 20), nullptr, 1.0); @@ -27,7 +27,7 @@ TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) { } TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) { - auto embedder = new AndroidExternalViewEmbedder(); + auto embedder = new AndroidExternalViewEmbedder(nullptr); embedder->PrerollCompositeEmbeddedView( 0, std::make_unique()); @@ -39,7 +39,7 @@ TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) { } TEST(AndroidExternalViewEmbedder, CancelFrame) { - auto embedder = new AndroidExternalViewEmbedder(); + auto embedder = new AndroidExternalViewEmbedder(nullptr); embedder->PrerollCompositeEmbeddedView( 0, std::make_unique()); @@ -50,7 +50,7 @@ TEST(AndroidExternalViewEmbedder, CancelFrame) { } TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) { - auto embedder = new AndroidExternalViewEmbedder(); + auto embedder = new AndroidExternalViewEmbedder(nullptr); auto platform_thread = new fml::Thread("platform"); auto rasterizer_thread = new fml::Thread("rasterizer"); auto platform_queue_id = platform_thread->GetTaskRunner()->GetTaskQueueId(); @@ -82,7 +82,7 @@ TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) { } TEST(AndroidExternalViewEmbedder, RasterizerRunsOnRasterizerThread) { - auto embedder = new AndroidExternalViewEmbedder(); + auto embedder = new AndroidExternalViewEmbedder(nullptr); auto platform_thread = new fml::Thread("platform"); auto rasterizer_thread = new fml::Thread("rasterizer"); auto platform_queue_id = platform_thread->GetTaskRunner()->GetTaskQueueId(); diff --git a/shell/platform/android/jni/BUILD.gn b/shell/platform/android/jni/BUILD.gn new file mode 100644 index 0000000000000..700dfb5c6676e --- /dev/null +++ b/shell/platform/android/jni/BUILD.gn @@ -0,0 +1,20 @@ +# 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. + +import("//flutter/common/config.gni") + +source_set("jni") { + sources = [ + "platform_view_android_jni.cc", + "platform_view_android_jni.h", + ] + + public_configs = [ "//flutter:config" ] + + deps = [ + "//flutter/fml", + "//flutter/lib/ui", + "//third_party/skia", + ] +} diff --git a/shell/platform/android/jni/platform_view_android_jni.cc b/shell/platform/android/jni/platform_view_android_jni.cc new file mode 100644 index 0000000000000..b00a39be3bae0 --- /dev/null +++ b/shell/platform/android/jni/platform_view_android_jni.cc @@ -0,0 +1,11 @@ +// 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/jni/platform_view_android_jni.h" + +namespace flutter { + +PlatformViewAndroidJNI::~PlatformViewAndroidJNI() = default; + +} // namespace flutter diff --git a/shell/platform/android/jni/platform_view_android_jni.h b/shell/platform/android/jni/platform_view_android_jni.h new file mode 100644 index 0000000000000..eed89a1347845 --- /dev/null +++ b/shell/platform/android/jni/platform_view_android_jni.h @@ -0,0 +1,137 @@ +// 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_PLATFORM_VIEW_ANDROID_JNI_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_H_ + +#include "flutter/fml/macros.h" +#include "flutter/fml/mapping.h" + +#if OS_ANDROID +#include "flutter/fml/platform/android/jni_weak_ref.h" +#endif + +#include "flutter/lib/ui/window/platform_message.h" +#include "third_party/skia/include/core/SkMatrix.h" + +namespace flutter { + +#if OS_ANDROID +using JavaWeakGlobalRef = fml::jni::JavaObjectWeakGlobalRef; +#else +using JavaWeakGlobalRef = std::nullptr_t; +#endif + +//------------------------------------------------------------------------------ +/// Allows to call Java code running in the JVM from any thread. However, most +/// methods can only be called from the platform thread as that is where the +/// Java code runs. +/// +/// This interface must not depend on the Android toolchain directly, so it can +/// be used in unit tests compiled with the host toolchain. +/// +class PlatformViewAndroidJNI { + public: + virtual ~PlatformViewAndroidJNI(); + + //---------------------------------------------------------------------------- + /// @brief Sends a platform message. The message may be empty. + /// + virtual void FlutterViewHandlePlatformMessage( + fml::RefPtr message, + int responseId) = 0; + + //---------------------------------------------------------------------------- + /// @brief Responds to a platform message. The data may be a `nullptr`. + /// + virtual void FlutterViewHandlePlatformMessageResponse( + int responseId, + std::unique_ptr data) = 0; + + //---------------------------------------------------------------------------- + /// @brief Sends semantics tree updates. + /// + /// @note Must be called from the platform thread. + /// + virtual void FlutterViewUpdateSemantics(std::vector buffer, + std::vector strings) = 0; + + //---------------------------------------------------------------------------- + /// @brief Sends new custom accessibility events. + /// + /// @note Must be called from the platform thread. + /// + virtual void FlutterViewUpdateCustomAccessibilityActions( + std::vector actions_buffer, + std::vector strings) = 0; + + //---------------------------------------------------------------------------- + /// @brief Indicates that FlutterView should start painting pixels. + /// + /// @note Must be called from the platform thread. + /// + virtual void FlutterViewOnFirstFrame() = 0; + + //---------------------------------------------------------------------------- + /// @brief Indicates that a hot restart is about to happen. + /// + virtual void FlutterViewOnPreEngineRestart() = 0; + + //---------------------------------------------------------------------------- + /// @brief Attach the SurfaceTexture to the OpenGL ES context that is + /// current on the calling thread. + /// + virtual void SurfaceTextureAttachToGLContext( + JavaWeakGlobalRef surface_texture, + int textureId) = 0; + + //---------------------------------------------------------------------------- + /// @brief Updates the texture image to the most recent frame from the + /// image stream. + /// + virtual void SurfaceTextureUpdateTexImage( + JavaWeakGlobalRef surface_texture) = 0; + + //---------------------------------------------------------------------------- + /// @brief Gets the transform matrix from the SurfaceTexture. + /// Then, it updates the `transform` matrix, so it fill the canvas + /// and preserve the aspect ratio. + /// + virtual void SurfaceTextureGetTransformMatrix( + JavaWeakGlobalRef surface_texture, + SkMatrix& transform) = 0; + + //---------------------------------------------------------------------------- + /// @brief Detaches a SurfaceTexture from the OpenGL ES context. + /// + virtual void SurfaceTextureDetachFromGLContext( + JavaWeakGlobalRef surface_texture) = 0; + + //---------------------------------------------------------------------------- + /// @brief Positions and sizes a platform view if using hybrid + /// composition. + /// + /// @note Must be called from the platform thread. + /// + virtual void FlutterViewOnDisplayPlatformView(int view_id, + int x, + int y, + int width, + int height) = 0; + + //---------------------------------------------------------------------------- + /// @brief Positions and sizes an overlay surface in hybrid composition. + /// + /// @note Must be called from the platform thread. + /// + virtual void FlutterViewDisplayOverlaySurface(int surface_id, + int x, + int y, + int width, + int height) = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_H_ diff --git a/shell/platform/android/platform_message_response_android.cc b/shell/platform/android/platform_message_response_android.cc index f79f2b8c155a7..36950caf43942 100644 --- a/shell/platform/android/platform_message_response_android.cc +++ b/shell/platform/android/platform_message_response_android.cc @@ -5,16 +5,16 @@ #include "flutter/shell/platform/android/platform_message_response_android.h" #include "flutter/fml/make_copyable.h" -#include "flutter/shell/platform/android/platform_view_android_jni.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" namespace flutter { PlatformMessageResponseAndroid::PlatformMessageResponseAndroid( int response_id, - fml::jni::JavaObjectWeakGlobalRef weak_java_object, + std::shared_ptr jni_facade, fml::RefPtr platform_task_runner) : response_id_(response_id), - weak_java_object_(weak_java_object), + jni_facade_(jni_facade), platform_task_runner_(std::move(platform_task_runner)) {} PlatformMessageResponseAndroid::~PlatformMessageResponseAndroid() = default; @@ -23,53 +23,23 @@ PlatformMessageResponseAndroid::~PlatformMessageResponseAndroid() = default; void PlatformMessageResponseAndroid::Complete( std::unique_ptr data) { platform_task_runner_->PostTask( - fml::MakeCopyable([response = response_id_, // - weak_java_object = weak_java_object_, // - data = std::move(data) // - ]() { - // We are on the platform thread. Attempt to get the strong reference to - // the Java object. - auto* env = fml::jni::AttachCurrentThread(); - auto java_object = weak_java_object.get(env); - - if (java_object.is_null()) { - // The Java object was collected before this message response got to - // it. Drop the response on the floor. - return; - } - - // Convert the vector to a Java byte array. - fml::jni::ScopedJavaLocalRef data_array( - env, env->NewByteArray(data->GetSize())); - env->SetByteArrayRegion( - data_array.obj(), 0, data->GetSize(), - reinterpret_cast(data->GetMapping())); - - // Make the response call into Java. - FlutterViewHandlePlatformMessageResponse(env, java_object.obj(), - response, data_array.obj()); + fml::MakeCopyable([response_id = response_id_, // + data = std::move(data), // + jni_facade = jni_facade_]() mutable { + jni_facade->FlutterViewHandlePlatformMessageResponse(response_id, + std::move(data)); })); } // |flutter::PlatformMessageResponse| void PlatformMessageResponseAndroid::CompleteEmpty() { platform_task_runner_->PostTask( - fml::MakeCopyable([response = response_id_, // - weak_java_object = weak_java_object_ // + fml::MakeCopyable([response_id = response_id_, // + jni_facade = jni_facade_ // ]() { - // We are on the platform thread. Attempt to get the strong reference to - // the Java object. - auto* env = fml::jni::AttachCurrentThread(); - auto java_object = weak_java_object.get(env); - - if (java_object.is_null()) { - // The Java object was collected before this message response got to - // it. Drop the response on the floor. - return; - } // Make the response call into Java. - FlutterViewHandlePlatformMessageResponse(env, java_object.obj(), - response, nullptr); + jni_facade->FlutterViewHandlePlatformMessageResponse(response_id, + nullptr); })); } } // namespace flutter diff --git a/shell/platform/android/platform_message_response_android.h b/shell/platform/android/platform_message_response_android.h index a93b4c802efe4..5b13e4bd268ae 100644 --- a/shell/platform/android/platform_message_response_android.h +++ b/shell/platform/android/platform_message_response_android.h @@ -9,6 +9,7 @@ #include "flutter/fml/platform/android/jni_weak_ref.h" #include "flutter/fml/task_runner.h" #include "flutter/lib/ui/window/platform_message_response.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" namespace flutter { @@ -23,14 +24,14 @@ class PlatformMessageResponseAndroid : public flutter::PlatformMessageResponse { private: PlatformMessageResponseAndroid( int response_id, - fml::jni::JavaObjectWeakGlobalRef weak_java_object, + std::shared_ptr jni_facade, fml::RefPtr platform_task_runner); ~PlatformMessageResponseAndroid() override; - int response_id_; - fml::jni::JavaObjectWeakGlobalRef weak_java_object_; - fml::RefPtr platform_task_runner_; + const int response_id_; + const std::shared_ptr jni_facade_; + const fml::RefPtr platform_task_runner_; FML_FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseAndroid); FML_DISALLOW_COPY_AND_ASSIGN(PlatformMessageResponseAndroid); diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index c1e396d043e02..0cae52e370c4d 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -13,8 +13,8 @@ #include "flutter/shell/platform/android/android_context.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" #include "flutter/shell/platform/android/android_surface_gl.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/platform_view_android_jni.h" #include "flutter/shell/platform/android/vsync_waiter_android.h" namespace flutter { @@ -22,10 +22,9 @@ namespace flutter { PlatformViewAndroid::PlatformViewAndroid( PlatformView::Delegate& delegate, flutter::TaskRunners task_runners, - fml::jni::JavaObjectWeakGlobalRef java_object, + std::shared_ptr jni_facade, bool use_software_rendering) - : PlatformView(delegate, std::move(task_runners)), - java_object_(java_object) { + : PlatformView(delegate, std::move(task_runners)), jni_facade_(jni_facade) { std::shared_ptr android_context; if (use_software_rendering) { android_context = AndroidContext::Create(AndroidRenderingAPI::kSoftware); @@ -36,7 +35,7 @@ PlatformViewAndroid::PlatformViewAndroid( android_context = AndroidContext::Create(AndroidRenderingAPI::kOpenGLES); #endif // SHELL_ENABLE_VULKAN } - android_surface_ = AndroidSurface::Create(android_context); + android_surface_ = AndroidSurface::Create(android_context, jni_facade); FML_CHECK(android_surface_) << "Could not create an OpenGL, Vulkan or Software surface to setup " "rendering."; @@ -45,10 +44,9 @@ PlatformViewAndroid::PlatformViewAndroid( PlatformViewAndroid::PlatformViewAndroid( PlatformView::Delegate& delegate, flutter::TaskRunners task_runners, - fml::jni::JavaObjectWeakGlobalRef java_object) + std::shared_ptr jni_facade) : PlatformView(delegate, std::move(task_runners)), - java_object_(java_object), - android_surface_(nullptr) {} + jni_facade_(jni_facade) {} PlatformViewAndroid::~PlatformViewAndroid() = default; @@ -113,7 +111,7 @@ void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, fml::RefPtr response; if (response_id) { response = fml::MakeRefCounted( - response_id, java_object_, task_runners_.GetPlatformTaskRunner()); + response_id, jni_facade_, task_runners_.GetPlatformTaskRunner()); } PlatformView::DispatchPlatformMessage( @@ -127,7 +125,7 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env, fml::RefPtr response; if (response_id) { response = fml::MakeRefCounted( - response_id, java_object_, task_runners_.GetPlatformTaskRunner()); + response_id, jni_facade_, task_runners_.GetPlatformTaskRunner()); } PlatformView::DispatchPlatformMessage( @@ -171,46 +169,19 @@ void PlatformViewAndroid::InvokePlatformMessageEmptyResponseCallback( // |PlatformView| void PlatformViewAndroid::HandlePlatformMessage( fml::RefPtr message) { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef view = java_object_.get(env); - if (view.is_null()) - return; - int response_id = 0; if (auto response = message->response()) { response_id = next_response_id_++; pending_responses_[response_id] = response; } - auto java_channel = fml::jni::StringToJavaString(env, message->channel()); - if (message->hasData()) { - fml::jni::ScopedJavaLocalRef message_array( - env, env->NewByteArray(message->data().size())); - env->SetByteArrayRegion( - message_array.obj(), 0, message->data().size(), - reinterpret_cast(message->data().data())); - message = nullptr; - - // This call can re-enter in InvokePlatformMessageXxxResponseCallback. - FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(), - message_array.obj(), response_id); - } else { - message = nullptr; - - // This call can re-enter in InvokePlatformMessageXxxResponseCallback. - FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(), - nullptr, response_id); - } + // This call can re-enter in InvokePlatformMessageXxxResponseCallback. + jni_facade_->FlutterViewHandlePlatformMessage(message, response_id); + message = nullptr; } // |PlatformView| void PlatformViewAndroid::OnPreEngineRestart() const { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef view = java_object_.get(env); - if (view.is_null()) { - // The Java object died. - return; - } - FlutterViewOnPreEngineRestart(fml::jni::AttachCurrentThread(), view.obj()); + jni_facade_->FlutterViewOnPreEngineRestart(); } void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env, @@ -242,12 +213,7 @@ void PlatformViewAndroid::UpdateSemantics( constexpr size_t kBytesPerChild = sizeof(int32_t); constexpr size_t kBytesPerAction = 4 * sizeof(int32_t); - JNIEnv* env = fml::jni::AttachCurrentThread(); { - fml::jni::ScopedJavaLocalRef view = java_object_.get(env); - if (view.is_null()) - return; - size_t num_bytes = 0; for (const auto& value : update) { num_bytes += kBytesPerNode; @@ -372,20 +338,12 @@ void PlatformViewAndroid::UpdateSemantics( // Calling NewDirectByteBuffer in API level 22 and below with a size of zero // will cause a JNI crash. if (actions_buffer.size() > 0) { - fml::jni::ScopedJavaLocalRef direct_actions_buffer( - env, env->NewDirectByteBuffer(actions_buffer.data(), - actions_buffer.size())); - FlutterViewUpdateCustomAccessibilityActions( - env, view.obj(), direct_actions_buffer.obj(), - fml::jni::VectorToStringArray(env, action_strings).obj()); + jni_facade_->FlutterViewUpdateCustomAccessibilityActions(actions_buffer, + strings); } if (buffer.size() > 0) { - fml::jni::ScopedJavaLocalRef direct_buffer( - env, env->NewDirectByteBuffer(buffer.data(), buffer.size())); - FlutterViewUpdateSemantics( - env, view.obj(), direct_buffer.obj(), - fml::jni::VectorToStringArray(env, strings).obj()); + jni_facade_->FlutterViewUpdateSemantics(buffer, strings); } } } @@ -393,8 +351,8 @@ void PlatformViewAndroid::UpdateSemantics( void PlatformViewAndroid::RegisterExternalTexture( int64_t texture_id, const fml::jni::JavaObjectWeakGlobalRef& surface_texture) { - RegisterTexture( - std::make_shared(texture_id, surface_texture)); + RegisterTexture(std::make_shared( + texture_id, surface_texture, std::move(jni_facade_))); } // |PlatformView| @@ -454,13 +412,7 @@ void PlatformViewAndroid::InstallFirstFrameCallback() { } void PlatformViewAndroid::FireFirstFrameCallback() { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef view = java_object_.get(env); - if (view.is_null()) { - // The Java object died. - return; - } - FlutterViewOnFirstFrame(fml::jni::AttachCurrentThread(), view.obj()); + jni_facade_->FlutterViewOnFirstFrame(); } } // namespace flutter diff --git a/shell/platform/android/platform_view_android.h b/shell/platform/android/platform_view_android.h index d517e7fda2970..9f859a1dcdaf5 100644 --- a/shell/platform/android/platform_view_android.h +++ b/shell/platform/android/platform_view_android.h @@ -17,6 +17,7 @@ #include "flutter/shell/common/platform_view.h" #include "flutter/shell/platform/android/android_native_window.h" #include "flutter/shell/platform/android/android_surface.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" namespace flutter { @@ -28,12 +29,12 @@ class PlatformViewAndroid final : public PlatformView { // background execution. PlatformViewAndroid(PlatformView::Delegate& delegate, flutter::TaskRunners task_runners, - fml::jni::JavaObjectWeakGlobalRef java_object); + std::shared_ptr jni_facade); // Creates a PlatformViewAndroid with a rendering surface. PlatformViewAndroid(PlatformView::Delegate& delegate, flutter::TaskRunners task_runners, - fml::jni::JavaObjectWeakGlobalRef java_object, + std::shared_ptr jni_facade, bool use_software_rendering); ~PlatformViewAndroid() override; @@ -74,7 +75,7 @@ class PlatformViewAndroid final : public PlatformView { const fml::jni::JavaObjectWeakGlobalRef& surface_texture); private: - const fml::jni::JavaObjectWeakGlobalRef java_object_; + const std::shared_ptr jni_facade_; std::unique_ptr android_surface_; // We use id 0 to mean that no response is expected. diff --git a/shell/platform/android/platform_view_android_jni.h b/shell/platform/android/platform_view_android_jni.h deleted file mode 100644 index ca0736410c1cf..0000000000000 --- a/shell/platform/android/platform_view_android_jni.h +++ /dev/null @@ -1,67 +0,0 @@ -// 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_PLATFORM_VIEW_ANDROID_JNI_H_ -#define FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_H_ - -#include -#include "flutter/fml/macros.h" -#include "flutter/shell/platform/android/platform_view_android.h" - -namespace flutter { - -void FlutterViewHandlePlatformMessage(JNIEnv* env, - jobject obj, - jstring channel, - jobject message, - jint responseId); - -void FlutterViewHandlePlatformMessageResponse(JNIEnv* env, - jobject obj, - jint responseId, - jobject response); - -void FlutterViewUpdateSemantics(JNIEnv* env, - jobject obj, - jobject buffer, - jobjectArray strings); - -void FlutterViewUpdateCustomAccessibilityActions(JNIEnv* env, - jobject obj, - jobject buffer, - jobjectArray strings); - -void FlutterViewOnFirstFrame(JNIEnv* env, jobject obj); - -void FlutterViewOnPreEngineRestart(JNIEnv* env, jobject obj); - -void FlutterViewOnDisplayPlatformView(JNIEnv* env, - jobject obj, - jint view_id, - jint x, - jint y, - jint width, - jint height); - -void FlutterViewDisplayOverlaySurface(JNIEnv* env, - jobject obj, - jint id, - jint x, - jint y, - jint width, - jint height); - -void SurfaceTextureAttachToGLContext(JNIEnv* env, jobject obj, jint textureId); - -void SurfaceTextureUpdateTexImage(JNIEnv* env, jobject obj); - -void SurfaceTextureGetTransformMatrix(JNIEnv* env, - jobject obj, - jfloatArray result); - -void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj); - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_H_ diff --git a/shell/platform/android/platform_view_android_jni.cc b/shell/platform/android/platform_view_android_jni_impl.cc similarity index 76% rename from shell/platform/android/platform_view_android_jni.cc rename to shell/platform/android/platform_view_android_jni_impl.cc index cc9ce7c242524..b791f120f7dcf 100644 --- a/shell/platform/android/platform_view_android_jni.cc +++ b/shell/platform/android/platform_view_android_jni_impl.cc @@ -2,11 +2,12 @@ // 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/platform_view_android_jni.h" +#include "flutter/shell/platform/android/platform_view_android_jni_impl.h" #include - +#include #include + #include "unicode/uchar.h" #include "flutter/assets/directory_asset_bundle.h" @@ -23,6 +24,7 @@ #include "flutter/shell/platform/android/android_shell_holder.h" #include "flutter/shell/platform/android/apk_asset_provider.h" #include "flutter/shell/platform/android/flutter_main.h" +#include "flutter/shell/platform/android/platform_view_android.h" #define ANDROID_SHELL_HOLDER \ (reinterpret_cast(shell_holder)) @@ -67,105 +69,39 @@ jobject CreateFlutterCallbackInformation( } static jmethodID g_handle_platform_message_method = nullptr; -void FlutterViewHandlePlatformMessage(JNIEnv* env, - jobject obj, - jstring channel, - jobject message, - jint responseId) { - env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message, - responseId); - FML_CHECK(CheckException(env)); -} static jmethodID g_handle_platform_message_response_method = nullptr; -void FlutterViewHandlePlatformMessageResponse(JNIEnv* env, - jobject obj, - jint responseId, - jobject response) { - env->CallVoidMethod(obj, g_handle_platform_message_response_method, - responseId, response); - FML_CHECK(CheckException(env)); -} static jmethodID g_update_semantics_method = nullptr; -void FlutterViewUpdateSemantics(JNIEnv* env, - jobject obj, - jobject buffer, - jobjectArray strings) { - env->CallVoidMethod(obj, g_update_semantics_method, buffer, strings); - FML_CHECK(CheckException(env)); -} static jmethodID g_update_custom_accessibility_actions_method = nullptr; -void FlutterViewUpdateCustomAccessibilityActions(JNIEnv* env, - jobject obj, - jobject buffer, - jobjectArray strings) { - env->CallVoidMethod(obj, g_update_custom_accessibility_actions_method, buffer, - strings); - FML_CHECK(CheckException(env)); -} static jmethodID g_on_first_frame_method = nullptr; -void FlutterViewOnFirstFrame(JNIEnv* env, jobject obj) { - env->CallVoidMethod(obj, g_on_first_frame_method); - FML_CHECK(CheckException(env)); -} static jmethodID g_on_engine_restart_method = nullptr; -void FlutterViewOnPreEngineRestart(JNIEnv* env, jobject obj) { - env->CallVoidMethod(obj, g_on_engine_restart_method); - FML_CHECK(CheckException(env)); -} - -static jmethodID g_on_display_platform_view_method = nullptr; -void FlutterViewOnDisplayPlatformView(JNIEnv* env, - jobject obj, - jint view_id, - jint x, - jint y, - jint width, - jint height) { - env->CallVoidMethod(obj, g_on_display_platform_view_method, view_id, x, y, - width, height); - FML_CHECK(CheckException(env)); -} static jmethodID g_attach_to_gl_context_method = nullptr; -void SurfaceTextureAttachToGLContext(JNIEnv* env, jobject obj, jint textureId) { - env->CallVoidMethod(obj, g_attach_to_gl_context_method, textureId); - FML_CHECK(CheckException(env)); -} static jmethodID g_update_tex_image_method = nullptr; -void SurfaceTextureUpdateTexImage(JNIEnv* env, jobject obj) { - env->CallVoidMethod(obj, g_update_tex_image_method); - FML_CHECK(CheckException(env)); -} static jmethodID g_get_transform_matrix_method = nullptr; -void SurfaceTextureGetTransformMatrix(JNIEnv* env, - jobject obj, - jfloatArray result) { - env->CallVoidMethod(obj, g_get_transform_matrix_method, result); - FML_CHECK(CheckException(env)); -} static jmethodID g_detach_from_gl_context_method = nullptr; -void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj) { - env->CallVoidMethod(obj, g_detach_from_gl_context_method); - FML_CHECK(CheckException(env)); -} -// Called By Java +static jmethodID g_on_display_platform_view_method = nullptr; +static jmethodID g_on_display_overlay_surface_method = nullptr; + +// Called By Java static jlong AttachJNI(JNIEnv* env, jclass clazz, jobject flutterJNI, jboolean is_background_view) { fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterJNI); + std::shared_ptr jni_facade = + std::make_shared(java_object); auto shell_holder = std::make_unique( - FlutterMain::Get().GetSettings(), java_object, is_background_view); + FlutterMain::Get().GetSettings(), jni_facade, is_background_view); if (shell_holder->IsValid()) { return reinterpret_cast(shell_holder.release()); } else { @@ -782,6 +718,14 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { return false; } + g_on_display_overlay_surface_method = env->GetMethodID( + g_flutter_jni_class->obj(), "onDisplayOverlaySurface", "(IIIII)V"); + + if (g_on_display_overlay_surface_method == nullptr) { + FML_LOG(ERROR) << "Could not locate onDisplayOverlaySurface method"; + return false; + } + g_surface_texture_class = new fml::jni::ScopedJavaGlobalRef( env, env->FindClass("android/graphics/SurfaceTexture")); if (g_surface_texture_class->is_null()) { @@ -824,4 +768,270 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { return RegisterApi(env); } +PlatformViewAndroidJNIImpl::PlatformViewAndroidJNIImpl( + fml::jni::JavaObjectWeakGlobalRef java_object) + : java_object_(java_object) {} + +PlatformViewAndroidJNIImpl::~PlatformViewAndroidJNIImpl() = default; + +void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessage( + fml::RefPtr message, + int responseId) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + fml::jni::ScopedJavaLocalRef java_channel = + fml::jni::StringToJavaString(env, message->channel()); + + if (message->hasData()) { + fml::jni::ScopedJavaLocalRef message_array( + env, env->NewByteArray(message->data().size())); + env->SetByteArrayRegion( + message_array.obj(), 0, message->data().size(), + reinterpret_cast(message->data().data())); + env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method, + java_channel.obj(), message_array.obj(), responseId); + } else { + env->CallVoidMethod(java_object.obj(), g_handle_platform_message_method, + java_channel.obj(), nullptr, responseId); + } + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::FlutterViewHandlePlatformMessageResponse( + int responseId, + std::unique_ptr data) { + // We are on the platform thread. Attempt to get the strong reference to + // the Java object. + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + // The Java object was collected before this message response got to + // it. Drop the response on the floor. + return; + } + if (data == nullptr) { // Empty response. + env->CallVoidMethod(java_object.obj(), + g_handle_platform_message_response_method, responseId, + nullptr); + } else { + // Convert the vector to a Java byte array. + fml::jni::ScopedJavaLocalRef data_array( + env, env->NewByteArray(data->GetSize())); + env->SetByteArrayRegion(data_array.obj(), 0, data->GetSize(), + reinterpret_cast(data->GetMapping())); + + env->CallVoidMethod(java_object.obj(), + g_handle_platform_message_response_method, responseId, + data_array.obj()); + } + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::FlutterViewUpdateSemantics( + std::vector buffer, + std::vector strings) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + fml::jni::ScopedJavaLocalRef direct_buffer( + env, env->NewDirectByteBuffer(buffer.data(), buffer.size())); + fml::jni::ScopedJavaLocalRef jstrings = + fml::jni::VectorToStringArray(env, strings); + + env->CallVoidMethod(java_object.obj(), g_update_semantics_method, + direct_buffer.obj(), jstrings.obj()); + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::FlutterViewUpdateCustomAccessibilityActions( + std::vector actions_buffer, + std::vector strings) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + fml::jni::ScopedJavaLocalRef direct_actions_buffer( + env, + env->NewDirectByteBuffer(actions_buffer.data(), actions_buffer.size())); + + fml::jni::ScopedJavaLocalRef jstrings = + fml::jni::VectorToStringArray(env, strings); + + env->CallVoidMethod(java_object.obj(), + g_update_custom_accessibility_actions_method, + direct_actions_buffer.obj(), jstrings.obj()); + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::FlutterViewOnFirstFrame() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + env->CallVoidMethod(java_object.obj(), g_on_first_frame_method); + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::FlutterViewOnPreEngineRestart() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + env->CallVoidMethod(java_object.obj(), g_on_engine_restart_method); + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::SurfaceTextureAttachToGLContext( + JavaWeakGlobalRef surface_texture, + int textureId) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + fml::jni::ScopedJavaLocalRef surface_texture_local_ref = + surface_texture.get(env); + if (surface_texture_local_ref.is_null()) { + return; + } + + env->CallVoidMethod(surface_texture_local_ref.obj(), + g_attach_to_gl_context_method, textureId); + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::SurfaceTextureUpdateTexImage( + JavaWeakGlobalRef surface_texture) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + fml::jni::ScopedJavaLocalRef surface_texture_local_ref = + surface_texture.get(env); + if (surface_texture_local_ref.is_null()) { + return; + } + + env->CallVoidMethod(surface_texture_local_ref.obj(), + g_update_tex_image_method); + + FML_CHECK(CheckException(env)); +} + +// The bounds we set for the canvas are post composition. +// To fill the canvas we need to ensure that the transformation matrix +// on the `SurfaceTexture` will be scaled to fill. We rescale and preseve +// the scaled aspect ratio. +SkSize ScaleToFill(float scaleX, float scaleY) { + const double epsilon = std::numeric_limits::epsilon(); + // scaleY is negative. + const double minScale = fmin(scaleX, fabs(scaleY)); + const double rescale = 1.0f / (minScale + epsilon); + return SkSize::Make(scaleX * rescale, scaleY * rescale); +} + +void PlatformViewAndroidJNIImpl::SurfaceTextureGetTransformMatrix( + JavaWeakGlobalRef surface_texture, + SkMatrix& transform) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + fml::jni::ScopedJavaLocalRef surface_texture_local_ref = + surface_texture.get(env); + if (surface_texture_local_ref.is_null()) { + return; + } + + fml::jni::ScopedJavaLocalRef transformMatrix( + env, env->NewFloatArray(16)); + + env->CallVoidMethod(surface_texture_local_ref.obj(), + g_get_transform_matrix_method, transformMatrix.obj()); + FML_CHECK(CheckException(env)); + + float* m = env->GetFloatArrayElements(transformMatrix.obj(), nullptr); + float scaleX = m[0], scaleY = m[5]; + const SkSize scaled = ScaleToFill(scaleX, scaleY); + SkScalar matrix3[] = { + scaled.fWidth, m[1], m[2], // + m[4], scaled.fHeight, m[6], // + m[8], m[9], m[10], // + }; + env->ReleaseFloatArrayElements(transformMatrix.obj(), m, JNI_ABORT); + transform.set9(matrix3); +} + +void PlatformViewAndroidJNIImpl::SurfaceTextureDetachFromGLContext( + JavaWeakGlobalRef surface_texture) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + fml::jni::ScopedJavaLocalRef surface_texture_local_ref = + surface_texture.get(env); + if (surface_texture_local_ref.is_null()) { + return; + } + + env->CallVoidMethod(surface_texture_local_ref.obj(), + g_detach_from_gl_context_method); + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::FlutterViewOnDisplayPlatformView(int view_id, + int x, + int y, + int width, + int height) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + env->CallVoidMethod(java_object.obj(), g_on_display_platform_view_method, + view_id, x, y, width, height); + + FML_CHECK(CheckException(env)); +} + +void PlatformViewAndroidJNIImpl::FlutterViewDisplayOverlaySurface( + int surface_id, + int x, + int y, + int width, + int height) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + auto java_object = java_object_.get(env); + if (java_object.is_null()) { + return; + } + + env->CallVoidMethod(java_object.obj(), g_on_display_overlay_surface_method, + surface_id, x, y, width, height); + + FML_CHECK(CheckException(env)); +} + } // namespace flutter diff --git a/shell/platform/android/platform_view_android_jni_impl.h b/shell/platform/android/platform_view_android_jni_impl.h new file mode 100644 index 0000000000000..db0441036b6f1 --- /dev/null +++ b/shell/platform/android/platform_view_android_jni_impl.h @@ -0,0 +1,74 @@ +// 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_PLATFORM_VIEW_ANDROID_JNI_IMPL_H_ +#define FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_IMPL_H_ + +#include "flutter/fml/platform/android/jni_weak_ref.h" +#include "flutter/shell/platform/android/jni/platform_view_android_jni.h" + +namespace flutter { + +//------------------------------------------------------------------------------ +/// @brief Concrete implementation of `PlatformViewAndroidJNI` that is +/// compiled with the Android toolchain. +/// +class PlatformViewAndroidJNIImpl final : public PlatformViewAndroidJNI { + public: + PlatformViewAndroidJNIImpl(fml::jni::JavaObjectWeakGlobalRef java_object); + + ~PlatformViewAndroidJNIImpl() override; + + void FlutterViewHandlePlatformMessage( + fml::RefPtr message, + int responseId) override; + + void FlutterViewHandlePlatformMessageResponse( + int responseId, + std::unique_ptr data) override; + + void FlutterViewUpdateSemantics(std::vector buffer, + std::vector strings) override; + + void FlutterViewUpdateCustomAccessibilityActions( + std::vector actions_buffer, + std::vector strings) override; + + void FlutterViewOnFirstFrame() override; + + void FlutterViewOnPreEngineRestart() override; + + void SurfaceTextureAttachToGLContext(JavaWeakGlobalRef surface_texture, + int textureId) override; + + void SurfaceTextureUpdateTexImage(JavaWeakGlobalRef surface_texture) override; + + void SurfaceTextureGetTransformMatrix(JavaWeakGlobalRef surface_texture, + SkMatrix& transform) override; + + void SurfaceTextureDetachFromGLContext( + JavaWeakGlobalRef surface_texture) override; + + void FlutterViewOnDisplayPlatformView(int view_id, + int x, + int y, + int width, + int height) override; + + void FlutterViewDisplayOverlaySurface(int surface_id, + int x, + int y, + int width, + int height) override; + + private: + // Reference to FlutterJNI object. + const fml::jni::JavaObjectWeakGlobalRef java_object_; + + FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewAndroidJNIImpl); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_VIEW_ANDROID_JNI_IMPL_H_