diff --git a/BUILD.gn b/BUILD.gn index e84bece9519de..07095b6a708d5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -145,6 +145,11 @@ group("flutter") { "//flutter/third_party/txt:txt_unittests", ] + if (is_android) { + public_deps += + [ "//flutter/shell/platform/android:flutter_shell_native_unittests" ] + } + # The accessibility library only supports Mac and Windows at the moment. if (is_mac || is_win) { public_deps += diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b776f69941a82..ca1141917564a 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -770,6 +770,7 @@ FILE: ../../../flutter/shell/gpu/gpu_surface_vulkan_delegate.h FILE: ../../../flutter/shell/platform/android/AndroidManifest.xml FILE: ../../../flutter/shell/platform/android/android_context_gl.cc FILE: ../../../flutter/shell/platform/android/android_context_gl.h +FILE: ../../../flutter/shell/platform/android/android_context_gl_unittests.cc FILE: ../../../flutter/shell/platform/android/android_environment_gl.cc FILE: ../../../flutter/shell/platform/android/android_environment_gl.h FILE: ../../../flutter/shell/platform/android/android_exports.lst @@ -779,6 +780,7 @@ FILE: ../../../flutter/shell/platform/android/android_image_generator.cc FILE: ../../../flutter/shell/platform/android/android_image_generator.h FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc FILE: ../../../flutter/shell/platform/android/android_shell_holder.h +FILE: ../../../flutter/shell/platform/android/android_shell_holder_unittests.cc FILE: ../../../flutter/shell/platform/android/android_surface_gl.cc FILE: ../../../flutter/shell/platform/android/android_surface_gl.h FILE: ../../../flutter/shell/platform/android/android_surface_software.cc @@ -795,6 +797,7 @@ FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_poo FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool_unittests.cc FILE: ../../../flutter/shell/platform/android/flutter_main.cc FILE: ../../../flutter/shell/platform/android/flutter_main.h +FILE: ../../../flutter/shell/platform/android/flutter_shell_native_unittests.cc FILE: ../../../flutter/shell/platform/android/io/flutter/FlutterInjector.java FILE: ../../../flutter/shell/platform/android/io/flutter/Log.java FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivity.java diff --git a/shell/common/platform_view.h b/shell/common/platform_view.h index 1cbf73ce4abea..2b17b5066cc5c 100644 --- a/shell/common/platform_view.h +++ b/shell/common/platform_view.h @@ -8,9 +8,9 @@ #include #include -#include "flow/embedded_views.h" #include "flutter/common/graphics/texture.h" #include "flutter/common/task_runners.h" +#include "flutter/flow/embedded_views.h" #include "flutter/flow/surface.h" #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 6d76a91c87573..2780a734ef590 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -35,10 +35,30 @@ source_set("image_generator") { ] } -shared_library("flutter_shell_native") { - visibility = [ ":*" ] +executable("flutter_shell_native_unittests") { + visibility = [ "*" ] + testonly = true + sources = [ + "android_context_gl_unittests.cc", + "android_shell_holder_unittests.cc", + "flutter_shell_native_unittests.cc", + ] + public_configs = [ "//flutter:config" ] + deps = [ + ":flutter_shell_native_src", + "//third_party/googletest:gmock", + "//third_party/googletest:gtest", + ] +} +shared_library("flutter_shell_native") { output_name = "flutter" + deps = [ ":flutter_shell_native_src" ] + ldflags = [ "-Wl,--version-script=" + rebase_path("android_exports.lst") ] +} + +source_set("flutter_shell_native_src") { + visibility = [ ":*" ] sources = [ "$root_build_dir/flutter_icu/icudtl.o", @@ -69,7 +89,7 @@ shared_library("flutter_shell_native") { "vsync_waiter_android.h", ] - deps = [ + public_deps = [ ":android_gpu_configuration", ":icudtl_object", ":image_generator", @@ -100,8 +120,6 @@ shared_library("flutter_shell_native") { "EGL", "GLESv2", ] - - ldflags = [ "-Wl,--version-script=" + rebase_path("android_exports.lst") ] } action("gen_android_build_config_java") { diff --git a/shell/platform/android/android_context_gl.cc b/shell/platform/android/android_context_gl.cc index ee056925d05a4..1d0f83cafa7e7 100644 --- a/shell/platform/android/android_context_gl.cc +++ b/shell/platform/android/android_context_gl.cc @@ -204,14 +204,18 @@ AndroidContextGL::~AndroidContextGL() { std::unique_ptr AndroidContextGL::CreateOnscreenSurface( fml::RefPtr window) const { - EGLDisplay display = environment_->Display(); + if (window->IsFakeWindow()) { + return CreatePbufferSurface(); + } else { + EGLDisplay display = environment_->Display(); - const EGLint attribs[] = {EGL_NONE}; + const EGLint attribs[] = {EGL_NONE}; - EGLSurface surface = eglCreateWindowSurface( - display, config_, reinterpret_cast(window->handle()), - attribs); - return std::make_unique(surface, display, context_); + EGLSurface surface = eglCreateWindowSurface( + display, config_, + reinterpret_cast(window->handle()), attribs); + return std::make_unique(surface, display, context_); + } } std::unique_ptr AndroidContextGL::CreateOffscreenSurface() diff --git a/shell/platform/android/android_context_gl_unittests.cc b/shell/platform/android/android_context_gl_unittests.cc new file mode 100644 index 0000000000000..f31b023643c9c --- /dev/null +++ b/shell/platform/android/android_context_gl_unittests.cc @@ -0,0 +1,11 @@ +#include +#include "flutter/shell/platform/android/android_context_gl.h" +#include "flutter/shell/platform/android/android_environment_gl.h" +#include "gtest/gtest.h" + +TEST(AndroidContextGl, Create) { + auto environment = fml::MakeRefCounted(); + auto context = std::make_unique( + flutter::AndroidRenderingAPI::kOpenGLES, environment); + EXPECT_NE(context.get(), nullptr); +} diff --git a/shell/platform/android/android_shell_holder_unittests.cc b/shell/platform/android/android_shell_holder_unittests.cc new file mode 100644 index 0000000000000..eca2eed8bc067 --- /dev/null +++ b/shell/platform/android/android_shell_holder_unittests.cc @@ -0,0 +1,70 @@ +#include +#include "flutter/shell/platform/android/android_shell_holder.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { +namespace { +class MockPlatformViewAndroidJNI : public PlatformViewAndroidJNI { + MOCK_METHOD2(FlutterViewHandlePlatformMessage, + void(std::unique_ptr message, + int responseId)); + MOCK_METHOD2(FlutterViewHandlePlatformMessageResponse, + void(int responseId, std::unique_ptr data)); + MOCK_METHOD3(FlutterViewUpdateSemantics, + void(std::vector buffer, + std::vector strings, + std::vector> string_attribute_args)); + MOCK_METHOD2(FlutterViewUpdateCustomAccessibilityActions, + void(std::vector actions_buffer, + std::vector strings)); + MOCK_METHOD0(FlutterViewOnFirstFrame, void()); + MOCK_METHOD0(FlutterViewOnPreEngineRestart, void()); + MOCK_METHOD2(SurfaceTextureAttachToGLContext, + void(JavaLocalRef surface_texture, int textureId)); + MOCK_METHOD1(SurfaceTextureUpdateTexImage, + void(JavaLocalRef surface_texture)); + MOCK_METHOD2(SurfaceTextureGetTransformMatrix, + void(JavaLocalRef surface_texture, SkMatrix& transform)); + MOCK_METHOD1(SurfaceTextureDetachFromGLContext, + void(JavaLocalRef surface_texture)); + MOCK_METHOD8(FlutterViewOnDisplayPlatformView, + void(int view_id, + int x, + int y, + int width, + int height, + int viewWidth, + int viewHeight, + MutatorsStack mutators_stack)); + MOCK_METHOD5(FlutterViewDisplayOverlaySurface, + void(int surface_id, int x, int y, int width, int height)); + MOCK_METHOD0(FlutterViewBeginFrame, void()); + MOCK_METHOD0(FlutterViewEndFrame, void()); + MOCK_METHOD0(FlutterViewCreateOverlaySurface, + std::unique_ptr()); + MOCK_METHOD0(FlutterViewDestroyOverlaySurfaces, void()); + MOCK_METHOD1(FlutterViewComputePlatformResolvedLocale, + std::unique_ptr>( + std::vector supported_locales_data)); + MOCK_METHOD0(GetDisplayRefreshRate, double()); + MOCK_METHOD1(RequestDartDeferredLibrary, bool(int loading_unit_id)); +}; +} // namespace + +TEST(AndroidShellHolder, Create) { + Settings settings; + settings.enable_software_rendering = false; + auto jni = std::make_shared(); + auto holder = std::make_unique( + settings, jni, /*is_background_view=*/false); + EXPECT_NE(holder.get(), nullptr); + EXPECT_TRUE(holder->IsValid()); + EXPECT_NE(holder->GetPlatformView().get(), nullptr); + auto window = + fml::MakeRefCounted(nullptr, /*is_offscreen=*/true); + holder->GetPlatformView()->NotifyCreated(window); +} +} // namespace testing +} // namespace flutter diff --git a/shell/platform/android/flutter_shell_native_unittests.cc b/shell/platform/android/flutter_shell_native_unittests.cc new file mode 100644 index 0000000000000..fbebc29e38923 --- /dev/null +++ b/shell/platform/android/flutter_shell_native_unittests.cc @@ -0,0 +1,6 @@ +#include "gtest/gtest.h" + +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/shell/platform/android/surface/android_native_window.cc b/shell/platform/android/surface/android_native_window.cc index e701b986f48e9..5e4ebef7840b5 100644 --- a/shell/platform/android/surface/android_native_window.cc +++ b/shell/platform/android/surface/android_native_window.cc @@ -6,7 +6,11 @@ namespace flutter { -AndroidNativeWindow::AndroidNativeWindow(Handle window) : window_(window) {} +AndroidNativeWindow::AndroidNativeWindow(Handle window, bool is_fake_window) + : window_(window), is_fake_window_(is_fake_window) {} + +AndroidNativeWindow::AndroidNativeWindow(Handle window) + : AndroidNativeWindow(window, /*is_fake_window=*/false) {} AndroidNativeWindow::~AndroidNativeWindow() { if (window_ != nullptr) { diff --git a/shell/platform/android/surface/android_native_window.h b/shell/platform/android/surface/android_native_window.h index e2f385303403e..ac684b955eb4b 100644 --- a/shell/platform/android/surface/android_native_window.h +++ b/shell/platform/android/surface/android_native_window.h @@ -32,13 +32,20 @@ class AndroidNativeWindow SkISize GetSize() const; + /// Returns true when this AndroidNativeWindow is not backed by a real window + /// (used for testing). + bool IsFakeWindow() const { return is_fake_window_; } + private: Handle window_; + const bool is_fake_window_; /// Creates a native window with the given handle. Handle ownership is assumed /// by this instance of the native window. explicit AndroidNativeWindow(Handle window); + explicit AndroidNativeWindow(Handle window, bool is_fake_window); + ~AndroidNativeWindow(); FML_FRIEND_MAKE_REF_COUNTED(AndroidNativeWindow); diff --git a/testing/run_tests.py b/testing/run_tests.py index f8916dfd93087..3d1fc40bd74ba 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -351,6 +351,14 @@ def RunJavaTests(filter, android_variant='android_debug_unopt'): RunCmd(command, cwd=test_runner_dir, env=env) +def RunAndroidTests(android_variant='android_debug_unopt'): + test_runner_name = 'flutter_shell_native_unittests' + tests_path = os.path.join(out_dir, android_variant, test_runner_name) + remote_path = '/data/local/tmp' + remote_tests_path = os.path.join(remote_path, test_runner_name) + RunCmd(['adb', 'push', tests_path, remote_path], cwd=buildroot_dir) + RunCmd(['adb', 'shell', remote_tests_path]) + def RunObjcTests(ios_variant='ios_debug_sim_unopt', test_filter=None): """Runs Objective-C XCTest unit tests for the iOS embedding""" AssertExpectedXcodeVersion() @@ -592,6 +600,10 @@ def main(): java_filter = None RunJavaTests(java_filter, args.android_variant) + if 'android' in types: + assert not IsWindows(), "Android engine files can't be compiled on Windows." + RunAndroidTests(args.android_variant) + if 'objc' in types: assert IsMac(), "iOS embedding tests can only be run on macOS." RunObjcTests(args.ios_variant, args.objc_filter)