// 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/platform_view_android.h" #include #include #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/shell/common/shell_io_manager.h" #include "flutter/shell/gpu/gpu_surface_gl_delegate.h" #include "flutter/shell/platform/android/android_context_gl.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/android_surface_software.h" #include "flutter/shell/platform/android/external_view_embedder/external_view_embedder.h" #include "flutter/shell/platform/android/surface/android_surface.h" #if SHELL_ENABLE_VULKAN #include "flutter/shell/platform/android/android_surface_vulkan.h" #endif // SHELL_ENABLE_VULKAN #include "flutter/shell/platform/android/context/android_context.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/vsync_waiter_android.h" namespace flutter { AndroidSurfaceFactoryImpl::AndroidSurfaceFactoryImpl( std::shared_ptr context, std::shared_ptr jni_facade, std::weak_ptr external_view_embedder) : android_context_(context), jni_facade_(jni_facade), external_view_embedder_(external_view_embedder) {} AndroidSurfaceFactoryImpl::~AndroidSurfaceFactoryImpl() = default; std::unique_ptr AndroidSurfaceFactoryImpl::CreateSurface() { std::shared_ptr external_view_embedder = external_view_embedder_.lock(); FML_CHECK(external_view_embedder); switch (android_context_->RenderingApi()) { case AndroidRenderingAPI::kSoftware: return std::make_unique( android_context_, jni_facade_, external_view_embedder); case AndroidRenderingAPI::kOpenGLES: return std::make_unique(android_context_, jni_facade_, external_view_embedder); case AndroidRenderingAPI::kVulkan: #if SHELL_ENABLE_VULKAN return std::make_unique( android_context_, jni_facade_, external_view_embedder); #endif // SHELL_ENABLE_VULKAN default: return nullptr; } return nullptr; } PlatformViewAndroid::PlatformViewAndroid( PlatformView::Delegate& delegate, flutter::TaskRunners task_runners, std::shared_ptr jni_facade, bool use_software_rendering) : PlatformView(delegate, std::move(task_runners)), jni_facade_(jni_facade), platform_view_android_delegate_(jni_facade) { std::shared_ptr android_context; if (use_software_rendering) { android_context = std::make_shared(AndroidRenderingAPI::kSoftware); } else { #if SHELL_ENABLE_VULKAN android_context = std::make_shared(AndroidRenderingAPI::kVulkan); #else // SHELL_ENABLE_VULKAN android_context = std::make_shared( AndroidRenderingAPI::kOpenGLES, fml::MakeRefCounted()); #endif // SHELL_ENABLE_VULKAN } FML_CHECK(android_context && android_context->IsValid()) << "Could not create an Android context."; external_view_embedder_ = std::make_shared(android_context, jni_facade, surface_factory_); surface_factory_ = std::make_shared(android_context, jni_facade, external_view_embedder_); android_surface_ = surface_factory_->CreateSurface(); FML_CHECK(android_surface_ && android_surface_->IsValid()) << "Could not create an OpenGL, Vulkan or Software surface to setup " "rendering."; } PlatformViewAndroid::PlatformViewAndroid( PlatformView::Delegate& delegate, flutter::TaskRunners task_runners, std::shared_ptr jni_facade) : PlatformView(delegate, std::move(task_runners)), jni_facade_(jni_facade), platform_view_android_delegate_(jni_facade) {} PlatformViewAndroid::~PlatformViewAndroid() = default; void PlatformViewAndroid::NotifyCreated( fml::RefPtr native_window) { if (android_surface_) { InstallFirstFrameCallback(); fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( task_runners_.GetRasterTaskRunner(), [&latch, surface = android_surface_.get(), native_window = std::move(native_window)]() { surface->SetNativeWindow(native_window); latch.Signal(); }); latch.Wait(); } PlatformView::NotifyCreated(); } void PlatformViewAndroid::NotifySurfaceWindowChanged( fml::RefPtr native_window) { if (android_surface_) { fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( task_runners_.GetRasterTaskRunner(), [&latch, surface = android_surface_.get(), native_window = std::move(native_window)]() { surface->TeardownOnScreenContext(); surface->SetNativeWindow(native_window); latch.Signal(); }); latch.Wait(); } } void PlatformViewAndroid::NotifyDestroyed() { PlatformView::NotifyDestroyed(); if (android_surface_) { fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( task_runners_.GetRasterTaskRunner(), [&latch, surface = android_surface_.get()]() { surface->TeardownOnScreenContext(); latch.Signal(); }); latch.Wait(); } } void PlatformViewAndroid::NotifyChanged(const SkISize& size) { if (!android_surface_) { return; } fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( task_runners_.GetRasterTaskRunner(), // [&latch, surface = android_surface_.get(), size]() { surface->OnScreenSurfaceResize(size); latch.Signal(); }); latch.Wait(); } void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, std::string name, jobject java_message_data, jint java_message_position, jint response_id) { uint8_t* message_data = static_cast(env->GetDirectBufferAddress(java_message_data)); std::vector message = std::vector(message_data, message_data + java_message_position); fml::RefPtr response; if (response_id) { response = fml::MakeRefCounted( response_id, jni_facade_, task_runners_.GetPlatformTaskRunner()); } PlatformView::DispatchPlatformMessage( fml::MakeRefCounted( std::move(name), std::move(message), std::move(response))); } void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env, std::string name, jint response_id) { fml::RefPtr response; if (response_id) { response = fml::MakeRefCounted( response_id, jni_facade_, task_runners_.GetPlatformTaskRunner()); } PlatformView::DispatchPlatformMessage( fml::MakeRefCounted(std::move(name), std::move(response))); } void PlatformViewAndroid::InvokePlatformMessageResponseCallback( JNIEnv* env, jint response_id, jobject java_response_data, jint java_response_position) { if (!response_id) return; auto it = pending_responses_.find(response_id); if (it == pending_responses_.end()) return; uint8_t* response_data = static_cast(env->GetDirectBufferAddress(java_response_data)); std::vector response = std::vector( response_data, response_data + java_response_position); auto message_response = std::move(it->second); pending_responses_.erase(it); message_response->Complete( std::make_unique(std::move(response))); } void PlatformViewAndroid::InvokePlatformMessageEmptyResponseCallback( JNIEnv* env, jint response_id) { if (!response_id) return; auto it = pending_responses_.find(response_id); if (it == pending_responses_.end()) return; auto message_response = std::move(it->second); pending_responses_.erase(it); message_response->CompleteEmpty(); } // |PlatformView| void PlatformViewAndroid::HandlePlatformMessage( fml::RefPtr message) { int response_id = 0; if (auto response = message->response()) { response_id = next_response_id_++; pending_responses_[response_id] = response; } // This call can re-enter in InvokePlatformMessageXxxResponseCallback. jni_facade_->FlutterViewHandlePlatformMessage(message, response_id); message = nullptr; } // |PlatformView| void PlatformViewAndroid::OnPreEngineRestart() const { jni_facade_->FlutterViewOnPreEngineRestart(); } void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env, jint id, jint action, jobject args, jint args_position) { if (env->IsSameObject(args, NULL)) { std::vector args_vector; PlatformView::DispatchSemanticsAction( id, static_cast(action), args_vector); return; } uint8_t* args_data = static_cast(env->GetDirectBufferAddress(args)); std::vector args_vector = std::vector(args_data, args_data + args_position); PlatformView::DispatchSemanticsAction( id, static_cast(action), std::move(args_vector)); } // |PlatformView| void PlatformViewAndroid::UpdateSemantics( flutter::SemanticsNodeUpdates update, flutter::CustomAccessibilityActionUpdates actions) { platform_view_android_delegate_.UpdateSemantics(update, actions); } void PlatformViewAndroid::RegisterExternalTexture( int64_t texture_id, const fml::jni::JavaObjectWeakGlobalRef& surface_texture) { RegisterTexture(std::make_shared( texture_id, surface_texture, std::move(jni_facade_))); } // |PlatformView| std::unique_ptr PlatformViewAndroid::CreateVSyncWaiter() { return std::make_unique(task_runners_); } // |PlatformView| std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { if (!android_surface_) { return nullptr; } return android_surface_->CreateGPUSurface(); } // |PlatformView| sk_sp PlatformViewAndroid::CreateResourceContext() const { if (!android_surface_) { return nullptr; } sk_sp resource_context; if (android_surface_->ResourceContextMakeCurrent()) { // TODO(chinmaygarde): Currently, this code depends on the fact that only // the OpenGL surface will be able to make a resource context current. If // this changes, this assumption breaks. Handle the same. resource_context = ShellIOManager::CreateCompatibleResourceLoadingContext( GrBackend::kOpenGL_GrBackend, GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface()); } else { FML_DLOG(ERROR) << "Could not make the resource context current."; } return resource_context; } // |PlatformView| void PlatformViewAndroid::ReleaseResourceContext() const { if (android_surface_) { android_surface_->ResourceContextClearCurrent(); } } // |PlatformView| std::unique_ptr> PlatformViewAndroid::ComputePlatformResolvedLocales( const std::vector& supported_locale_data) { return jni_facade_->FlutterViewComputePlatformResolvedLocale( supported_locale_data); } void PlatformViewAndroid::InstallFirstFrameCallback() { // On Platform Task Runner. SetNextFrameCallback( [platform_view = GetWeakPtr(), platform_task_runner = task_runners_.GetPlatformTaskRunner()]() { // On GPU Task Runner. platform_task_runner->PostTask([platform_view]() { // Back on Platform Task Runner. if (platform_view) { reinterpret_cast(platform_view.get()) ->FireFirstFrameCallback(); } }); }); } void PlatformViewAndroid::FireFirstFrameCallback() { jni_facade_->FlutterViewOnFirstFrame(); } } // namespace flutter