From b0d80cc091ce8eb69b2bbd6543263a15e32e7678 Mon Sep 17 00:00:00 2001 From: David Worsham Date: Fri, 19 Aug 2022 17:58:53 -0700 Subject: [PATCH] [fuchsia] Migrate integration test to CFv2 (flutter/engine#35318) --- .../ci/licenses_golden/licenses_flutter | 12 - .../shell/platform/fuchsia/flutter/BUILD.gn | 30 +- .../flutter/integration_flutter_tests/OWNERS | 5 - .../embedder/BUILD.gn | 67 -- .../embedder/README.md | 173 ----- .../embedder/child-view2/BUILD.gn | 38 -- .../embedder/child-view2/meta/child-view2.cmx | 13 - .../embedder/flutter-embedder-test2.cc | 218 ------- .../embedder/flutter-embedder-test2.h | 234 ------- .../embedder/meta/flutter-embedder-test2.cmx | 25 - .../embedder/parent-view2/BUILD.gn | 46 -- .../parent-view2/meta/parent-view2.cmx | 14 - .../src/lib/ui/base_view/BUILD.gn | 30 - .../src/lib/ui/base_view/base_view.cc | 240 ------- .../src/lib/ui/base_view/base_view.h | 210 ------ .../lib/ui/base_view/embedded_view_utils.cc | 48 -- .../lib/ui/base_view/embedded_view_utils.h | 58 -- .../src/lib/ui/base_view/math.h | 92 --- .../src/ui/testing/views/BUILD.gn | 24 - .../src/ui/testing/views/embedder_view.cc | 88 --- .../src/ui/testing/views/embedder_view.h | 59 -- .../integration}/BUILD.gn | 6 +- .../flutter/tests/integration/README.md | 84 +++ .../tests/integration/embedder/BUILD.gn | 65 ++ .../integration/embedder/child-view/BUILD.gn | 26 + .../embedder/child-view/lib/child_view.dart} | 16 +- .../embedder/child-view/meta/child-view.cml | 21 + .../embedder/child-view}/pubspec.yaml | 0 .../integration/embedder}/color.cc | 3 +- .../integration/embedder}/color.h | 0 .../embedder/flutter-embedder-test.cc | 602 ++++++++++++++++++ .../embedder/meta/flutter-embedder-test.cml | 27 + .../embedder/meta/gtest_runner.shard.cml | 14 + .../integration/embedder/parent-view/BUILD.gn | 36 ++ .../parent-view/lib/parent_view.dart} | 151 +++-- .../embedder/parent-view/meta/parent-view.cml | 33 + .../embedder/parent-view}/pubspec.yaml | 0 .../flutter/testing/fuchsia/test_suites.yaml | 14 +- .../flutter/tools/fuchsia/fuchsia_archive.gni | 89 +-- 39 files changed, 1103 insertions(+), 1808 deletions(-) delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/OWNERS delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/BUILD.gn delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/README.md delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/BUILD.gn delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/BUILD.gn delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/BUILD.gn delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/BUILD.gn delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.cc delete mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.h rename engine/src/flutter/shell/platform/fuchsia/flutter/{integration_flutter_tests => tests/integration}/BUILD.gn (73%) create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/README.md create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/BUILD.gn rename engine/src/flutter/shell/platform/fuchsia/flutter/{integration_flutter_tests/embedder/child-view2/child_view2.dart => tests/integration/embedder/child-view/lib/child_view.dart} (85%) create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml rename engine/src/flutter/shell/platform/fuchsia/flutter/{integration_flutter_tests/embedder/child-view2 => tests/integration/embedder/child-view}/pubspec.yaml (100%) rename engine/src/flutter/shell/platform/fuchsia/flutter/{integration_flutter_tests/fuchsia_testing/src/ui/testing/views => tests/integration/embedder}/color.cc (98%) rename engine/src/flutter/shell/platform/fuchsia/flutter/{integration_flutter_tests/fuchsia_testing/src/ui/testing/views => tests/integration/embedder}/color.h (100%) create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/BUILD.gn rename engine/src/flutter/shell/platform/fuchsia/flutter/{integration_flutter_tests/embedder/parent-view2/parent_view2.dart => tests/integration/embedder/parent-view/lib/parent_view.dart} (71%) create mode 100644 engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml rename engine/src/flutter/shell/platform/fuchsia/flutter/{integration_flutter_tests/embedder/parent-view2 => tests/integration/embedder/parent-view}/pubspec.yaml (100%) diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index ff50b5a9d01..c78b93d5c00 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -2129,18 +2129,6 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/gfx_platform_view.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/gfx_platform_view.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/gfx_session_connection.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/gfx_session_connection.h -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child_view2.dart -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/kernel/extract_far.dart diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/BUILD.gn index 0680f429130..01a1f2e3ce1 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/BUILD.gn +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/BUILD.gn @@ -457,6 +457,34 @@ jit_runner("flutter_jit_product_runner") { product = true } +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +aot_runner("oot_flutter_aot_runner") { + product = false +} + +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +aot_runner("oot_flutter_aot_product_runner") { + product = true +} + +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +jit_runner("oot_flutter_jit_runner") { + product = false +} + +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +jit_runner("oot_flutter_jit_product_runner") { + product = true +} + test_fixtures("flutter_runner_fixtures") { fixtures = [] } @@ -885,7 +913,7 @@ if (enable_unittests) { ":testing_tests", ":txt_tests", ":ui_tests", - "integration_flutter_tests", + "tests/integration", ] } } diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/OWNERS b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/OWNERS deleted file mode 100644 index aa90637fa8f..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -dworsham@google.com -sanjayc@google.com -richkadel@google.com - -# COMPONENT: FlutteronFuchsia diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/BUILD.gn deleted file mode 100644 index bba0da5c26d..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/BUILD.gn +++ /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. - -assert(is_fuchsia) - -import("//build/fuchsia/sdk.gni") -import("//flutter/tools/fuchsia/fuchsia_archive.gni") - -group("tests") { - testonly = true - deps = [ - ":flutter-embedder-test2", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2", - ] -} - -executable("flutter-embedder-test2-bin") { - testonly = true - - output_name = "flutter-embedder-test2" - - sources = [ - "flutter-embedder-test2.cc", - "flutter-embedder-test2.h", - ] - - # This is needed for //third_party/googletest for linking zircon symbols. - libs = [ "$fuchsia_sdk_path/arch/$target_cpu/sysroot/lib/libzircon.so" ] - - include_dirs = [ "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing" ] - - public_deps = [ "//third_party/googletest:gtest" ] - - deps = [ - "$fuchsia_sdk_root/fidl:fuchsia.sys", - "$fuchsia_sdk_root/fidl:fuchsia.ui.app", - "$fuchsia_sdk_root/fidl:fuchsia.ui.input", - "$fuchsia_sdk_root/fidl:fuchsia.ui.lifecycle", - "$fuchsia_sdk_root/fidl:fuchsia.ui.policy", - "$fuchsia_sdk_root/fidl:fuchsia.ui.scenic", - "$fuchsia_sdk_root/pkg:async-loop-cpp", - "$fuchsia_sdk_root/pkg:async-loop-default", - "$fuchsia_sdk_root/pkg:fit", - "$fuchsia_sdk_root/pkg:scenic_cpp", - "$fuchsia_sdk_root/pkg:sys_cpp", - "$fuchsia_sdk_root/pkg:sys_cpp_testing", - "$fuchsia_sdk_root/pkg:zx", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views", - "//third_party/dart/runtime:libdart_jit", - "//third_party/googletest:gtest_main", - ] -} - -fuchsia_test_archive("flutter-embedder-test2") { - deps = [ - ":flutter-embedder-test2-bin", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2:package", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2:package", - ] - - binary = "$target_name" - - cmx_file = rebase_path("meta/$target_name.cmx") -} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/README.md b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/README.md deleted file mode 100644 index 6b5190b9af8..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# `flutter scenic embedder tests` - -## Configure and build fuchsia - -For tests that require scenic, for example, run `fx set` with the required -targets; for example: - -```shell -$ cd "$FUCHSIA_DIR" -$ fx set core.x64 \ - --with //src/ui/scenic \ - --with //src/ui/bin/root_presenter \ - --with //src/ui/bin/hardware_display_controller_provider -$ fx build -``` - -Note 1: You could use `--with-base` here, instead of `--with`, but if so, you -would also need to add `--with-base //garnet/bin/run_test_component`. More on -this below, under [Start the package servers](#start-the-package-servers). - -Note 2: The `fx set` flags, above, offer a minimized fuchsia platform -configuration to successfully execute the test, but some optional services may -be missing. Be aware that the Fuchsia system logs may include multiple -occurrences `WARNING: error resolving ...` messages, such as the following, -which can be ignored: - -``` -[pkg-resolver] WARNING: error resolving fuchsia-pkg://fuchsia.com/fonts/0 ... -[pkg-resolver] WARNING: error resolving fuchsia-pkg://fuchsia.com/ime_service/0 ... -[pkg-resolver] WARNING: error resolving fuchsia-pkg://fuchsia.com/intl_property_manager/0 ... -``` - -## Restart and reboot your device - -_(Optional)_ If developing with the emulator, launch (or shutdown and relaunch) -the emulator. - -```shell -fx vdl start -N -``` - -NOTE: Do _not_ run the default package server. The instructions below describe -how to launch a flutter-specific package server. - -Or if you've rebuilt fuchsia for a device that is already running a version of -fuchsia, you may be able to reboot without restarting the device: - -```shell -$ fx reboot -r -``` - -If you are building a device that launches the UI at startup, you will likely -need to kill Scenic before running the test. - -```shell -$ fx shell killall scenic.cmx -``` - -## Build the test - -You can specify the test's package target to build only the test package, with -its dependencies. This will also build the required runner. - -```shell -$ cd "$FLUTTER_ENGINE_DIR/src" -$ ./flutter/tools/gn --fuchsia \ - # for example: --goma --fuchsia-cpu=x64 --runtime-mode=debug -$ ninja -C out/fuchsia_debug_x64 \ - flutter/shell/platform/fuchsia/flutter/integration_flutter_tests -``` - -## Publish the test packages to the Fuchsia package server - -The tests currently specify the Fuchsia package server's standard domain, -`fuchsia.com`, as the server to use to resolve (locate and load) the test -packages. So, before running the test, the most recently built `.far` files -need to be published to the Fuchsia package repo: - -```shell -$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ - -f "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64/flutter-embedder-test2-0.far -$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ - -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name parent-view2.far) -$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ - -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name child-view2.far) -``` - -## Run the test (using the package server at `fuchsia.com`) - -```shell -$ fx test flutter-embedder-test2 -``` - -## Make a change and re-run the test - -If, for example, you only make a change to the Dart code in `parent-view2`, you -can rebuild only the parent-view2 package target, republish it, and then re-run -the test, with: - -```shell -$ ninja -C out/fuchsia_debug_x64 \ - flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2:package -$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ - -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name parent-view2.far) -$ fx test flutter-embedder-test2 -``` - -From here, you can modify the Flutter test, rebuild flutter, and usually rerun -the test without rebooting, by repeating the commands above. - -The embedder tests must be run on a product without a graphical base shell, -such as `core` because it starts and stops Scenic. - -## (Alternative) Serving flutter packages from a custom package server - -If you want to use a custom package server, you will need to edit these sources: - - * `//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc` - * `//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart` - -Search for the component URLs with `fuchsia.com`, and change it to `engine`, -which is the domain currently registered with the custom package server in -`//tools/fuchsia/devshell/serve.sh`. - -WARNING: Be careful not to check in that change because CI requires using the -`fuchsia.com` domain/package server. - -The default fuchsia package server (launched via `fx serve`) is normally -required, unless all of your test's package dependencies are included in the -fuchsia system image. You can force additional packages into the system image -with `fx set ... --with-base ` (instead of using `--with`). For -example, in the `fx set` command above, using, `--with-base scenic`, and so on. -Note, however, that the default `core.x64` configuration bundles the test -runner as if it was included via -`--with //garnet/bin/run_test_component`, so to include the test runner in the -system image requires adding that package as well, via `--with-base`, instead. - -In order to serve fuchsia package dependencies (like `scenic`, `root_presenter`, -and `hardware-display-controller-provider`), without forcing them into the -system image, you will need to run the fuchsia default package server, via `fx -serve`. - -The `flutter/engine` packages (tests and flutter runners, for dart-based tests) -are served from a separate package server. The `flutter/engine` repo's -`serve.sh` script launches this secondary package server, and configures -package URL rewrite rules to redirect fuchsia's requests for flutter- and -dart-runner packages from `fuchsia.com` to flutter's package server instead. - -**IMPORTANT:** _The flutter package server must be launched **after** the -default package server, because both `fx serve` and flutter's `serve.sh` set -package URL rewrite rules, and only the last one wins._ - -Launch each package server in a separate window or shell: - -```shell -$ cd "${FUCHSIA_DIR}" -$ fx serve -``` - -From the flutter engine `src` directory, run the following script to launch the -`engine` package server, to serve the flutter runner and test components. - -```shell -$ flutter/tools/fuchsia/devshell/serve.sh --out out/fuchsia_debug_x64 --only-serve-runners -``` - -## Run the test, using `engine` as the package server domain - -```shell -$ fx test flutter-embedder-test2 -``` - -You can recompile and run the test without needing to re-publish the `.far`. diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/BUILD.gn deleted file mode 100644 index 93e83638693..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/BUILD.gn +++ /dev/null @@ -1,38 +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. - -import("//build/fuchsia/sdk.gni") -import("//flutter/tools/fuchsia/dart/dart_library.gni") -import("//flutter/tools/fuchsia/flutter/flutter_component.gni") -import("//flutter/tools/fuchsia/gn-sdk/package.gni") - -dart_library("child-view2_dart_library") { - package_name = "child-view2" - - source_dir = "." - sources = [ "child_view2.dart" ] - - deps = [] -} - -flutter_component("child-view2_flutter_component") { - main_package = "child-view2" - component_name = "child-view2" - main_dart = "child_view2.dart" - manifest = rebase_path("meta/child-view2.cmx") - deps = [ ":child-view2_dart_library" ] -} - -# TODO(richkadel): The target name is set differently compared to fuchsia.git's flutter_app(). -# Unlike in fuchsia.git's version of fuchsia_component, the Fuchsia GN SDK -# version passes the component name to fuchsia_component via it's target_name only. -# GN SDK's fuchsia_component doesn't have a `component_name` argument! So I'm forced to set -# the component name via "target_name". This is a problem in fuchsia_package, which uses -# the target_name to name the fuchsia_pm_tool target, creating duplicate target IDs! -# So I have to change the fuchsia_package name to something that is NOT the component name, -# and then set the package_name (which fuchsia_package does support). -fuchsia_package("package") { - package_name = "child-view2" - deps = [ ":child-view2_flutter_component" ] -} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx deleted file mode 100644 index 2157ca21909..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx +++ /dev/null @@ -1,13 +0,0 @@ -{ - "program": { - "data": "data/child-view2" - }, - "sandbox": { - "services": [ - "fuchsia.fonts.Provider", - "fuchsia.sys.Environment", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc deleted file mode 100644 index 63a5cd197ab..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc +++ /dev/null @@ -1,218 +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. - -#include "flutter-embedder-test2.h" - -namespace flutter_embedder_test2 { - -// TODO(richkadel): To run the test serving the runner and test packages from -// the flutter/engine package server (via -// `//flutter/tools/fuchsia/devshell/serve.sh`), change `fuchsia.com` to -// `engine`. -constexpr char kParentViewUrl[] = - "fuchsia-pkg://fuchsia.com/parent-view2#meta/parent-view2.cmx"; - -constexpr scenic::Color kParentBackgroundColor = {0x00, 0x00, 0xFF, - 0xFF}; // Blue -constexpr scenic::Color kParentTappedColor = {0x00, 0x00, 0x00, 0xFF}; // Black -constexpr scenic::Color kChildBackgroundColor = {0xFF, 0x00, 0xFF, - 0xFF}; // Pink -constexpr scenic::Color kChildTappedColor = {0xFF, 0xFF, 0x00, 0xFF}; // Yellow - -// TODO(fxb/94000): The new flutter renderer draws overlays as a single, large -// layer. Some parts of this layer are fully transparent, so we want the -// compositor to treat the layer as transparent and blend it with the contents -// below. -// -// The gfx Scenic API only provides one way to mark this layer as transparent -// which is to set an opacity < 1.0 for the entire layer. In practice, we use -// 0.9961 (254 / 255) as an opacity value to force transparency. Unfortunately -// this causes the overlay to blend very slightly and it looks wrong. -// -// Flatland allows marking a layer as transparent while still using a 1.0 -// opacity value when blending, so migrating flutter to Flatland will fix this -// issue. For now we just hard-code the broken, blended values. -constexpr scenic::Color kOverlayBackgroundColor1 = { - 0x00, 0xFF, 0x0E, 0xFF}; // Green, blended with blue (FEMU local) -constexpr scenic::Color kOverlayBackgroundColor2 = { - 0x0E, 0xFF, 0x0E, 0xFF}; // Green, blended with pink (FEMU local) -constexpr scenic::Color kOverlayBackgroundColor3 = { - 0x00, 0xFF, 0x0D, 0xFF}; // Green, blended with blue (AEMU infra) -constexpr scenic::Color kOverlayBackgroundColor4 = { - 0x0D, 0xFF, 0x0D, 0xFF}; // Green, blended with pink (AEMU infra) -constexpr scenic::Color kOverlayBackgroundColor5 = { - 0x00, 0xFE, 0x0D, 0xFF}; // Green, blended with blue (NUC) -constexpr scenic::Color kOverlayBackgroundColor6 = { - 0x0D, 0xFF, 0x00, 0xFF}; // Green, blended with pink (NUC) - -static size_t OverlayPixelCount(std::map& histogram) { - return histogram[kOverlayBackgroundColor1] + - histogram[kOverlayBackgroundColor2] + - histogram[kOverlayBackgroundColor3] + - histogram[kOverlayBackgroundColor4] + - histogram[kOverlayBackgroundColor5] + - histogram[kOverlayBackgroundColor6]; -} - -/// Defines a list of services that are injected into the test environment. -/// Unlike the injected-services in CMX which are injected per test package, -/// these are injected per test and result in a more hermetic test environment. -const std::vector> GetInjectedServices() { - std::vector> injected_services = {{ - {"fuchsia.accessibility.semantics.SemanticsManager", - "fuchsia-pkg://fuchsia.com/a11y-manager#meta/a11y-manager.cmx"}, - {"fuchsia.fonts.Provider", - "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx"}, - {"fuchsia.hardware.display.Provider", - "fuchsia-pkg://fuchsia.com/" - "fake-hardware-display-controller-provider#meta/hdcp.cmx"}, - {"fuchsia.intl.PropertyProvider", - "fuchsia-pkg://fuchsia.com/intl_property_manager#meta/" - "intl_property_manager.cmx"}, - {"fuchsia.netstack.Netstack", - "fuchsia-pkg://fuchsia.com/network-legacy-deprecated#meta/netstack.cmx"}, - {"fuchsia.posix.socket.Provider", - "fuchsia-pkg://fuchsia.com/network-legacy-deprecated#meta/netstack.cmx"}, - {"fuchsia.tracing.provider.Registry", - "fuchsia-pkg://fuchsia.com/trace_manager#meta/trace_manager.cmx"}, - {"fuchsia.ui.input.ImeService", - "fuchsia-pkg://fuchsia.com/text_manager#meta/text_manager.cmx"}, - {"fuchsia.ui.input.ImeVisibilityService", - "fuchsia-pkg://fuchsia.com/text_manager#meta/text_manager.cmx"}, - {"fuchsia.ui.scenic.Scenic", - "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx"}, - {"fuchsia.ui.pointerinjector.Registry", - "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx"}, // For - // root_presenter - // TODO(fxbug.dev/82655): Remove this after migrating to RealmBuilder. - {"fuchsia.ui.lifecycle.LifecycleController", - "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx"}, - {"fuchsia.ui.policy.Presenter", - "fuchsia-pkg://fuchsia.com/root_presenter#meta/root_presenter.cmx"}, - {"fuchsia.ui.input.InputDeviceRegistry", - "fuchsia-pkg://fuchsia.com/root_presenter#meta/root_presenter.cmx"}, - }}; - return injected_services; -} - -TEST_F(FlutterScenicEmbedderTests, Embedding) { - RunAppWithArgs(kParentViewUrl); - - // Take screenshot until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil( - kChildBackgroundColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent and child background colors, with parent color > child - // color. - EXPECT_GT(histogram[kParentBackgroundColor], 0u); - EXPECT_GT(histogram[kChildBackgroundColor], 0u); - EXPECT_GT(histogram[kParentBackgroundColor], - histogram[kChildBackgroundColor]); - - // Expect all corners to be the parent-view2 background color - EXPECT_EQ(kParentBackgroundColor, screenshot.ColorAtPixelXY(10, 10)); - EXPECT_EQ(kParentBackgroundColor, - screenshot.ColorAtPixelXY(screenshot.width() - 10, 0)); - EXPECT_EQ(kParentBackgroundColor, - screenshot.ColorAtPixelXY(0, screenshot.height() - 10)); - EXPECT_EQ(kParentBackgroundColor, - screenshot.ColorAtPixelXY(screenshot.width() - 10, - screenshot.height() - 10)); - })); -} - -TEST_F(FlutterScenicEmbedderTests, HittestEmbedding) { - RunAppWithArgs(kParentViewUrl); - - // Take screenshot until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); - - // Tap the center of child view2. - InjectInput(); - - // Take screenshot until we see the child-view2's tapped color. - ASSERT_TRUE(TakeScreenshotUntil( - kChildTappedColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent and child background colors, with parent color > child - // color. - EXPECT_GT(histogram[kParentBackgroundColor], 0u); - EXPECT_EQ(histogram[kChildBackgroundColor], 0u); - EXPECT_GT(histogram[kChildTappedColor], 0u); - EXPECT_GT(histogram[kParentBackgroundColor], - histogram[kChildTappedColor]); - })); -} - -TEST_F(FlutterScenicEmbedderTests, HittestDisabledEmbedding) { - RunAppWithArgs(kParentViewUrl, {"--no-hitTestable"}); - - // Take screenshots until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); - - // Tap the center of child view2. Since it's not hit-testable, the tap should - // go to the parent. - InjectInput(); - - // The parent-view2 should change color. - ASSERT_TRUE(TakeScreenshotUntil( - kParentTappedColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent and child background colors, with parent color > child - // color. - EXPECT_EQ(histogram[kParentBackgroundColor], 0u); - EXPECT_GT(histogram[kParentTappedColor], 0u); - EXPECT_GT(histogram[kChildBackgroundColor], 0u); - EXPECT_EQ(histogram[kChildTappedColor], 0u); - EXPECT_GT(histogram[kParentTappedColor], - histogram[kChildBackgroundColor]); - })); -} - -TEST_F(FlutterScenicEmbedderTests, EmbeddingWithOverlay) { - RunAppWithArgs(kParentViewUrl, {"--showOverlay"}); - - // Take screenshot until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil( - kChildBackgroundColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent, overlay and child background colors. - // With parent color > child color and overlay color > child color. - const size_t overlay_pixel_count = OverlayPixelCount(histogram); - EXPECT_GT(histogram[kParentBackgroundColor], 0u); - EXPECT_GT(overlay_pixel_count, 0u); - EXPECT_GT(histogram[kChildBackgroundColor], 0u); - EXPECT_GT(histogram[kParentBackgroundColor], - histogram[kChildBackgroundColor]); - EXPECT_GT(overlay_pixel_count, histogram[kChildBackgroundColor]); - })); -} - -TEST_F(FlutterScenicEmbedderTests, HittestEmbeddingWithOverlay) { - RunAppWithArgs(kParentViewUrl, {"--showOverlay"}); - - // Take screenshot until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); - - // Tap the center of child view2. - InjectInput(); - - // Take screenshot until we see the child-view2's tapped color. - ASSERT_TRUE(TakeScreenshotUntil( - kChildTappedColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent, overlay and child background colors. - // With parent color > child color and overlay color > child color. - const size_t overlay_pixel_count = OverlayPixelCount(histogram); - EXPECT_GT(histogram[kParentBackgroundColor], 0u); - EXPECT_GT(overlay_pixel_count, 0u); - EXPECT_EQ(histogram[kChildBackgroundColor], 0u); - EXPECT_GT(histogram[kChildTappedColor], 0u); - EXPECT_GT(histogram[kParentBackgroundColor], - histogram[kChildTappedColor]); - EXPECT_GT(overlay_pixel_count, histogram[kChildTappedColor]); - })); -} - -} // namespace flutter_embedder_test2 diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h deleted file mode 100644 index 1a8cbf54e4b..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h +++ /dev/null @@ -1,234 +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 SRC_UI_TESTS_INTEGRATION_FLUTTER_TESTS_EMBEDDER_flutter_embedder_test2_H_ -#define SRC_UI_TESTS_INTEGRATION_FLUTTER_TESTS_EMBEDDER_flutter_embedder_test2_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "flutter/fml/logging.h" - -#include - -#include "src/lib/ui/base_view/embedded_view_utils.h" -#include "src/ui/testing/views/color.h" -#include "src/ui/testing/views/embedder_view.h" - -namespace flutter_embedder_test2 { - -/// Defines a list of services that are injected into the test environment. -/// Unlike the injected-services in CMX which are injected per test package, -/// these are injected per test and result in a more hermetic test environment. -const std::vector> GetInjectedServices(); - -// Timeout when waiting on Scenic API calls like |GetDisplayInfo|. -constexpr zx::duration kCallTimeout = zx::sec(5); -// Timeout for Scenic's |TakeScreenshot| FIDL call. -constexpr zx::duration kScreenshotTimeout = zx::sec(10); -// Timeout to fail the test if it goes beyond this duration. -constexpr zx::duration kTestTimeout = zx::min(1); - -class FlutterScenicEmbedderTests : public sys::testing::TestWithEnvironment, - public ::testing::Test { - public: - // |testing::Test| - void SetUp() override { - Test::SetUp(); - - // Create test-specific launchable services. - auto services = TestWithEnvironment::CreateServices(); - for (const auto& service_info : GetInjectedServices()) { - zx_status_t status = services->AddServiceWithLaunchInfo( - {.url = service_info.second}, service_info.first); - FML_CHECK(status == ZX_OK) - << "Failed to add service " << service_info.first; - } - - environment_ = CreateNewEnclosingEnvironment( - "flutter-embedder-test2s", std::move(services), - {.inherit_parent_services = true}); - WaitForEnclosingEnvToStart(environment()); - - FML_VLOG(fml::LOG_INFO) << "Created test environment."; - - // Connects to scenic lifecycle controller in order to shutdown scenic at - // the end of the test. This ensures the correct ordering of shutdown under - // CFv1: first scenic, then the fake display controller. - // - // TODO(fxbug.dev/82655): Remove this after migrating to RealmBuilder. - environment_->ConnectToService( - scenic_lifecycle_controller_.NewRequest()); - - environment_->ConnectToService(scenic_.NewRequest()); - scenic_.set_error_handler([](zx_status_t status) { - FAIL() << "Lost connection to Scenic: " << zx_status_get_string(status); - }); - - // Post a "just in case" quit task, if the test hangs. - async::PostDelayedTask( - dispatcher(), - [] { - FML_LOG(FATAL) - << "\n\n>> Test did not complete in time, terminating. <<\n\n"; - }, - kTestTimeout); - } - - // |testing::Test| - void TearDown() override { - // Avoid spurious errors since we are about to kill scenic. - // - // TODO(fxbug.dev/82655): Remove this after migrating to RealmBuilder. - scenic_.set_error_handler(nullptr); - - zx_status_t terminate_status = scenic_lifecycle_controller_->Terminate(); - FML_CHECK(terminate_status == ZX_OK) - << "Failed to terminate Scenic with status: " - << zx_status_get_string(terminate_status); - } - - sys::testing::EnclosingEnvironment* environment() { - return environment_.get(); - } - - fuchsia::ui::views::ViewToken CreatePresentationViewToken() { - auto [view_token, view_holder_token] = scenic::ViewTokenPair::New(); - - auto presenter = - environment()->ConnectToService(); - presenter.set_error_handler([](zx_status_t status) { - FAIL() << "presenter: " << zx_status_get_string(status); - }); - presenter->PresentView(std::move(view_holder_token), nullptr); - - return std::move(view_token); - } - - void RunAppWithArgs(const std::string& component_url, - const std::vector& component_args = {}) { - scenic::EmbeddedViewInfo flutter_runner = - scenic::LaunchComponentAndCreateView(environment()->launcher_ptr(), - component_url, component_args); - flutter_runner.controller.events().OnTerminated = [](auto...) { FAIL(); }; - - // Present the view. - embedder_view_.emplace(scenic::ViewContext{ - .session_and_listener_request = - scenic::CreateScenicSessionPtrAndListenerRequest(scenic_.get()), - .view_token = CreatePresentationViewToken(), - }); - - // Embed the view. - bool is_rendering = false; - embedder_view_->EmbedView( - std::move(flutter_runner), - [&is_rendering](fuchsia::ui::gfx::ViewState view_state) { - is_rendering = view_state.is_rendering; - }); - RunLoopUntil([&is_rendering] { return is_rendering; }); - FML_LOG(INFO) << "Launched component: " << component_url; - } - - scenic::Screenshot TakeScreenshot() { - FML_LOG(INFO) << "Taking screenshot... "; - fuchsia::ui::scenic::ScreenshotData screenshot_out; - scenic_->TakeScreenshot( - [this, &screenshot_out](fuchsia::ui::scenic::ScreenshotData screenshot, - bool status) { - EXPECT_TRUE(status) << "Failed to take screenshot"; - screenshot_out = std::move(screenshot); - QuitLoop(); - }); - EXPECT_FALSE(RunLoopWithTimeout(kScreenshotTimeout)) - << "Timed out waiting for screenshot."; - FML_LOG(INFO) << "Screenshot captured."; - - return scenic::Screenshot(screenshot_out); - } - - bool TakeScreenshotUntil( - scenic::Color color, - fit::function)> - callback = nullptr, - zx::duration timeout = kTestTimeout) { - return RunLoopWithTimeoutOrUntil( - [this, &callback, &color] { - auto screenshot = TakeScreenshot(); - auto histogram = screenshot.Histogram(); - - bool color_found = histogram[color] > 0; - if (color_found && callback != nullptr) { - callback(std::move(screenshot), std::move(histogram)); - } - return color_found; - }, - timeout); - } - - // Inject directly into Root Presenter, using fuchsia.ui.input FIDLs. - void InjectInput() { - using fuchsia::ui::input::InputReport; - // Device parameters - auto parameters = fuchsia::ui::input::TouchscreenDescriptor::New(); - *parameters = {.x = {.range = {.min = -1000, .max = 1000}}, - .y = {.range = {.min = -1000, .max = 1000}}, - .max_finger_id = 10}; - - FML_LOG(INFO) << "Injecting input... "; - // Register it against Root Presenter. - fuchsia::ui::input::DeviceDescriptor device{.touchscreen = - std::move(parameters)}; - auto registry = - environment() - ->ConnectToService(); - fuchsia::ui::input::InputDevicePtr connection; - registry->RegisterDevice(std::move(device), connection.NewRequest()); - - { - // Inject one input report, then a conclusion (empty) report. - auto touch = fuchsia::ui::input::TouchscreenReport::New(); - *touch = { - .touches = {{.finger_id = 1, .x = 0, .y = 0}}}; // center of display - InputReport report{ - .event_time = static_cast(zx::clock::get_monotonic().get()), - .touchscreen = std::move(touch)}; - connection->DispatchReport(std::move(report)); - } - - { - auto touch = fuchsia::ui::input::TouchscreenReport::New(); - InputReport report{ - .event_time = static_cast(zx::clock::get_monotonic().get()), - .touchscreen = std::move(touch)}; - connection->DispatchReport(std::move(report)); - } - FML_LOG(INFO) << "Input dispatched."; - } - - private: - const std::unique_ptr component_context_; - std::unique_ptr environment_; - - fuchsia::ui::lifecycle::LifecycleControllerSyncPtr - scenic_lifecycle_controller_; - fuchsia::ui::scenic::ScenicPtr scenic_; - - // Wrapped in optional since the view is not created until the middle of SetUp - std::optional embedder_view_; -}; - -} // namespace flutter_embedder_test2 - -#endif // SRC_UI_TESTS_INTEGRATION_FLUTTER_TESTS_EMBEDDER_flutter_embedder_test2_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx deleted file mode 100644 index 0e21e6dc387..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx +++ /dev/null @@ -1,25 +0,0 @@ -{ - "facets": { - "fuchsia.test": { - "system-services": [ - "fuchsia.scheduler.ProfileProvider", - "fuchsia.sysmem.Allocator", - "fuchsia.vulkan.loader.Loader" - ] - } - }, - "program": { - "binary": "bin/app" - }, - "sandbox": { - "services": [ - "fuchsia.logger.LogSink", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.sys.Loader", - "fuchsia.sysmem.Allocator", - "fuchsia.tracing.provider.Registry", - "fuchsia.vulkan.loader.Loader" - ] - } -} \ No newline at end of file diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/BUILD.gn deleted file mode 100644 index 0b2ec390b39..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/BUILD.gn +++ /dev/null @@ -1,46 +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. - -import("//build/fuchsia/sdk.gni") -import("//flutter/tools/fuchsia/dart/dart_library.gni") -import("//flutter/tools/fuchsia/flutter/flutter_component.gni") -import("//flutter/tools/fuchsia/gn-sdk/package.gni") - -dart_library("parent-view2_dart_library") { - package_name = "parent-view2" - - source_dir = "." - sources = [ "parent_view2.dart" ] - - deps = [ - "//flutter/shell/platform/fuchsia/dart:args", - "//flutter/shell/platform/fuchsia/dart:vector_math", - "//flutter/tools/fuchsia/dart:fuchsia_services", - "//flutter/tools/fuchsia/dart:zircon", - "//flutter/tools/fuchsia/fidl:fuchsia.sys", - "//flutter/tools/fuchsia/fidl:fuchsia.ui.app", - "//flutter/tools/fuchsia/fidl:fuchsia.ui.views", - ] -} - -flutter_component("parent-view2_flutter_component") { - main_package = "parent-view2" - component_name = "parent-view2" - main_dart = "parent_view2.dart" - manifest = rebase_path("meta/parent-view2.cmx") - deps = [ ":parent-view2_dart_library" ] -} - -# TODO(richkadel): The target name is set differently compared to fuchsia.git's flutter_app(). -# Unlike in fuchsia.git's version of fuchsia_component, the Fuchsia GN SDK -# version passes the component name to fuchsia_component via it's target_name only. -# GN SDK's fuchsia_component doesn't have a `component_name` argument! So I'm forced to set -# the component name via "target_name". This is a problem in fuchsia_package, which uses -# the target_name to name the fuchsia_pm_tool target, creating duplicate target IDs! -# So I have to change the fuchsia_package name to something that is NOT the component name, -# and then set the package_name (which fuchsia_package does support). -fuchsia_package("package") { - package_name = "parent-view2" - deps = [ ":parent-view2_flutter_component" ] -} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx deleted file mode 100644 index b839053be4c..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx +++ /dev/null @@ -1,14 +0,0 @@ -{ - "program": { - "data": "data/parent-view2" - }, - "sandbox": { - "services": [ - "fuchsia.fonts.Provider", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/BUILD.gn deleted file mode 100644 index 36d862c7136..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/BUILD.gn +++ /dev/null @@ -1,30 +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. - -import("//build/fuchsia/sdk.gni") - -source_set("base_view") { - sources = [ - "base_view.cc", - "base_view.h", - "embedded_view_utils.cc", - "embedded_view_utils.h", - "math.h", - ] - - include_dirs = [ "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing" ] - - public_deps = [ - "$fuchsia_sdk_root/fidl:fuchsia.sys", - "$fuchsia_sdk_root/fidl:fuchsia.ui.app", - "$fuchsia_sdk_root/fidl:fuchsia.ui.gfx", - "$fuchsia_sdk_root/fidl:fuchsia.ui.input", - "$fuchsia_sdk_root/fidl:fuchsia.ui.views", - "$fuchsia_sdk_root/pkg:scenic_cpp", - "$fuchsia_sdk_root/pkg:sys_cpp", - "//flutter/fml", - ] - - deps = [ "$fuchsia_sdk_root/pkg:trace" ] -} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc deleted file mode 100644 index e4756f0bb8c..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc +++ /dev/null @@ -1,240 +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. - -#include "src/lib/ui/base_view/base_view.h" - -#include -#include -#include -#include -#include "flutter/fml/logging.h" - -namespace scenic { - -BaseView::BaseView(ViewContext context, const std::string& debug_name) - : component_context_(context.component_context), - listener_binding_(this, - std::move(context.session_and_listener_request.second)), - session_(std::move(context.session_and_listener_request.first)), - root_node_(&session_), - ime_client_(this), - enable_ime_(context.enable_ime) { - if (!context.view_ref_pair) { - context.view_ref_pair = scenic::ViewRefPair::New(); - } - view_.emplace(&session_, std::move(context.view_token), - std::move(context.view_ref_pair->control_ref), - std::move(context.view_ref_pair->view_ref), debug_name); - FML_DCHECK(view_); - - session_.SetDebugName(debug_name); - - // Listen for metrics events on our top node. - root_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask); - view_->AddChild(root_node_); - - if (enable_ime_) { - ime_manager_ = - component_context_->svc()->Connect(); - - ime_.set_error_handler([](zx_status_t status) { - FML_LOG(ERROR) << "Interface error on: Input Method Editor " - << zx_status_get_string(status); - }); - ime_manager_.set_error_handler([](zx_status_t status) { - FML_LOG(ERROR) << "Interface error on: Text Sync Service " - << zx_status_get_string(status); - }); - } - - // We must immediately invalidate the scene, otherwise we wouldn't ever hook - // the View up to the ViewHolder. An alternative would be to require - // subclasses to call an Init() method to set up the initial connection. - InvalidateScene(); -} - -void BaseView::SetReleaseHandler(fit::function callback) { - listener_binding_.set_error_handler(std::move(callback)); -} - -void BaseView::InvalidateScene(PresentCallback present_callback) { - TRACE_DURATION("view", "BaseView::InvalidateScene"); - if (present_callback) { - callbacks_for_next_present_.push_back(std::move(present_callback)); - } - if (invalidate_pending_) - return; - - invalidate_pending_ = true; - - // Present the scene ASAP. Pass in the last presentation time; otherwise, if - // presentation_time argument is less than the previous time passed to - // PresentScene, the Session will be closed. - // (We cannot use the current time because the last requested presentation - // time, |last_presentation_time_|, could still be in the future. This is - // because Session.Present() returns after it _begins_ preparing the given - // frame, not after it is presented.) - if (!present_pending_) - PresentScene(last_presentation_time_); -} - -void BaseView::PresentScene() { - PresentScene(last_presentation_time_); -} - -void BaseView::OnScenicEvent(std::vector events) { - TRACE_DURATION("view", "BaseView::OnScenicEvent"); - for (auto& event : events) { - switch (event.Which()) { - case ::fuchsia::ui::scenic::Event::Tag::kGfx: - switch (event.gfx().Which()) { - case ::fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged: { - auto& evt = event.gfx().view_properties_changed(); - FML_DCHECK(view_->id() == evt.view_id); - auto old_props = view_properties_; - view_properties_ = evt.properties; - - ::fuchsia::ui::gfx::BoundingBox layout_box = - ViewPropertiesLayoutBox(view_properties_); - - logical_size_ = scenic::Max(layout_box.max - layout_box.min, 0.f); - physical_size_.x = logical_size_.x * metrics_.scale_x; - physical_size_.y = logical_size_.y * metrics_.scale_y; - physical_size_.z = logical_size_.z * metrics_.scale_z; - - OnPropertiesChanged(std::move(old_props)); - InvalidateScene(); - break; - } - case fuchsia::ui::gfx::Event::Tag::kMetrics: { - auto& evt = event.gfx().metrics(); - if (evt.node_id == root_node_.id()) { - auto old_metrics = metrics_; - metrics_ = std::move(evt.metrics); - physical_size_.x = logical_size_.x * metrics_.scale_x; - physical_size_.y = logical_size_.y * metrics_.scale_y; - physical_size_.z = logical_size_.z * metrics_.scale_z; - OnMetricsChanged(std::move(old_metrics)); - InvalidateScene(); - } - break; - } - default: { - OnScenicEvent(std::move(event)); - } - } - break; - case ::fuchsia::ui::scenic::Event::Tag::kInput: { - if (event.input().Which() == - fuchsia::ui::input::InputEvent::Tag::kFocus && - enable_ime_) { - OnHandleFocusEvent(event.input().focus()); - } - OnInputEvent(std::move(event.input())); - break; - } - case ::fuchsia::ui::scenic::Event::Tag::kUnhandled: { - OnUnhandledCommand(std::move(event.unhandled())); - break; - } - default: { - OnScenicEvent(std::move(event)); - } - } - } -} - -void BaseView::PresentScene(zx_time_t presentation_time) { - TRACE_DURATION("view", "BaseView::PresentScene"); - // TODO(fxbug.dev/24406): Remove this when BaseView::PresentScene() is - // deprecated, see fxbug.dev/24573. - if (present_pending_) - return; - - present_pending_ = true; - - // Keep track of the most recent presentation time we've passed to - // Session.Present(), for use in InvalidateScene(). - last_presentation_time_ = presentation_time; - - TRACE_FLOW_BEGIN("gfx", "Session::Present", session_present_count_); - ++session_present_count_; - - session()->Present( - presentation_time, - [this, present_callbacks = std::move(callbacks_for_next_present_)]( - fuchsia::images::PresentationInfo info) mutable { - TRACE_DURATION("view", "BaseView::PresentationCallback"); - TRACE_FLOW_END("gfx", "present_callback", info.presentation_time); - - FML_DCHECK(present_pending_); - - zx_time_t next_presentation_time = - info.presentation_time + info.presentation_interval; - - bool present_needed = false; - if (invalidate_pending_) { - invalidate_pending_ = false; - OnSceneInvalidated(std::move(info)); - present_needed = true; - } - - for (auto& callback : present_callbacks) { - callback(info); - } - - present_pending_ = false; - if (present_needed) - PresentScene(next_presentation_time); - }); - callbacks_for_next_present_.clear(); -} - -// |fuchsia::ui::input::InputMethodEditorClient| -void BaseView::DidUpdateState( - fuchsia::ui::input::TextInputState state, - std::unique_ptr input_event) { - if (input_event) { - const fuchsia::ui::input::InputEvent& input = *input_event; - fuchsia::ui::input::InputEvent input_event_copy; - fidl::Clone(input, &input_event_copy); - OnInputEvent(std::move(input_event_copy)); - } -} - -// |fuchsia::ui::input::InputMethodEditorClient| -void BaseView::OnAction(fuchsia::ui::input::InputMethodAction action) {} - -bool BaseView::OnHandleFocusEvent(const fuchsia::ui::input::FocusEvent& focus) { - if (focus.focused) { - ActivateIme(); - return true; - } else if (!focus.focused) { - DeactivateIme(); - return true; - } - return false; -} - -void BaseView::ActivateIme() { - ime_manager_->GetInputMethodEditor( - fuchsia::ui::input::KeyboardType::TEXT, // keyboard type - fuchsia::ui::input::InputMethodAction::DONE, // input method action - fuchsia::ui::input::TextInputState{}, // initial state - ime_client_.NewBinding(), // client - ime_.NewRequest() // editor - ); -} - -void BaseView::DeactivateIme() { - if (ime_) { - ime_manager_->HideKeyboard(); - ime_ = nullptr; - } - if (ime_client_.is_bound()) { - ime_client_.Unbind(); - } -} - -} // namespace scenic diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h deleted file mode 100644 index 6ad0257ca55..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h +++ /dev/null @@ -1,210 +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 SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_ -#define SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include "src/lib/ui/base_view/embedded_view_utils.h" -#include "src/lib/ui/base_view/math.h" - -namespace scenic { - -// Parameters for creating a BaseView. -struct ViewContext { - scenic::SessionPtrAndListenerRequest session_and_listener_request; - fuchsia::ui::views::ViewToken view_token; - std::optional view_ref_pair; - sys::ComponentContext* component_context; - bool enable_ime = false; -}; - -// Abstract base implementation of a view for simple applications. -// Subclasses must handle layout and provide content for the scene by -// overriding the virtual methods defined in this class. -// -// It is not necessary to use this class to implement all Views. -// This class is merely intended to make the simple apps easier to write. -class BaseView : private fuchsia::ui::scenic::SessionListener, - private fuchsia::ui::input::InputMethodEditorClient { - public: - using PresentCallback = - fit::function; - - // Subclasses are typically created by ViewProviderService::CreateView(), - // which provides the necessary args to pass down to this base class. - BaseView(ViewContext context, const std::string& debug_name); - - BaseView(const BaseView&) = delete; - - // |root_node| is the node directly under our View; i.e. it's the top-most - // node within the tree under our View. Use it to attach any resources for - // your UI. - scenic::EntityNode& root_node() { return root_node_; } - Session* session() { return &session_; } - sys::ComponentContext* component_context() { return component_context_; } - - fuchsia::ui::gfx::ViewProperties view_properties() const { - return view_properties_; - } - - // Returns true if the view has a non-empty size in logical pixels. - bool has_logical_size() const { - auto& sz = logical_size(); - return sz.x > 0.f && sz.y > 0.f && sz.z > 0.f; - } - - // Gets the size of the view in logical pixels. - // This value is zero until the view receives a layout from its parent. - const fuchsia::ui::gfx::vec3& logical_size() const { return logical_size_; } - - // Returns true if the view has a non-empty size in physical pixels. - bool has_physical_size() const { - auto& sz = physical_size(); - return sz.x > 0.f && sz.y > 0.f && sz.z > 0.f; - } - - // Gets the size of the view in physical pixels. - // This value is zero until the view receives a layout from its parent - // and metrics from its session. - const fuchsia::ui::gfx::vec3& physical_size() const { return physical_size_; } - - // Returns true if the view has received metrics from its session. - bool has_metrics() const { - return metrics_.scale_x > 0.f && metrics_.scale_y > 0.f && - metrics_.scale_z > 0.f; - } - - // Gets the view's metrics. - // This value is zero until the view receives metrics from its session. - const fuchsia::ui::gfx::Metrics& metrics() const { return metrics_; } - - // Sets a callback which is invoked when the view's owner releases the - // view causing the view manager to unregister it. - // - // This should be used to implement cleanup policies to release resources - // associated with the view (including the object itself). - void SetReleaseHandler(fit::function callback); - - // Invalidates the scene, causing |OnSceneInvalidated()| to be invoked - // during the next frame. When the Present() callback corresponding to this - // invalidate is invoked, the optional |present_callback| will also be - // invoked. - void InvalidateScene(PresentCallback present_callback = nullptr); - - // Called when it's time for the view to update its scene contents due to - // invalidation. The new contents are presented once this function returns. - // - // The default implementation does nothing. - virtual void OnSceneInvalidated( - fuchsia::images::PresentationInfo presentation_info) {} - - // Called when the view's properties have changed. - // - // The subclass should compare the old and new properties and make note of - // whether these property changes will affect the layout or content of - // the view then update accordingly. - // - // The default implementation does nothing. - virtual void OnPropertiesChanged( - fuchsia::ui::gfx::ViewProperties old_properties) {} - - // Called when the view's metrics have changed. - // - // The subclass should compare the old and new metrics and make note of - // whether this change will affect the layout or content of the view then - // update accordingly. - // - // The default implementation does nothing. - virtual void OnMetricsChanged(fuchsia::ui::gfx::Metrics old_metrics){}; - - // Called to handle an input event. - // - // The default implementation does nothing. - virtual void OnInputEvent(fuchsia::ui::input::InputEvent event) {} - - // Called when a command sent by the client was not handled by Scenic. - // - // The default implementation does nothing. - virtual void OnUnhandledCommand(fuchsia::ui::scenic::Command unhandled) {} - - // Called when an event that is not handled directly by BaseView is received. - // For example, BaseView handles fuchsia::ui::gfx::ViewPropertiesChangedEvent, - // and notifies the subclass via OnPropertiesChanged(); not all events are - // handled in this way. - // - // The default implementation does nothing. - virtual void OnScenicEvent(fuchsia::ui::scenic::Event) {} - - protected: - // An alternative way to update the scene. Provide a faster way to cause a - // present in comparison to InvalidateScene(). Caller should update the - // scene contents before calling this method. - void PresentScene(); - - private: - // |scenic::SessionListener| - // - // Iterates over the received events and either handles them in a sensible way - // (e.g. fuchsia::ui::gfx::ViewPropertiesChangedEvent is handled by invoking - // the virtual method OnPropertiesChanged()), or delegates handling to the - // subclass via the single-event version of OnEvent() above. - // - // Subclasses should not override this. - void OnScenicEvent(std::vector events) override; - - // |fuchsia::ui::input::InputMethodEditorClient| - void DidUpdateState( - fuchsia::ui::input::TextInputState state, - std::unique_ptr event) override; - - // |fuchsia::ui::input::InputMethodEditorClient| - void OnAction(fuchsia::ui::input::InputMethodAction action) override; - - void PresentScene(zx_time_t presentation_time); - - // Handles focus event when IME is enabled. This event is used to activate - // or deactivate the IME client. - bool OnHandleFocusEvent(const fuchsia::ui::input::FocusEvent& focus); - - // Gets a new input method editor from the IME manager. - void ActivateIme(); - - // Detaches the input method editor connection, ending the edit session and - // closing the onscreen keyboard. - void DeactivateIme(); - - sys::ComponentContext* const component_context_; - fidl::Binding listener_binding_; - Session session_; - std::optional view_; - scenic::EntityNode root_node_; - - fidl::Binding ime_client_; - fuchsia::ui::input::InputMethodEditorPtr ime_; - fuchsia::ui::input::ImeServicePtr ime_manager_; - - fuchsia::ui::gfx::vec3 logical_size_; - fuchsia::ui::gfx::vec3 physical_size_; - fuchsia::ui::gfx::ViewProperties view_properties_; - fuchsia::ui::gfx::Metrics metrics_; - - zx_time_t last_presentation_time_ = 0; - size_t session_present_count_ = 0; - bool invalidate_pending_ = false; - std::vector callbacks_for_next_present_; - bool present_pending_ = false; - bool enable_ime_ = false; -}; - -} // namespace scenic - -#endif // SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc deleted file mode 100644 index 6235b8d29c1..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc +++ /dev/null @@ -1,48 +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. - -#include "src/lib/ui/base_view/embedded_view_utils.h" - -#include -#include -#include "flutter/fml/logging.h" - -namespace scenic { - -EmbeddedViewInfo LaunchComponentAndCreateView( - const fuchsia::sys::LauncherPtr& launcher, - const std::string& component_url, - const std::vector& component_args) { - FML_DCHECK(launcher); - - EmbeddedViewInfo info; - - // Configure the information to launch the component with. - fuchsia::sys::LaunchInfo launch_info; - info.app_services = - sys::ServiceDirectory::CreateWithRequest(&launch_info.directory_request); - launch_info.url = component_url; - launch_info.arguments = fidl::VectorPtr( - std::vector(component_args.begin(), component_args.end())); - - launcher->CreateComponent(std::move(launch_info), - info.controller.NewRequest()); - - info.view_provider = - info.app_services->Connect(); - - auto [view_token, view_holder_token] = scenic::ViewTokenPair::New(); - info.view_holder_token = std::move(view_holder_token); - - auto [view_ref_control, view_ref] = scenic::ViewRefPair::New(); - fidl::Clone(view_ref, &info.view_ref); - - info.view_provider->CreateViewWithViewRef(std::move(view_token.value), - std::move(view_ref_control), - std::move(view_ref)); - - return info; -} - -} // namespace scenic diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h deleted file mode 100644 index ff087d4a03c..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h +++ /dev/null @@ -1,58 +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 SRC_LIB_UI_BASE_VIEW_EMBEDDED_VIEW_UTILS_H_ -#define SRC_LIB_UI_BASE_VIEW_EMBEDDED_VIEW_UTILS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace scenic { - -// Serves as the return value for LaunchAppAndCreateView(), below. -struct EmbeddedViewInfo { - // Controls the launched app. The app will be destroyed if this connection - // is closed. - fuchsia::sys::ComponentControllerPtr controller; - - // Services provided by the launched app. Must not be destroyed - // immediately, otherwise the |view_provider| connection may not be - // established. - std::shared_ptr app_services; - - // ViewProvider service obtained from the app via |app_services|. Must not - // be destroyed immediately, otherwise the call to CreateView() might not be - // processed. - fuchsia::ui::app::ViewProviderPtr view_provider; - - // A token that can be used to create a ViewHolder; the corresponding token - // was provided to |view_provider| via ViewProvider.CreateView(). The - // launched app is expected to create a View, which will be connected to the - // ViewHolder created with this token. - fuchsia::ui::views::ViewHolderToken view_holder_token; - - // The ViewRef of the embedded View. - fuchsia::ui::views::ViewRef view_ref; -}; - -// Launch a component and connect to its ViewProvider service, passing it the -// necessary information to attach itself as a child view2. Populates the -// returned EmbeddedViewInfo, which the caller can use to embed the child. -// For example, an interface to a ViewProvider is obtained, a pair of -// zx::eventpairs is created, CreateView is called, etc. This encapsulates -// the boilerplate the client would otherwise write themselves. -EmbeddedViewInfo LaunchComponentAndCreateView( - const fuchsia::sys::LauncherPtr& launcher, - const std::string& component_url, - const std::vector& component_args = {}); - -} // namespace scenic - -#endif // SRC_LIB_UI_BASE_VIEW_EMBEDDED_VIEW_UTILS_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h deleted file mode 100644 index 9cf99ce8276..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h +++ /dev/null @@ -1,92 +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 SRC_LIB_UI_BASE_VIEW_MATH_H_ -#define SRC_LIB_UI_BASE_VIEW_MATH_H_ - -#include - -namespace scenic { - -// Return a vec3 consisting of the component-wise sum of the two arguments. -inline fuchsia::ui::gfx::vec3 operator+(const fuchsia::ui::gfx::vec3& a, - const fuchsia::ui::gfx::vec3& b) { - return {.x = a.x + b.x, .y = a.y + b.y, .z = a.z + b.z}; -} - -// Return a vec3 consisting of the component-wise difference of the two args. -inline fuchsia::ui::gfx::vec3 operator-(const fuchsia::ui::gfx::vec3& a, - const fuchsia::ui::gfx::vec3& b) { - return {.x = a.x - b.x, .y = a.y - b.y, .z = a.z - b.z}; -} - -// Return true if |point| is contained by |box|, including when it is on the -// box boundary, and false otherwise. -inline bool ContainsPoint(const fuchsia::ui::gfx::BoundingBox& box, - const fuchsia::ui::gfx::vec3& point) { - return point.x >= box.min.x && point.y >= box.min.y && point.z >= box.min.z && - point.x <= box.max.x && point.y <= box.max.y && point.z <= box.max.z; -} - -// Similar to fuchsia::ui::gfx::ViewProperties: adds the inset to box.min, and -// subtracts it from box.max. -inline fuchsia::ui::gfx::BoundingBox InsetBy( - const fuchsia::ui::gfx::BoundingBox& box, - const fuchsia::ui::gfx::vec3& inset) { - return {.min = box.min + inset, .max = box.max - inset}; -} - -// Similar to fuchsia::ui::gfx::ViewProperties: adds the inset to box.min, and -// subtracts it from box.max. -inline fuchsia::ui::gfx::BoundingBox InsetBy( - const fuchsia::ui::gfx::BoundingBox& box, - const fuchsia::ui::gfx::vec3& inset_from_min, - const fuchsia::ui::gfx::vec3& inset_from_max) { - return {.min = box.min + inset_from_min, .max = box.max - inset_from_max}; -} - -// Inset the view properties' outer box by its insets. -inline fuchsia::ui::gfx::BoundingBox ViewPropertiesLayoutBox( - const fuchsia::ui::gfx::ViewProperties& view_properties) { - return InsetBy(view_properties.bounding_box, view_properties.inset_from_min, - view_properties.inset_from_max); -} - -// Return a vec3 consisting of the maximum x/y/z from the two arguments. -inline fuchsia::ui::gfx::vec3 Max(const fuchsia::ui::gfx::vec3& a, - const fuchsia::ui::gfx::vec3& b) { - return {.x = std::max(a.x, b.x), - .y = std::max(a.y, b.y), - .z = std::max(a.z, b.z)}; -} - -// Return a vec3 consisting of the maximum of the x/y/z components of |v|, -// compared with |min_val|. -inline fuchsia::ui::gfx::vec3 Max(const fuchsia::ui::gfx::vec3& v, - float min_val) { - return {.x = std::max(v.x, min_val), - .y = std::max(v.y, min_val), - .z = std::max(v.z, min_val)}; -} - -// Return a vec3 consisting of the minimum x/y/z from the two arguments. -inline fuchsia::ui::gfx::vec3 Min(const fuchsia::ui::gfx::vec3& a, - const fuchsia::ui::gfx::vec3& b) { - return {.x = std::min(a.x, b.x), - .y = std::min(a.y, b.y), - .z = std::min(a.z, b.z)}; -} - -// Return a vec3 consisting of the minimum of the x/y/z components of |v|, -// compared with |max_val|. -inline fuchsia::ui::gfx::vec3 Min(const fuchsia::ui::gfx::vec3& v, - float max_val) { - return {.x = std::min(v.x, max_val), - .y = std::min(v.y, max_val), - .z = std::min(v.z, max_val)}; -} - -} // namespace scenic - -#endif // SRC_LIB_UI_BASE_VIEW_MATH_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/BUILD.gn deleted file mode 100644 index f97e927c2dc..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/BUILD.gn +++ /dev/null @@ -1,24 +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. - -import("//build/fuchsia/sdk.gni") - -source_set("views") { - testonly = true - - sources = [ - "color.cc", - "color.h", - "embedder_view.cc", - "embedder_view.h", - ] - - include_dirs = [ "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing" ] - - public_deps = [ - "$fuchsia_sdk_root/pkg:scenic_cpp", - "//flutter/fml", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view", - ] -} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.cc deleted file mode 100644 index 0d1128256be..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.cc +++ /dev/null @@ -1,88 +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. - -#include - -#include "flutter/fml/logging.h" -#include "src/ui/testing/views/embedder_view.h" - -namespace scenic { - -EmbedderView::EmbedderView(ViewContext context, const std::string& debug_name) - : binding_(this, std::move(context.session_and_listener_request.second)), - session_(std::move(context.session_and_listener_request.first)), - view_(&session_, std::move(context.view_token), debug_name), - top_node_(&session_) { - binding_.set_error_handler([](zx_status_t status) { - FML_LOG(FATAL) << "Session listener binding: " - << zx_status_get_string(status); - }); - view_.AddChild(top_node_); - // Call |Session::Present| in order to flush events having to do with - // creation of |view_| and |top_node_|. - session_.Present(0, [](auto) {}); -} - -// Sets the EmbeddedViewInfo and attaches the embedded View to the scene. Any -// callbacks for the embedded View's ViewState are delivered to the supplied -// callback. -void EmbedderView::EmbedView(EmbeddedViewInfo info, - std::function - view_state_changed_callback) { - // Only one EmbeddedView is currently supported. - FML_CHECK(!embedded_view_); - embedded_view_ = std::make_unique( - std::move(info), &session_, std::move(view_state_changed_callback)); - - // Attach the embedded view to the scene. - top_node_.Attach(embedded_view_->view_holder); - - // Call |Session::Present| to apply the embedded view to the scene graph. - session_.Present(0, [](auto) {}); -} - -void EmbedderView::OnScenicEvent( - std::vector events) { - for (const auto& event : events) { - if (event.Which() == fuchsia::ui::scenic::Event::Tag::kGfx && - event.gfx().Which() == - fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged) { - const auto& evt = event.gfx().view_properties_changed(); - // Naively apply the parent's ViewProperties to any EmbeddedViews. - if (embedded_view_) { - embedded_view_->view_holder.SetViewProperties( - std::move(evt.properties)); - session_.Present(0, [](auto) {}); - } - } else if (event.Which() == fuchsia::ui::scenic::Event::Tag::kGfx && - event.gfx().Which() == - fuchsia::ui::gfx::Event::Tag::kViewStateChanged) { - const auto& evt = event.gfx().view_state_changed(); - if (embedded_view_ && - evt.view_holder_id == embedded_view_->view_holder.id()) { - // Clients of |EmbedderView| *must* set a view state changed - // callback. Failure to do so is a usage error. - FML_CHECK(embedded_view_->view_state_changed_callback); - embedded_view_->view_state_changed_callback(evt.state); - } - } - } -} - -void EmbedderView::OnScenicError(std::string error) { - FML_LOG(FATAL) << "OnScenicError: " << error; -} - -EmbedderView::EmbeddedView::EmbeddedView( - EmbeddedViewInfo info, - Session* session, - std::function view_state_callback, - const std::string& debug_name) - : embedded_info(std::move(info)), - view_holder(session, - std::move(embedded_info.view_holder_token), - debug_name + " ViewHolder"), - view_state_changed_callback(std::move(view_state_callback)) {} - -} // namespace scenic diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.h b/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.h deleted file mode 100644 index 4514d0f850f..00000000000 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.h +++ /dev/null @@ -1,59 +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 SRC_UI_TESTING_VIEWS_EMBEDDER_VIEW_H_ -#define SRC_UI_TESTING_VIEWS_EMBEDDER_VIEW_H_ - -#include -#include -#include - -#include "src/lib/ui/base_view/base_view.h" - -namespace scenic { - -// This is a simplified |BaseView| that exposes view state events. -// -// See also lib/ui/base_view. -class EmbedderView : public fuchsia::ui::scenic::SessionListener { - public: - EmbedderView(ViewContext context, - const std::string& debug_name = "EmbedderView"); - - // Sets the EmbeddedViewInfo and attaches the embedded View to the scene. Any - // callbacks for the embedded View's ViewState are delivered to the supplied - // callback. - void EmbedView(EmbeddedViewInfo info, - std::function - view_state_changed_callback); - - private: - // |fuchsia::ui::scenic::SessionListener| - void OnScenicEvent(std::vector events) override; - // |fuchsia::ui::scenic::SessionListener| - void OnScenicError(std::string error) override; - - struct EmbeddedView { - EmbeddedView( - EmbeddedViewInfo info, - Session* session, - std::function view_state_callback, - const std::string& debug_name = "EmbedderView"); - - EmbeddedViewInfo embedded_info; - ViewHolder view_holder; - std::function - view_state_changed_callback; - }; - - fidl::Binding binding_; - Session session_; - View view_; - EntityNode top_node_; - std::optional embedded_view_properties_; - std::unique_ptr embedded_view_; -}; - -} // namespace scenic -#endif // SRC_UI_TESTING_VIEWS_EMBEDDER_VIEW_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn similarity index 73% rename from engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/BUILD.gn rename to engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn index 6e5e43e0b05..c25f18aaa8b 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/BUILD.gn +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn @@ -2,7 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -group("integration_flutter_tests") { +assert(is_fuchsia) + +import("//build/fuchsia/sdk.gni") + +group("integration") { testonly = true deps = [ "embedder:tests" ] } diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/README.md b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/README.md new file mode 100644 index 00000000000..2e86aa70286 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/README.md @@ -0,0 +1,84 @@ +# `flutter integration tests` + +## Configure and build fuchsia + +```shell +$ cd "$FUCHSIA_DIR" +$ fx set terminal.x64 +$ fx build +``` + +## Build the test + +You can specify the test's package target to build only the test package, with +its dependencies. This will also build the required runner. + +```shell +$ cd "$ENGINE_DIR/src" +$ ./flutter/tools/gn --fuchsia \ + # for example: --goma --fuchsia-cpu=x64 --runtime-mode=debug +$ ninja -C out/fuchsia_debug_x64 \ + flutter/shell/platform/fuchsia/flutter/tests/integration +``` + + +## Start an emulator + +```shell +ffx emu start --net tap +``` + +NOTE: Do _not_ run the default package server. The instructions below describe +how to launch a flutter-specific package server. + +## Publish the test packages to the Fuchsia package server + +The tests currently specify the Fuchsia package server's standard domain, +`fuchsia.com`, as the server to use to resolve (locate and load) the test +packages. So, before running the test, the most recently built `.far` files +need to be published to the Fuchsia package repo: + +```shell +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64/oot_flutter_jit_runner-0.far +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64/flutter-embedder-test-0.far +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name parent-view.far) +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name child-view.far) +``` + +## Run the test + +```shell +$ ffx test run fuchsia-pkg:://fuchsia.com/flutter-embedder-test#meta/flutter-embedder-test.cm +``` + +If, for example, you only make a change to the Dart code in `parent-view`, you +can rebuild only the parent-view package target, and republish it. + +```shell +$ ninja -C out/fuchsia_debug_x64 \ + flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view:package +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name parent-view.far) +``` + +Then re-run the test as above. + +The tests use a flutter runner with "oot_" prefixed to its package name, to +avoid conflicting with any flutter_runner package in the base fuchsia image. +After making a change to the flutter_runner you can re-deploy it with: + +```shell +$ ninja -C out/fuchsia_debug_x64 \ + flutter/shell/platform/fuchsia/flutter:oot_flutter_jit_runner +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name oot_flutter_jit_runner.far) +``` + +Then re-run the test as above. + +From here, you can modify the Flutter test, rebuild flutter, and usually rerun +the test without rebooting, by repeating the commands above. diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn new file mode 100644 index 00000000000..ce295f31107 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn @@ -0,0 +1,65 @@ +# 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. + +assert(is_fuchsia) + +import("//build/fuchsia/sdk.gni") +import("//flutter/tools/fuchsia/fuchsia_archive.gni") + +group("tests") { + testonly = true + deps = [ ":flutter-embedder-test" ] +} + +executable("flutter-embedder-test-bin") { + testonly = true + + output_name = "flutter-embedder-test" + + sources = [ + "color.cc", + "color.h", + "flutter-embedder-test.cc", + ] + + # This is needed for //third_party/googletest for linking zircon symbols. + libs = [ "$fuchsia_sdk_path/arch/$target_cpu/sysroot/lib/libzircon.so" ] + + deps = [ + "$fuchsia_sdk_root/fidl:fuchsia.logger", + "$fuchsia_sdk_root/fidl:fuchsia.tracing.provider", + "$fuchsia_sdk_root/fidl:fuchsia.ui.app", + "$fuchsia_sdk_root/fidl:fuchsia.ui.composition", + "$fuchsia_sdk_root/fidl:fuchsia.ui.observation.geometry", + "$fuchsia_sdk_root/fidl:fuchsia.ui.scenic", + "$fuchsia_sdk_root/fidl:fuchsia.ui.test.input", + "$fuchsia_sdk_root/fidl:fuchsia.ui.test.scene", + "$fuchsia_sdk_root/pkg:async", + "$fuchsia_sdk_root/pkg:async-loop-testing", + "$fuchsia_sdk_root/pkg:fidl_cpp", + "$fuchsia_sdk_root/pkg:scenic_cpp", + "$fuchsia_sdk_root/pkg:sys_component_cpp_testing", + "$fuchsia_sdk_root/pkg:zx", + "//flutter/fml", + "//third_party/googletest:gtest", + "//third_party/googletest:gtest_main", + ] +} + +fuchsia_test_archive("flutter-embedder-test") { + deps = [ + ":flutter-embedder-test-bin", + "child-view:package", + "parent-view:package", + + # "OOT" copies of the runners used by tests, to avoid conflicting with the + # runners in the base fuchsia image. + # TODO(fxbug.dev/106575): Fix this with subpackages. + "//flutter/shell/platform/fuchsia/flutter:oot_flutter_jit_runner", + ] + + binary = "$target_name" + + cml_file = rebase_path("meta/$target_name.cml") +} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/BUILD.gn new file mode 100644 index 00000000000..dedf77c3eb9 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/BUILD.gn @@ -0,0 +1,26 @@ +# 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("//build/fuchsia/sdk.gni") +import("//flutter/tools/fuchsia/dart/dart_library.gni") +import("//flutter/tools/fuchsia/flutter/flutter_component.gni") +import("//flutter/tools/fuchsia/gn-sdk/package.gni") + +dart_library("lib") { + package_name = "child-view" + sources = [ "child_view.dart" ] +} + +flutter_component("component") { + main_package = "child-view" + component_name = "child-view" + main_dart = "child_view.dart" + manifest = rebase_path("meta/child-view.cml") + deps = [ ":lib" ] +} + +fuchsia_package("package") { + package_name = "child-view" + deps = [ ":component" ] +} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child_view2.dart b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/lib/child_view.dart similarity index 85% rename from engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child_view2.dart rename to engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/lib/child_view.dart index a36195526d4..5b71294b700 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child_view2.dart +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/lib/child_view.dart @@ -4,10 +4,10 @@ import 'dart:ui'; -TestApp app; - void main(List args) { - app = TestApp(); + print('child-view: starting'); + + TestApp app = TestApp(); app.run(); } @@ -19,11 +19,15 @@ class TestApp { void run() { window.onPointerDataPacket = (PointerDataPacket packet) { - app.pointerDataPacket(packet); + this.pointerDataPacket(packet); + }; + window.onMetricsChanged = () { + window.scheduleFrame(); }; window.onBeginFrame = (Duration duration) { - app.beginFrame(duration); + this.beginFrame(duration); }; + window.scheduleFrame(); } @@ -46,7 +50,7 @@ class TestApp { void pointerDataPacket(PointerDataPacket packet) { for (final data in packet.data) { - if (data.change == PointerChange.up) { + if (data.change == PointerChange.down) { this._backgroundColor = _yellow; } } diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml new file mode 100644 index 00000000000..9e33d6a3eff --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml @@ -0,0 +1,21 @@ +{ + include: [ "syslog/client.shard.cml" ], + program: { + data: "data/child-view", + + // Always use the jit runner for now. + // TODO(fxbug.dev/106577): Implement manifest merging build rules for V2 components. + runner: "flutter_jit_runner", + }, + capabilities: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + }, + ], + expose: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + from: "self", + }, + ], +} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/pubspec.yaml similarity index 100% rename from engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/pubspec.yaml rename to engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/pubspec.yaml diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc similarity index 98% rename from engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.cc rename to engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc index d723734f1a3..24fd6753752 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "color.h" + #include #include "flutter/fml/logging.h" -#include "src/ui/testing/views/color.h" namespace scenic { diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.h b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/color.h similarity index 100% rename from engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.h rename to engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/color.h diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc new file mode 100644 index 00000000000..73f36e85ede --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc @@ -0,0 +1,602 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "flutter/fml/logging.h" +#include "gtest/gtest.h" + +#include "color.h" + +namespace flutter_embedder_test { +namespace { + +// Types imported for the realm_builder library. +using component_testing::ChildOptions; +using component_testing::ChildRef; +using component_testing::DirectoryContents; +using component_testing::ParentRef; +using component_testing::Protocol; +using component_testing::RealmRoot; +using component_testing::Route; +using component_testing::StartupMode; + +// The FIDL bindings for this service are not exposed in the Fuchsia SDK, so we +// must encode the name manually here. +constexpr auto kVulkanLoaderServiceName = "fuchsia.vulkan.loader.Loader"; + +constexpr auto kFlutterJitRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_flutter_jit_runner#meta/" + "flutter_jit_runner.cm"; +constexpr auto kFlutterJitProductRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_flutter_jit_product_runner#meta/" + "flutter_jit_product_runner.cm"; +constexpr auto kFlutterAotRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_flutter_aot_runner#meta/" + "flutter_aot_runner.cm"; +constexpr auto kFlutterAotProductRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_flutter_aot_product_runner#meta/" + "flutter_aot_product_runner.cm"; +constexpr char kChildViewUrl[] = + "fuchsia-pkg://fuchsia.com/child-view#meta/child-view.cm"; +constexpr char kParentViewUrl[] = + "fuchsia-pkg://fuchsia.com/parent-view#meta/parent-view.cm"; +static constexpr auto kTestUIStackUrl = + "fuchsia-pkg://fuchsia.com/test-ui-stack#meta/test-ui-stack.cm"; + +constexpr auto kFlutterRunnerEnvironment = "flutter_runner_env"; +constexpr auto kFlutterJitRunner = "flutter_jit_runner"; +constexpr auto kFlutterJitRunnerRef = ChildRef{kFlutterJitRunner}; +constexpr auto kFlutterJitProductRunner = "flutter_jit_product_runner"; +constexpr auto kFlutterJitProductRunnerRef = ChildRef{kFlutterJitProductRunner}; +constexpr auto kFlutterAotRunner = "flutter_aot_runner"; +constexpr auto kFlutterAotRunnerRef = ChildRef{kFlutterAotRunner}; +constexpr auto kFlutterAotProductRunner = "flutter_aot_product_runner"; +constexpr auto kFlutterAotProductRunnerRef = ChildRef{kFlutterAotProductRunner}; +constexpr auto kChildView = "child_view"; +constexpr auto kChildViewRef = ChildRef{kChildView}; +constexpr auto kParentView = "parent_view"; +constexpr auto kParentViewRef = ChildRef{kParentView}; +constexpr auto kTestUIStack = "ui"; +constexpr auto kTestUIStackRef = ChildRef{kTestUIStack}; + +constexpr scenic::Color kParentBackgroundColor = {0x00, 0x00, 0xFF, + 0xFF}; // Blue +constexpr scenic::Color kParentTappedColor = {0x00, 0x00, 0x00, 0xFF}; // Black +constexpr scenic::Color kChildBackgroundColor = {0xFF, 0x00, 0xFF, + 0xFF}; // Pink +constexpr scenic::Color kChildTappedColor = {0xFF, 0xFF, 0x00, 0xFF}; // Yellow + +// TODO(fxb/64201): Remove forced opacity colors when Flatland is enabled. +constexpr scenic::Color kOverlayBackgroundColor1 = { + 0x00, 0xFF, 0x0E, 0xFF}; // Green, blended with blue (FEMU local) +constexpr scenic::Color kOverlayBackgroundColor2 = { + 0x0E, 0xFF, 0x0E, 0xFF}; // Green, blended with pink (FEMU local) +constexpr scenic::Color kOverlayBackgroundColor3 = { + 0x00, 0xFF, 0x0D, 0xFF}; // Green, blended with blue (AEMU infra) +constexpr scenic::Color kOverlayBackgroundColor4 = { + 0x0D, 0xFF, 0x0D, 0xFF}; // Green, blended with pink (AEMU infra) +constexpr scenic::Color kOverlayBackgroundColor5 = { + 0x00, 0xFE, 0x0D, 0xFF}; // Green, blended with blue (NUC) +constexpr scenic::Color kOverlayBackgroundColor6 = { + 0x0D, 0xFF, 0x00, 0xFF}; // Green, blended with pink (NUC) + +static size_t OverlayPixelCount(std::map& histogram) { + return histogram[kOverlayBackgroundColor1] + + histogram[kOverlayBackgroundColor2] + + histogram[kOverlayBackgroundColor3] + + histogram[kOverlayBackgroundColor4] + + histogram[kOverlayBackgroundColor5] + + histogram[kOverlayBackgroundColor6]; +} + +// Timeout for Scenic's |TakeScreenshot| FIDL call. +constexpr zx::duration kScreenshotTimeout = zx::sec(10); +// Timeout to fail the test if it goes beyond this duration. +constexpr zx::duration kTestTimeout = zx::min(1); + +bool CheckViewExistsInSnapshot( + const fuchsia::ui::observation::geometry::ViewTreeSnapshot& snapshot, + zx_koid_t view_ref_koid) { + if (!snapshot.has_views()) { + return false; + } + + auto snapshot_count = + std::count_if(snapshot.views().begin(), snapshot.views().end(), + [view_ref_koid](const auto& view) { + return view.view_ref_koid() == view_ref_koid; + }); + + return snapshot_count > 0; +} + +bool CheckViewExistsInUpdates( + const std::vector& + updates, + zx_koid_t view_ref_koid) { + auto update_count = std::count_if( + updates.begin(), updates.end(), [view_ref_koid](auto& snapshot) { + return CheckViewExistsInSnapshot(snapshot, view_ref_koid); + }); + + return update_count > 0; +} + +} // namespace + +class FlutterEmbedderTest : public ::loop_fixture::RealLoop, + public ::testing::Test { + public: + FlutterEmbedderTest() + : realm_builder_(component_testing::RealmBuilder::Create()) { + FML_VLOG(-1) << "Setting up base realm"; + SetUpRealmBase(); + + // Post a "just in case" quit task, if the test hangs. + async::PostDelayedTask( + dispatcher(), + [] { + FML_LOG(FATAL) + << "\n\n>> Test did not complete in time, terminating. <<\n\n"; + }, + kTestTimeout); + } + + bool HasViewConnected( + const fuchsia::ui::observation::geometry::ViewTreeWatcherPtr& + view_tree_watcher, + std::optional& + watch_response, + zx_koid_t view_ref_koid); + + void LaunchParentViewInRealm( + const std::vector& component_args = {}); + + scenic::Screenshot TakeScreenshot(); + + bool TakeScreenshotUntil( + scenic::Color color, + fit::function)> callback = nullptr, + zx::duration timeout = kTestTimeout); + + // Simulates a tap at location (x, y). + void InjectTap(int32_t x, int32_t y); + + // Injects an input event, and posts a task to retry after + // `kTapRetryInterval`. + // + // We post the retry task because the first input event we send to Flutter may + // be lost. The reason the first event may be lost is that there is a race + // condition as the scene owner starts up. + // + // More specifically: in order for our app + // to receive the injected input, two things must be true before we inject + // touch input: + // * The Scenic root view must have been installed, and + // * The Input Pipeline must have received a viewport to inject touch into. + // + // The problem we have is that the `is_rendering` signal that we monitor only + // guarantees us the view is ready. If the viewport is not ready in Input + // Pipeline at that time, it will drop the touch event. + // + // TODO(fxbug.dev/96986): Improve synchronization and remove retry logic. + void TryInject(int32_t x, int32_t y); + + private: + fuchsia::ui::scenic::Scenic* scenic() { return scenic_.get(); } + + void SetUpRealmBase(); + + // Registers a fake touch screen device with an injection coordinate space + // spanning [-1000, 1000] on both axes. + void RegisterTouchScreen(); + + fuchsia::ui::scenic::ScenicPtr scenic_; + fuchsia::ui::test::input::RegistryPtr input_registry_; + fuchsia::ui::test::input::TouchScreenPtr fake_touchscreen_; + fuchsia::ui::test::scene::ControllerPtr scene_provider_; + fuchsia::ui::observation::geometry::ViewTreeWatcherPtr view_tree_watcher_; + + // Wrapped in optional since the view is not created until the middle of SetUp + component_testing::RealmBuilder realm_builder_; + std::unique_ptr realm_; + + // The typical latency on devices we've tested is ~60 msec. The retry interval + // is chosen to be a) Long enough that it's unlikely that we send a new tap + // while a previous tap is still being + // processed. That is, it should be far more likely that a new tap is sent + // because the first tap was lost, than because the system is just running + // slowly. + // b) Short enough that we don't slow down tryjobs. + // + // The first property is important to avoid skewing the latency metrics that + // we collect. For an explanation of why a tap might be lost, see the + // documentation for TryInject(). + static constexpr auto kTapRetryInterval = zx::sec(1); +}; + +void FlutterEmbedderTest::SetUpRealmBase() { + FML_LOG(INFO) << "Setting up realm base."; + + // First, add the flutter runner(s) as children. + realm_builder_.AddChild(kFlutterJitRunner, kFlutterJitRunnerUrl); + realm_builder_.AddChild(kFlutterJitProductRunner, + kFlutterJitProductRunnerUrl); + realm_builder_.AddChild(kFlutterAotRunner, kFlutterAotRunnerUrl); + realm_builder_.AddChild(kFlutterAotProductRunner, + kFlutterAotProductRunnerUrl); + + // Then, add an environment providing them. + fuchsia::component::decl::Environment flutter_runner_environment; + flutter_runner_environment.set_name(kFlutterRunnerEnvironment); + flutter_runner_environment.set_extends( + fuchsia::component::decl::EnvironmentExtends::REALM); + flutter_runner_environment.set_runners({}); + auto environment_runners = flutter_runner_environment.mutable_runners(); + fuchsia::component::decl::RunnerRegistration flutter_jit_runner_reg; + flutter_jit_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = kFlutterJitRunner})); + flutter_jit_runner_reg.set_source_name(kFlutterJitRunner); + flutter_jit_runner_reg.set_target_name(kFlutterJitRunner); + environment_runners->push_back(std::move(flutter_jit_runner_reg)); + fuchsia::component::decl::RunnerRegistration flutter_jit_product_runner_reg; + flutter_jit_product_runner_reg.set_source( + fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = + kFlutterJitProductRunner})); + flutter_jit_product_runner_reg.set_source_name(kFlutterJitProductRunner); + flutter_jit_product_runner_reg.set_target_name(kFlutterJitProductRunner); + environment_runners->push_back(std::move(flutter_jit_product_runner_reg)); + fuchsia::component::decl::RunnerRegistration flutter_aot_runner_reg; + flutter_aot_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = kFlutterAotRunner})); + flutter_aot_runner_reg.set_source_name(kFlutterAotRunner); + flutter_aot_runner_reg.set_target_name(kFlutterAotRunner); + environment_runners->push_back(std::move(flutter_aot_runner_reg)); + fuchsia::component::decl::RunnerRegistration flutter_aot_product_runner_reg; + flutter_aot_product_runner_reg.set_source( + fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = + kFlutterAotProductRunner})); + flutter_aot_product_runner_reg.set_source_name(kFlutterAotProductRunner); + flutter_aot_product_runner_reg.set_target_name(kFlutterAotProductRunner); + environment_runners->push_back(std::move(flutter_aot_product_runner_reg)); + auto realm_decl = realm_builder_.GetRealmDecl(); + if (!realm_decl.has_environments()) { + realm_decl.set_environments({}); + } + auto realm_environments = realm_decl.mutable_environments(); + realm_environments->push_back(std::move(flutter_runner_environment)); + realm_builder_.ReplaceRealmDecl(std::move(realm_decl)); + + // Add test UI stack component. + realm_builder_.AddChild(kTestUIStack, kTestUIStackUrl); + + // Add embedded parent and child components. + realm_builder_.AddChild(kChildView, kChildViewUrl, + ChildOptions{ + .environment = kFlutterRunnerEnvironment, + }); + realm_builder_.AddChild(kParentView, kParentViewUrl, + ChildOptions{ + .environment = kFlutterRunnerEnvironment, + }); + + // Route base system services to flutter runners. + realm_builder_.AddRoute( + Route{.capabilities = + { + Protocol{fuchsia::logger::LogSink::Name_}, + Protocol{fuchsia::sysmem::Allocator::Name_}, + Protocol{fuchsia::tracing::provider::Registry::Name_}, + Protocol{kVulkanLoaderServiceName}, + }, + .source = ParentRef{}, + .targets = {kFlutterJitRunnerRef, kFlutterJitProductRunnerRef, + kFlutterAotRunnerRef, kFlutterAotProductRunnerRef}}); + + // Route base system services to the test UI stack. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::logger::LogSink::Name_}, + Protocol{fuchsia::sysmem::Allocator::Name_}, + Protocol{fuchsia::tracing::provider::Registry::Name_}, + Protocol{kVulkanLoaderServiceName}}, + .source = ParentRef{}, + .targets = {kTestUIStackRef}}); + + // Route UI capabilities from test UI stack to flutter runners. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::ui::composition::Flatland::Name_}, + Protocol{fuchsia::ui::scenic::Scenic::Name_}}, + .source = kTestUIStackRef, + .targets = {kFlutterJitRunnerRef, kFlutterJitProductRunnerRef, + kFlutterAotRunnerRef, kFlutterAotProductRunnerRef}}); + + // Route test capabilities from test UI stack to test driver. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::ui::test::input::Registry::Name_}, + Protocol{fuchsia::ui::test::scene::Controller::Name_}, + Protocol{fuchsia::ui::scenic::Scenic::Name_}}, + .source = kTestUIStackRef, + .targets = {ParentRef{}}}); + + // Route ViewProvider from child to parent, and parent to test. + realm_builder_.AddRoute( + Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}}, + .source = kParentViewRef, + .targets = {ParentRef()}}); + realm_builder_.AddRoute( + Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}}, + .source = kChildViewRef, + .targets = {kParentViewRef}}); +} + +// Checks whether the view with |view_ref_koid| has connected to the view tree. +// The response of a f.u.o.g.Provider.Watch call is stored in |watch_response| +// if it contains |view_ref_koid|. +bool FlutterEmbedderTest::HasViewConnected( + const fuchsia::ui::observation::geometry::ViewTreeWatcherPtr& + view_tree_watcher, + std::optional& + watch_response, + zx_koid_t view_ref_koid) { + std::optional watch_result; + view_tree_watcher->Watch( + [&watch_result](auto response) { watch_result = std::move(response); }); + FML_LOG(INFO) << "Waiting for view tree watch result"; + RunLoopUntil([&watch_result] { return watch_result.has_value(); }); + FML_LOG(INFO) << "Received for view tree watch result"; + if (CheckViewExistsInUpdates(watch_result->updates(), view_ref_koid)) { + watch_response = std::move(watch_result); + }; + return watch_response.has_value(); +} + +void FlutterEmbedderTest::LaunchParentViewInRealm( + const std::vector& component_args) { + FML_LOG(INFO) << "Launching parent-view"; + + if (!component_args.empty()) { + // Construct a args.csv file containing the specified comma-separated + // component args. + std::string csv; + for (const auto& arg : component_args) { + csv += arg + ','; + } + // Remove last comma. + csv.pop_back(); + + auto config_directory_contents = DirectoryContents(); + config_directory_contents.AddFile("args.csv", csv); + realm_builder_.RouteReadOnlyDirectory("config-data", {kParentViewRef}, + std::move(config_directory_contents)); + } + realm_ = std::make_unique(realm_builder_.Build()); + + // Register fake touch screen device. + RegisterTouchScreen(); + + // Instruct Test UI Stack to present parent-view's View. + std::optional view_ref_koid; + scene_provider_ = realm_->Connect(); + scene_provider_.set_error_handler( + [](auto) { FML_LOG(ERROR) << "Error from test scene provider"; }); + fuchsia::ui::test::scene::ControllerAttachClientViewRequest request; + request.set_view_provider(realm_->Connect()); + scene_provider_->RegisterViewTreeWatcher(view_tree_watcher_.NewRequest(), + []() {}); + scene_provider_->AttachClientView( + std::move(request), [&view_ref_koid](auto client_view_ref_koid) { + view_ref_koid = client_view_ref_koid; + }); + + FML_LOG(INFO) << "Waiting for client view ref koid"; + RunLoopUntil([&view_ref_koid] { return view_ref_koid.has_value(); }); + + // Wait for the client view to get attached to the view tree. + std::optional + watch_response; + FML_LOG(INFO) << "Waiting for client view to render; koid is " + << (view_ref_koid.has_value() ? view_ref_koid.value() : 0); + RunLoopUntil([this, &watch_response, &view_ref_koid] { + return HasViewConnected(view_tree_watcher_, watch_response, *view_ref_koid); + }); + FML_LOG(INFO) << "Client view has rendered"; + + scenic_ = realm_->Connect(); + FML_LOG(INFO) << "Launched parent-view"; +} + +scenic::Screenshot FlutterEmbedderTest::TakeScreenshot() { + FML_LOG(INFO) << "Taking screenshot... "; + fuchsia::ui::scenic::ScreenshotData screenshot_out; + scenic_->TakeScreenshot( + [this, &screenshot_out](fuchsia::ui::scenic::ScreenshotData screenshot, + bool status) { + EXPECT_TRUE(status) << "Failed to take screenshot"; + screenshot_out = std::move(screenshot); + QuitLoop(); + }); + EXPECT_FALSE(RunLoopWithTimeout(kScreenshotTimeout)) + << "Timed out waiting for screenshot."; + FML_LOG(INFO) << "Screenshot captured."; + + return scenic::Screenshot(screenshot_out); +} + +bool FlutterEmbedderTest::TakeScreenshotUntil( + scenic::Color color, + fit::function)> callback, + zx::duration timeout) { + return RunLoopWithTimeoutOrUntil( + [this, &callback, &color] { + auto screenshot = TakeScreenshot(); + auto histogram = screenshot.Histogram(); + + bool color_found = histogram[color] > 0; + if (color_found && callback != nullptr) { + callback(std::move(histogram)); + } + return color_found; + }, + timeout); +} + +void FlutterEmbedderTest::RegisterTouchScreen() { + FML_LOG(INFO) << "Registering fake touch screen"; + input_registry_ = realm_->Connect(); + input_registry_.set_error_handler( + [](auto) { FML_LOG(ERROR) << "Error from input helper"; }); + bool touchscreen_registered = false; + fuchsia::ui::test::input::RegistryRegisterTouchScreenRequest request; + request.set_device(fake_touchscreen_.NewRequest()); + input_registry_->RegisterTouchScreen( + std::move(request), + [&touchscreen_registered]() { touchscreen_registered = true; }); + RunLoopUntil([&touchscreen_registered] { return touchscreen_registered; }); + FML_LOG(INFO) << "Touchscreen registered"; +} + +void FlutterEmbedderTest::InjectTap(int32_t x, int32_t y) { + fuchsia::ui::test::input::TouchScreenSimulateTapRequest tap_request; + tap_request.mutable_tap_location()->x = x; + tap_request.mutable_tap_location()->y = y; + fake_touchscreen_->SimulateTap(std::move(tap_request), [x, y]() { + FML_LOG(INFO) << "Tap injected at (" << x << ", " << y << ")"; + }); +} + +void FlutterEmbedderTest::TryInject(int32_t x, int32_t y) { + InjectTap(x, y); + async::PostDelayedTask( + dispatcher(), [this, x, y] { TryInject(x, y); }, kTapRetryInterval); +} + +TEST_F(FlutterEmbedderTest, Embedding) { + LaunchParentViewInRealm(); + + // Take screenshot until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil( + kChildBackgroundColor, [](std::map histogram) { + // Expect parent and child background colors, with parent color > child + // color. + EXPECT_GT(histogram[kParentBackgroundColor], 0u); + EXPECT_GT(histogram[kChildBackgroundColor], 0u); + EXPECT_GT(histogram[kParentBackgroundColor], + histogram[kChildBackgroundColor]); + })); +} + +TEST_F(FlutterEmbedderTest, HittestEmbedding) { + LaunchParentViewInRealm(); + + // Take screenshot until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); + + // Simulate a tap at the center of the child view. + TryInject(/* x = */ 0, /* y = */ 0); + + // Take screenshot until we see the child-view's tapped color. + ASSERT_TRUE(TakeScreenshotUntil( + kChildTappedColor, [](std::map histogram) { + // Expect parent and child background colors, with parent color > child + // color. + EXPECT_GT(histogram[kParentBackgroundColor], 0u); + EXPECT_EQ(histogram[kChildBackgroundColor], 0u); + EXPECT_GT(histogram[kChildTappedColor], 0u); + EXPECT_GT(histogram[kParentBackgroundColor], + histogram[kChildTappedColor]); + })); +} + +TEST_F(FlutterEmbedderTest, HittestDisabledEmbedding) { + LaunchParentViewInRealm({"--no-hitTestable"}); + + // Take screenshots until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); + + // Simulate a tap at the center of the child view. + TryInject(/* x = */ 0, /* y = */ 0); + + // The parent-view should change color. + ASSERT_TRUE(TakeScreenshotUntil( + kParentTappedColor, [](std::map histogram) { + // Expect parent and child background colors, with parent color > child + // color. + EXPECT_EQ(histogram[kParentBackgroundColor], 0u); + EXPECT_GT(histogram[kParentTappedColor], 0u); + EXPECT_GT(histogram[kChildBackgroundColor], 0u); + EXPECT_EQ(histogram[kChildTappedColor], 0u); + EXPECT_GT(histogram[kParentTappedColor], + histogram[kChildBackgroundColor]); + })); +} + +TEST_F(FlutterEmbedderTest, EmbeddingWithOverlay) { + LaunchParentViewInRealm({"--showOverlay"}); + + // Take screenshot until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil( + kChildBackgroundColor, [](std::map histogram) { + // Expect parent, overlay and child background colors. + // With parent color > child color and overlay color > child color. + const size_t overlay_pixel_count = OverlayPixelCount(histogram); + EXPECT_GT(histogram[kParentBackgroundColor], 0u); + EXPECT_GT(overlay_pixel_count, 0u); + EXPECT_GT(histogram[kChildBackgroundColor], 0u); + EXPECT_GT(histogram[kParentBackgroundColor], + histogram[kChildBackgroundColor]); + EXPECT_GT(overlay_pixel_count, histogram[kChildBackgroundColor]); + })); +} + +TEST_F(FlutterEmbedderTest, HittestEmbeddingWithOverlay) { + LaunchParentViewInRealm({"--showOverlay"}); + + // Take screenshot until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); + + // The bottom-left corner of the overlay is at the center of the screen, + // which is at (0, 0) in the injection coordinate space. Inject a pointer + // event just outside the overlay's bounds, and ensure that it goes to the + // embedded view. + TryInject(/* x = */ -1, /* y = */ 1); + + // Take screenshot until we see the child-view's tapped color. + ASSERT_TRUE(TakeScreenshotUntil( + kChildTappedColor, [](std::map histogram) { + // Expect parent, overlay and child background colors. + // With parent color > child color and overlay color > child color. + const size_t overlay_pixel_count = OverlayPixelCount(histogram); + EXPECT_GT(histogram[kParentBackgroundColor], 0u); + EXPECT_GT(overlay_pixel_count, 0u); + EXPECT_EQ(histogram[kChildBackgroundColor], 0u); + EXPECT_GT(histogram[kChildTappedColor], 0u); + EXPECT_GT(histogram[kParentBackgroundColor], + histogram[kChildTappedColor]); + EXPECT_GT(overlay_pixel_count, histogram[kChildTappedColor]); + })); +} + +} // namespace flutter_embedder_test diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml new file mode 100644 index 00000000000..b053b0a4cc2 --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml @@ -0,0 +1,27 @@ +{ + include: [ + "gtest_runner.shard.cml", + "sys/component/realm_builder_absolute.shard.cml", + + // This test needs both the vulkan facet and the hermetic-tier-2 facet, + // so we are forced to make it a system test. + "sys/testing/system-test.shard.cml", + ], + program: { + binary: "bin/app", + }, + offer: [ + { + // Offer capabilities needed by components in this test realm. + // Keep it minimal, describe only what's actually needed. + protocol: [ + "fuchsia.logger.LogSink", + "fuchsia.sysmem.Allocator", + "fuchsia.tracing.provider.Registry", + "fuchsia.vulkan.loader.Loader", + ], + from: "parent", + to: "#realm_builder", + }, + ], +} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml new file mode 100644 index 00000000000..4593cf2c66a --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml @@ -0,0 +1,14 @@ +{ + program: { + runner: "gtest_runner", + }, + capabilities: [ + { protocol: "fuchsia.test.Suite" }, + ], + expose: [ + { + protocol: "fuchsia.test.Suite", + from: "self", + }, + ], +} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/BUILD.gn b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/BUILD.gn new file mode 100644 index 00000000000..ceaf8299f4a --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/BUILD.gn @@ -0,0 +1,36 @@ +# 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("//build/fuchsia/sdk.gni") +import("//flutter/tools/fuchsia/dart/dart_library.gni") +import("//flutter/tools/fuchsia/flutter/flutter_component.gni") +import("//flutter/tools/fuchsia/gn-sdk/package.gni") + +dart_library("lib") { + package_name = "parent-view" + sources = [ "parent_view.dart" ] + + deps = [ + "//flutter/shell/platform/fuchsia/dart:args", + "//flutter/shell/platform/fuchsia/dart:vector_math", + "//flutter/tools/fuchsia/dart:fuchsia_services", + "//flutter/tools/fuchsia/dart:zircon", + "//flutter/tools/fuchsia/fidl:fuchsia.sys", + "//flutter/tools/fuchsia/fidl:fuchsia.ui.app", + "//flutter/tools/fuchsia/fidl:fuchsia.ui.views", + ] +} + +flutter_component("component") { + main_package = "parent-view" + component_name = "parent-view" + main_dart = "parent_view.dart" + manifest = rebase_path("meta/parent-view.cml") + deps = [ ":lib" ] +} + +fuchsia_package("package") { + package_name = "parent-view" + deps = [ ":component" ] +} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart similarity index 71% rename from engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart rename to engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart index 6dcddd2d5c6..5fd52166115 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart @@ -4,42 +4,49 @@ import 'dart:convert'; import 'dart:typed_data'; +import 'dart:io'; import 'dart:ui'; -import 'package:vector_math/vector_math_64.dart' as vector_math_64; + import 'package:args/args.dart'; -import 'package:fidl_fuchsia_sys/fidl_async.dart'; import 'package:fidl_fuchsia_ui_app/fidl_async.dart'; import 'package:fidl_fuchsia_ui_views/fidl_async.dart'; import 'package:fuchsia_services/services.dart'; +import 'package:vector_math/vector_math_64.dart' as vector_math_64; import 'package:zircon/zircon.dart'; -// TODO(richkadel): To run the test serving the runner and test packages from -// the flutter/engine package server (via -// `//flutter/tools/fuchsia/devshell/serve.sh`), change `fuchsia.com` to -// `engine`. -const _kChildAppUrl = - 'fuchsia-pkg://fuchsia.com/child-view2#meta/child-view2.cmx'; - -TestApp app; +final _argsCsvFilePath = '/config/data/args.csv'; void main(List args) { + print('parent-view: starting'); + + args = args + _GetArgsFromConfigFile(); final parser = ArgParser() ..addFlag('showOverlay', defaultsTo: false) ..addFlag('hitTestable', defaultsTo: true) - ..addFlag('focusable', defaultsTo: true); + ..addFlag('focusable', defaultsTo: true) + ..addFlag('useFlatland', defaultsTo: false); final arguments = parser.parse(args); for (final option in arguments.options) { - print('parent-view2: $option: ${arguments[option]}'); + print('parent-view: $option: ${arguments[option]}'); } - final childViewToken = _launchApp(_kChildAppUrl); - - app = TestApp( - ChildView(childViewToken), - showOverlay: arguments['showOverlay'], - hitTestable: arguments['hitTestable'], - focusable: arguments['focusable'], - ); + TestApp app; + final useFlatland = arguments['useFlatland']; + if (useFlatland) { + app = TestApp( + ChildView(_launchFlatlandChildView()), + showOverlay: arguments['showOverlay'], + hitTestable: arguments['hitTestable'], + focusable: arguments['focusable'], + ); + } else { + app = TestApp( + ChildView.gfx(_launchGfxChildView()), + showOverlay: arguments['showOverlay'], + hitTestable: arguments['hitTestable'], + focusable: arguments['focusable'], + ); + } app.run(); } @@ -64,19 +71,24 @@ class TestApp { void run() { childView.create(hitTestable, focusable, (ByteData reply) { - // The child-view2 should be attached to Scenic now. - // Ready to build the scene. + // Set up window allbacks. window.onPointerDataPacket = (PointerDataPacket packet) { for (final data in packet.data) { - if (data.change == PointerChange.up) { + if (data.change == PointerChange.down) { this._backgroundColor = _black; } } window.scheduleFrame(); }; - window.onBeginFrame = (Duration duration) { - app.beginFrame(duration); + window.onMetricsChanged = () { + window.scheduleFrame(); }; + window.onBeginFrame = (Duration duration) { + this.beginFrame(duration); + }; + + // The child view should be attached to Scenic now. + // Ready to build the scene. window.scheduleFrame(); }); } @@ -149,45 +161,16 @@ class TestApp { } } -ViewHolderToken _launchApp(String componentUrl) { - final incoming = Incoming(); - final componentController = ComponentControllerProxy(); - - final launcher = LauncherProxy(); - Incoming.fromSvcPath() - ..connectToService(launcher) - ..close(); - launcher.createComponent( - LaunchInfo( - url: componentUrl, - directoryRequest: incoming.request().passChannel(), - ), - componentController.ctrl.request(), - ); - launcher.ctrl.close(); - - ViewProviderProxy viewProvider = ViewProviderProxy(); - incoming - ..connectToService(viewProvider) - ..close(); - - final viewTokens = EventPairPair(); - assert(viewTokens.status == ZX.OK); - final viewHolderToken = ViewHolderToken(value: viewTokens.first); - final viewToken = ViewToken(value: viewTokens.second); - - viewProvider.createView(viewToken.value, null, null); - viewProvider.ctrl.close(); - - return viewHolderToken; -} - class ChildView { - - final ViewHolderToken viewToken; + final ViewHolderToken viewHolderToken; + final ViewportCreationToken viewportCreationToken; final int viewId; - ChildView(this.viewToken) : viewId = viewToken.value.handle.handle { + ChildView(this.viewportCreationToken) : viewHolderToken = null, viewId = viewportCreationToken.value.handle.handle { + assert(viewId != null); + } + + ChildView.gfx(this.viewHolderToken) : viewportCreationToken = null, viewId = viewHolderToken.value.handle.handle { assert(viewId != null); } @@ -227,3 +210,49 @@ class ChildView { callback); } } + +ViewportCreationToken _launchFlatlandChildView() { + ViewProviderProxy viewProvider = ViewProviderProxy(); + Incoming.fromSvcPath() + ..connectToService(viewProvider) + ..close(); + + final viewTokens = ChannelPair(); + assert(viewTokens.status == ZX.OK); + final viewportCreationToken = ViewportCreationToken(value: viewTokens.first); + final viewCreationToken = ViewCreationToken(value: viewTokens.second); + + final createViewArgs = CreateView2Args(viewCreationToken: viewCreationToken); + viewProvider.createView2(createViewArgs); + viewProvider.ctrl.close(); + + return viewportCreationToken; +} + +ViewHolderToken _launchGfxChildView() { + ViewProviderProxy viewProvider = ViewProviderProxy(); + Incoming.fromSvcPath() + ..connectToService(viewProvider) + ..close(); + + final viewTokens = EventPairPair(); + assert(viewTokens.status == ZX.OK); + final viewHolderToken = ViewHolderToken(value: viewTokens.first); + final viewToken = ViewToken(value: viewTokens.second); + + viewProvider.createView(viewToken.value, null, null); + viewProvider.ctrl.close(); + + return viewHolderToken; +} + +List _GetArgsFromConfigFile() { + List args; + final f = File(_argsCsvFilePath); + if (!f.existsSync()) { + return List.empty(); + } + final fileContentCsv = f.readAsStringSync(); + args = fileContentCsv.split('\n'); + return args; +} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml new file mode 100644 index 00000000000..aea9b8bc24d --- /dev/null +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml @@ -0,0 +1,33 @@ +{ + include: [ "syslog/client.shard.cml" ], + program: { + data: "data/parent-view", + + // Always use the jit runner for now. + // TODO(fxbug.dev/106577): Implement manifest merging build rules for V2 components. + runner: "flutter_jit_runner", + }, + capabilities: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + }, + ], + use: [ + { + protocol: [ + "fuchsia.ui.app.ViewProvider", + ], + }, + { + directory: "config-data", + rights: [ "r*" ], + path: "/config/data", + }, + ], + expose: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + from: "self", + }, + ], +} diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/pubspec.yaml b/engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/pubspec.yaml similarity index 100% rename from engine/src/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/pubspec.yaml rename to engine/src/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/pubspec.yaml diff --git a/engine/src/flutter/testing/fuchsia/test_suites.yaml b/engine/src/flutter/testing/fuchsia/test_suites.yaml index 8dcbc8a9e2e..86630bdb734 100644 --- a/engine/src/flutter/testing/fuchsia/test_suites.yaml +++ b/engine/src/flutter/testing/fuchsia/test_suites.yaml @@ -1,15 +1,13 @@ # This configuration file specifies several test suites with their package and # test command for femu_test.py. -# Legacy Component Framework v1 components. -- test_command: run-test-component fuchsia-pkg://fuchsia.com/flutter-embedder-test2#meta/flutter-embedder-test2.cmx - packages: - - flutter-embedder-test2-0.far - - gen/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child-view2/child-view2.far - - gen/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent-view2/parent-view2.far - - flutter_jit_runner-0.far - # v2 components. +- test_command: run-test-suite fuchsia-pkg://fuchsia.com/flutter-embedder-test#meta/flutter-embedder-test.cm + packages: + - flutter-embedder-test-0.far + - oot_flutter_jit_runner-0.far + - gen/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/child-view/child-view.far + - gen/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/parent-view/parent-view.far - test_command: run-test-suite fuchsia-pkg://fuchsia.com/dart_runner_tests#meta/dart_runner_tests.cm package: dart_runner_tests-0.far - test_command: run-test-suite fuchsia-pkg://fuchsia.com/flutter_runner_tests#meta/flutter_runner_tests.cm diff --git a/engine/src/flutter/tools/fuchsia/fuchsia_archive.gni b/engine/src/flutter/tools/fuchsia/fuchsia_archive.gni index c0cc730973d..a30d392c526 100644 --- a/engine/src/flutter/tools/fuchsia/fuchsia_archive.gni +++ b/engine/src/flutter/tools/fuchsia/fuchsia_archive.gni @@ -36,6 +36,8 @@ template("_compile_cml") { "--output", rebase_path(invoker.output, root_build_dir), "--includepath", + rebase_path("$fuchsia_sdk/pkg/", root_build_dir), + "--includepath", get_path_info(invoker.manifest, "dir"), "--includepath", rebase_path("//"), @@ -258,42 +260,66 @@ template("fuchsia_archive") { # cmx_file (optional): # A path to the .cmx file for the test archive. # If not defined, a generated .cml file for the test archive will be used instead. +# cml_file (optional): +# The path to the V2 component manifest (.cml file) for the test archive's component. +# Should include the file extension. +# If not defined, a generated .cml file for the test archive will be used instead. # libraries (optional): # Paths to .so libraries that should be dynamically linked to the binary. # resources (optional): # Files that should be placed into the `data/` directory of the archive. template("fuchsia_test_archive") { assert(defined(invoker.deps), "package must define deps") - - # Interpolate test_suite.cml template with the test suite's name. - test_suite = target_name - interpolate_cml_target = "${test_suite}_interpolate_cml" - generated_cml_file = "$root_out_dir/$test_suite.cml" - action(interpolate_cml_target) { - testonly = true - script = "//flutter/tools/fuchsia/interpolate_test_suite.py" - sources = [ "//flutter/testing/fuchsia/meta/test_suite.cml" ] - args = [ - "--input", - rebase_path("//flutter/testing/fuchsia/meta/test_suite.cml"), - "--test-suite", - test_suite, - "--output", - rebase_path(generated_cml_file), - ] - outputs = [ generated_cml_file ] + _deps = [] + if (defined(invoker.deps)) { + _deps += invoker.deps } - far_base_dir = "$root_out_dir/${target_name}_far" + if (defined(invoker.cml_file)) { + _far_base_dir = "$root_out_dir/${target_name}_far" + _cml_file_name = get_path_info(invoker.cml_file, "name") + _compile_cml_target = "${target_name}_${_cml_file_name}_compile_cml" - # Compile the resulting interpolated test suite's cml. - compile_test_suite_cml_target = "${test_suite}_test_suite_compile_cml" - _compile_cml(compile_test_suite_cml_target) { - testonly = true - deps = [ ":$interpolate_cml_target" ] + _compile_cml(_compile_cml_target) { + forward_variables_from(invoker, [ "testonly" ]) - manifest = generated_cml_file - output = "$far_base_dir/meta/${test_suite}.cm" + manifest = invoker.cml_file + output = "$_far_base_dir/meta/${_cml_file_name}.cm" + } + _deps += [ ":$_compile_cml_target" ] + } else { + # Interpolate test_suite.cml template with the test suite's name. + test_suite = target_name + interpolate_cml_target = "${test_suite}_interpolate_cml" + generated_cml_file = "$root_out_dir/$test_suite.cml" + action(interpolate_cml_target) { + testonly = true + script = "//flutter/tools/fuchsia/interpolate_test_suite.py" + sources = [ "//flutter/testing/fuchsia/meta/test_suite.cml" ] + args = [ + "--input", + rebase_path("//flutter/testing/fuchsia/meta/test_suite.cml"), + "--test-suite", + test_suite, + "--output", + rebase_path(generated_cml_file), + ] + outputs = [ generated_cml_file ] + } + + far_base_dir = "$root_out_dir/${target_name}_far" + + # Compile the resulting interpolated test suite's cml. + compile_test_suite_cml_target = "${test_suite}_test_suite_compile_cml" + _compile_cml(compile_test_suite_cml_target) { + testonly = true + deps = [ ":$interpolate_cml_target" ] + + manifest = generated_cml_file + output = "$far_base_dir/meta/${test_suite}.cm" + } + + _deps += [ ":$compile_test_suite_cml_target" ] } _fuchsia_archive(target_name) { @@ -309,15 +335,6 @@ template("fuchsia_test_archive") { libraries += invoker.libraries } - # TODO(fxbug.dev/79873): Only cfv2 components should be allowed after - # FakeScenic is available. - if (defined(invoker.cmx_file)) { - cmx_file = invoker.cmx_file - - # Don't include cml files. - deps = invoker.deps - } else { - deps = invoker.deps + [ ":$compile_test_suite_cml_target" ] - } + deps = _deps } }