Add test view for touch-input-test (flutter/engine#36879)

This PR adds a touch-input-view for use in the touch-input-test to validate touch input. The view will be attached to the test, and a touch event will be injected. The test asserts that a correct response is sent back from the view (the location of the touch as well as the name of the view).
This commit is contained in:
Erik
2022-10-20 13:26:41 -04:00
committed by GitHub
parent 73ad92dbbe
commit 0e283234ab
14 changed files with 375 additions and 239 deletions

View File

@@ -34,11 +34,11 @@ executable("touch-input-test-bin") {
"$fuchsia_sdk_root/fidl:fuchsia.tracing.provider",
"$fuchsia_sdk_root/fidl:fuchsia.ui.app",
"$fuchsia_sdk_root/fidl:fuchsia.ui.input",
"$fuchsia_sdk_root/fidl:fuchsia.ui.pointerinjector",
"$fuchsia_sdk_root/fidl:fuchsia.ui.policy",
"$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/fidl:fuchsia.ui.test.scene",
"$fuchsia_sdk_root/fidl:fuchsia.web",
"$fuchsia_sdk_root/pkg:async",
"$fuchsia_sdk_root/pkg:async-loop-testing",
@@ -46,6 +46,7 @@ executable("touch-input-test-bin") {
"$fuchsia_sdk_root/pkg:scenic_cpp",
"$fuchsia_sdk_root/pkg:sys_component_cpp_testing",
"$fuchsia_sdk_root/pkg:zx",
"touch-input-view:package",
"//build/fuchsia/fidl:fuchsia.ui.gfx",
"//flutter/fml",
"//flutter/shell/platform/fuchsia/flutter/tests/integration/utils:portable_ui_test",
@@ -58,7 +59,6 @@ fuchsia_test_archive("touch-input-test") {
testonly = true
deps = [
":touch-input-test-bin",
"one-flutter:package",
# "OOT" copies of the runners used by tests, to avoid conflicting with the
# runners in the base fuchsia image.

View File

@@ -0,0 +1,76 @@
# touch-input
`touch-input-test` exercises touch through a child view (in this case, the `touch-input-view` Dart component) and asserting
the precise location of the touch event. We do this by attaching the child view, injecting touch, and validating that the view
reports the touch event back with the correct coordinates.
```shell
Injecting the tap event
[touch-input-test.cm] INFO: [portable_ui_test.cc(193)] Injecting tap at (-500, -500)
View receives the event
[flutter_jit_runner] INFO: touch-input-view.cm(flutter): touch-input-view received tap: PointerData(embedderId: 0, timeStamp: 0:01:03.623259,
change: PointerChange.add, kind: PointerDeviceKind.touch, signalKind: PointerSignalKind.none, device: -4294967295, pointerIdentifier: 0,
physicalX: 319.99998331069946, physicalY: 199.99999284744263, physicalDeltaX: 0.0, physicalDeltaY: 0.0, buttons: 0, synthesized: false,
pressure: 0.0, pressureMin: 0.0, pressureMax: 0.0, distance: 0.0, distanceMax: 0.0, size: 0.0, radiusMajor: 0.0, radiusMinor: 0.0,
radiusMin: 0.0, radiusMax: 0.0, orientation: 0.0, tilt: 0.0, platformData: 0, scrollDeltaX: 0.0, scrollDeltaY: 0.0, panX: 0.0, panY: 0.0,
panDeltaX: 0.0, panDeltaY: 0.0, scale: 0.0, rotation: 0.0)
Successfully received response from view
[touch-input-test.cm] INFO: [touch-input-test.cc(162)] Received ReportTouchInput event
[touch-input-test.cm] INFO: [touch-input-test.cc(255)] Expecting event for component touch-input-view at (320, 200)
[touch-input-test.cm] INFO: [touch-input-test.cc(257)] Received event for component touch-input-view at (320, 200), accounting for pixel scale of 1
```
Some interesting details (thanks to abrusher@):
There exists two coordinate spaces within our testing realm. The first is `touch-input-view`'s "logical" coordinate space. This
is determined based on `touch-input-view`'s size and is the space in which it sees incoming events. The second is the "injector"
coordinate space, which spans [-1000, 1000] on both axes.
The size/position of a view doesn't always match the bounds of a display exactly. As a result, Scenic has a separate coordinate space
to specify the location at which to inject a touch event. This is always fixed to the display bounds. Scenic knows how to map this
coordinate space onto the client view's space.
For example, if we inject at (-500, -500) `touch-input-view` will see a touch event at the middle of the upper-left quadrant of the screen.
## Running the Test
Reference the Flutter integration test [documentation](https://github.com/flutter/engine/blob/main/shell/platform/fuchsia/flutter/tests/integration/README.md) at //flutter/shell/platform/fuchsia/flutter/tests/integration/README.md
## Playing around with `touch-input-view`
Build Fuchsia with `workstation_eng.qemu-x64`
```shell
fx set workstation_eng.qemu-x64 --with-base=//src/session/bin/session_manager && fx build
```
Build flutter/engine
```shell
$ENGINE_DIR/flutter/tools/gn --fuchsia --no-lto && ninja -C $ENGINE_DIR/out/fuchsia_debug_x64 flutter/shell/platform/fuchsia/flutter/tests/
integration/touch_input:tests
```
Start a Fuchsia package server
```shell
cd "$FUCHSIA_DIR"
fx serve
```
Publish `touch-input-view`
```shell
$FUCHSIA_DIR/.jiri_root/bin/fx pm publish -a -repo $FUCHSIA_DIR/$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files -f $ENGINE_DIR/out/
fuchsia_debug_x64/gen/flutter/shell/platform/fuchsia/flutter/tests/integration/touch-input/touch-input-view/touch-input-view/touch-input-view.far
```
Launch Fuchsia emulator in a graphical environment
```shell
ffx emu start
```
**Before proceeding, make sure you have successfully completed the "Set a Password" screen**
Add `touch-input-view`
```shell
ffx session add fuchsia-pkg://fuchsia.com/touch-input-view#meta/touch-input-view.cm
```

View File

@@ -6,9 +6,6 @@
"gtest_runner.shard.cml",
"sys/component/realm_builder_absolute.shard.cml",
"syslog/client.shard.cml",
"vulkan/client.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",
@@ -16,11 +13,17 @@
program: {
binary: "bin/app",
},
use: [
{
protocol: [
"fuchsia.ui.test.input.TouchInputListener",
]
}
],
offer: [
{
// Offer capabilities needed by components in this test realm.
// Keep it minimal, describe only what's actually needed.
// TODO(fxbug.dev/81446): Remove this list.
protocol: [
"fuchsia.kernel.RootJobForInspect",
"fuchsia.kernel.Stats",
@@ -30,9 +33,21 @@
"fuchsia.tracing.provider.Registry",
"fuchsia.ui.input.ImeService",
"fuchsia.vulkan.loader.Loader",
"fuchsia.ui.scenic.Scenic",
"fuchsia.ui.test.input.TouchInputListener",
"fuchsia.intl.PropertyProvider",
"fuchsia.posix.socket.Provider",
"fuchsia.ui.pointerinjector.Registry",
],
from: "parent",
to: "#realm_builder",
},
{
directory: "pkg",
subdir: "config",
as: "config-data",
from: "framework",
to: "#realm_builder",
},
],
}

View File

@@ -1,18 +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.
// TODO(https://fxbug.dev/84961): Fix null safety and remove this language version.
// @dart=2.9
import 'dart:convert';
import 'dart:typed_data';
import 'dart:io';
import 'dart:ui';
import 'package:fidl_fuchsia_ui_test_input/fidl_async.dart';
import 'package:fuchsia_services/services.dart';
int main() {
print('touch-input-view: starting');
}

View File

@@ -1,56 +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.
{
children: [
{
name: "flutter_jit_runner",
url: "fuchsia-pkg://fuchsia.com/flutter_jit_runner#meta/flutter_jit_runner.cm",
},
{
name: "one_flutter_view",
url: "#meta/one-flutter-view.cm",
environment: "#one_flutter_view_env",
},
],
offer: [
{
protocol: [
"fuchsia.logger.LogSink",
"fuchsia.sysmem.Allocator",
"fuchsia.tracing.provider.Registry",
"fuchsia.ui.scenic.Scenic",
"fuchsia.vulkan.loader.Loader",
],
from: "parent",
to: [
"#flutter_jit_runner",
"#one_flutter_view",
],
},
{
protocol: [ "fuchsia.ui.test.input.TouchInputListener" ],
from: "parent",
to: "#one_flutter_view",
},
],
expose: [
{
protocol: [ "fuchsia.ui.app.ViewProvider" ],
from: "#one_flutter_view",
to: "parent",
},
],
environments: [
{
name: "one_flutter_view_env",
extends: "realm",
runners: [
{
runner: "flutter_jit_runner",
from: "#flutter_jit_runner",
},
],
},
],
}

View File

@@ -123,52 +123,43 @@ using component_testing::Route;
using fuchsia_test_utils::PortableUITest;
using RealmBuilder = component_testing::RealmBuilder;
// Alias for Component child name as provided to Realm Builder.
using ChildName = std::string;
// Alias for Component Legacy URL as provided to Realm Builder.
using LegacyUrl = std::string;
// Max timeout in failure cases.
// Set this as low as you can that still works across all test platforms.
constexpr zx::duration kTimeout = zx::min(5);
constexpr auto kMockResponseListener = "response_listener";
enum class TapLocation { kTopLeft, kTopRight };
// Combines all vectors in `vecs` into one.
template <typename T>
std::vector<T> merge(std::initializer_list<std::vector<T>> vecs) {
std::vector<T> result;
for (auto v : vecs) {
result.insert(result.end(), v.begin(), v.end());
}
return result;
}
constexpr auto kMockTouchInputListener = "touch_input_listener";
constexpr auto kMockTouchInputListenerRef = ChildRef{kMockTouchInputListener};
constexpr auto kTouchInputView = "touch-input-view";
constexpr auto kTouchInputViewRef = ChildRef{kTouchInputView};
constexpr auto kTouchInputViewUrl =
"fuchsia-pkg://fuchsia.com/touch-input-view#meta/touch-input-view.cm";
bool CompareDouble(double f0, double f1, double epsilon) {
return std::abs(f0 - f1) <= epsilon;
}
// // This component implements the test.touch.ResponseListener protocol
// // and the interface for a RealmBuilder LocalComponent. A LocalComponent
// // is a component that is implemented here in the test, as opposed to
// elsewhere
// // in the system. When it's inserted to the realm, it will act like a proper
// // component. This is accomplished, in part, because the realm_builder
// // library creates the necessary plumbing. It creates a manifest for the
// // component and routes all capabilities to and from it.
class ResponseListenerServer
// This component implements the TouchInput protocol
// and the interface for a RealmBuilder LocalComponent. A LocalComponent
// is a component that is implemented here in the test, as opposed to
// elsewhere in the system. When it's inserted to the realm, it will act
// like a proper component. This is accomplished, in part, because the
// realm_builder library creates the necessary plumbing. It creates a manifest
// for the component and routes all capabilities to and from it.
// LocalComponent:
// https://fuchsia.dev/fuchsia-src/development/testing/components/realm_builder#mock-components
class TouchInputListenerServer
: public fuchsia::ui::test::input::TouchInputListener,
public LocalComponent {
public:
explicit ResponseListenerServer(async_dispatcher_t* dispatcher)
explicit TouchInputListenerServer(async_dispatcher_t* dispatcher)
: dispatcher_(dispatcher) {}
// |fuchsia::ui::test::input::TouchInputListener|
void ReportTouchInput(
fuchsia::ui::test::input::TouchInputListenerReportTouchInputRequest
request) override {
FML_LOG(INFO) << "Received ReportTouchInput event";
events_received_.push_back(std::move(request));
}
@@ -176,9 +167,9 @@ class ResponseListenerServer
// When the component framework requests for this component to start, this
// method will be invoked by the realm_builder library.
void Start(std::unique_ptr<LocalComponentHandles> local_handles) override {
FML_LOG(INFO) << "Starting TouchInputListenerServer";
// When this component starts, add a binding to the
// test.touch.ResponseListener protocol to this component's outgoing
// directory.
// protocol to this component's outgoing directory.
ASSERT_EQ(ZX_OK, local_handles->outgoing()->AddPublicService(
fidl::InterfaceRequestHandler<
fuchsia::ui::test::input::TouchInputListener>(
@@ -242,45 +233,12 @@ class FlutterTapTest : public PortableUITest,
RegisterTouchScreen();
}
// Routes needed to setup Flutter client.
static std::vector<Route> GetFlutterRoutes(ChildRef target) {
return {
{.capabilities = {Protocol{
fuchsia::ui::test::input::TouchInputListener::Name_}},
.source = ChildRef{kMockResponseListener},
.targets = {target}},
{.capabilities = {Protocol{fuchsia::logger::LogSink::Name_},
Protocol{fuchsia::sysmem::Allocator::Name_},
Protocol{
fuchsia::tracing::provider::Registry::Name_}},
.source = ParentRef(),
.targets = {target}},
{.capabilities = {Protocol{fuchsia::ui::scenic::Scenic::Name_}},
.source = kTestUIStackRef,
.targets = {target}},
};
}
std::vector<Route> GetTestRoutes() {
return merge(
{GetFlutterRoutes(ChildRef{kFlutterRealm}),
{
{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}},
.source = ChildRef{kFlutterRealm},
.targets = {ParentRef()}},
}});
}
std::vector<std::pair<ChildName, LegacyUrl>> GetTestV2Components() {
return {
std::make_pair(kFlutterRealm, kFlutterRealmUrl),
};
};
bool LastEventReceivedMatches(float expected_x,
float expected_y,
std::string component_name) {
const auto& events_received = response_listener_server_->events_received();
const auto& events_received =
touch_input_listener_server_->events_received();
if (events_received.empty()) {
return false;
}
@@ -305,75 +263,50 @@ class FlutterTapTest : public PortableUITest,
last_event.component_name() == component_name;
}
void InjectInput(TapLocation tap_location) {
// The /config/data/display_rotation (90) specifies how many degrees to
// rotate the presentation child view, counter-clockwise, in a
// right-handed coordinate system. Thus, the user observes the child
// view to rotate *clockwise* by that amount (90).
//
// Hence, a tap in the center of the display's top-right quadrant is
// observed by the child view as a tap in the center of its top-left
// quadrant.
auto touch = std::make_unique<fuchsia::ui::input::TouchscreenReport>();
switch (tap_location) {
case TapLocation::kTopLeft:
// center of top right quadrant -> ends up as center of top left
// quadrant
InjectTap(/* x = */ 500, /* y = */ -500);
break;
case TapLocation::kTopRight:
// center of bottom right quadrant -> ends up as center of top right
// quadrant
InjectTap(/* x = */ 500, /* y = */ 500);
break;
default:
FML_CHECK(false) << "Received invalid TapLocation";
}
}
// Guaranteed to be initialized after SetUp().
uint32_t display_width() const { return display_width_; }
uint32_t display_height() const { return display_height_; }
static constexpr auto kFlutterRealm = "flutter-realm";
static constexpr auto kFlutterRealmUrl =
"fuchsia-pkg://fuchsia.com/one-flutter#meta/one-flutter-realm.cm";
private:
void ExtendRealm() override {
// Key part of service setup: have this test component vend the
// |ResponseListener| service in the constructed realm.
response_listener_server_ =
std::make_unique<ResponseListenerServer>(dispatcher());
realm_builder()->AddLocalChild(kMockResponseListener,
response_listener_server_.get());
// |TouchInputListener| service in the constructed realm.
touch_input_listener_server_ =
std::make_unique<TouchInputListenerServer>(dispatcher());
realm_builder()->AddLocalChild(kMockTouchInputListener,
touch_input_listener_server_.get());
realm_builder()->AddChild(kTouchInputView, kTouchInputViewUrl,
component_testing::ChildOptions{
.environment = kFlutterRunnerEnvironment,
});
// Route the TouchInput protocol capability to the Dart component
realm_builder()->AddRoute(
Route{.capabilities = {Protocol{
fuchsia::ui::test::input::TouchInputListener::Name_}},
.source = kMockTouchInputListenerRef,
.targets = {kFlutterJitRunnerRef, kTouchInputViewRef}});
realm_builder()->AddRoute(
{.capabilities = {Protocol{fuchsia::ui::scenic::Scenic::Name_}},
.source = kTestUIStackRef,
.targets = {ParentRef()}});
// Add components specific for this test case to the realm.
for (const auto& [name, component] : GetTestV2Components()) {
realm_builder()->AddChild(name, component);
}
// Add the necessary routing for each of the extra components added
// above.
for (const auto& route : GetTestRoutes()) {
realm_builder()->AddRoute(route);
}
Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}},
.source = kTouchInputViewRef,
.targets = {ParentRef()}});
}
ParamType GetTestUIStackUrl() override { return GetParam(); };
std::unique_ptr<ResponseListenerServer> response_listener_server_;
std::unique_ptr<TouchInputListenerServer> touch_input_listener_server_;
fuchsia::ui::scenic::ScenicPtr scenic_;
uint32_t display_width_ = 0;
uint32_t display_height_ = 0;
};
// Makes use of gtest's parameterized testing, allowing us
// to test different combinations of test-ui-stack + runners. Currently, there
// is just one combination. Documentation:
// http://go/gunitadvanced#value-parameterized-tests
INSTANTIATE_TEST_SUITE_P(
FlutterTapTestParameterized,
FlutterTapTest,
@@ -387,12 +320,18 @@ TEST_P(FlutterTapTest, FlutterTap) {
LaunchClient();
FML_LOG(INFO) << "Client launched";
InjectInput(TapLocation::kTopLeft);
// touch-input-view logical coordinate space doesn't match the fake touch
// screen injector's coordinate space, which spans [-1000, 1000] on both axes.
// Scenic handles figuring out where in the coordinate space
// to inject a touch event (this is fixed to a display's bounds).
InjectTap(-500, -500);
// For a (-500 [x], -500 [y]) tap, we expect a touch event in the middle of
// the upper-left quadrant of the screen.
RunLoopUntil([this] {
return LastEventReceivedMatches(
/*expected_x=*/static_cast<float>(display_height()) / 4.f,
/*expected_y=*/static_cast<float>(display_width()) / 4.f,
/*component_name=*/"one-flutter");
/*expected_x=*/static_cast<float>(display_width() / 4.0f),
/*expected_y=*/static_cast<float>(display_height() / 4.0f),
/*component_name=*/"touch-input-view");
});
}

View File

@@ -9,9 +9,11 @@ import("//flutter/tools/fuchsia/gn-sdk/component.gni")
import("//flutter/tools/fuchsia/gn-sdk/package.gni")
dart_library("lib") {
package_name = "one-flutter"
sources = [ "one-flutter.dart" ]
package_name = "touch-input-view"
sources = [ "touch-input-view.dart" ]
deps = [
"//flutter/shell/platform/fuchsia/dart:args",
"//flutter/tools/fuchsia/dart:fuchsia_services",
"//flutter/tools/fuchsia/dart:zircon",
"//flutter/tools/fuchsia/fidl:fuchsia.ui.test.input",
@@ -20,24 +22,17 @@ dart_library("lib") {
flutter_component("component") {
testonly = true
component_name = "one-flutter-view"
manifest = rebase_path("meta/one-flutter-view.cml")
main_package = "one-flutter"
main_dart = "one-flutter.dart"
deps = [ ":lib" ]
}
component_name = "touch-input-view"
manifest = rebase_path("meta/touch-input-view.cml")
main_package = "touch-input-view"
main_dart = "touch-input-view.dart"
fuchsia_component("realm") {
testonly = true
manifest = "meta/one-flutter-realm.cml"
manifest_output_name = "one-flutter-realm.cml"
deps = [ ":component" ]
deps = [ ":lib" ]
}
fuchsia_package("package") {
testonly = true
deps = [
":component",
":realm",
]
package_name = "touch-input-view"
deps = [ ":component" ]
}

View File

@@ -0,0 +1,115 @@
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(https://fxbug.dev/84961): Fix null safety and remove this language version.
// @dart=2.9
import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui';
import 'package:args/args.dart';
import 'package:fidl_fuchsia_ui_test_input/fidl_async.dart' as test_touch;
import 'package:fuchsia_services/services.dart';
import 'package:zircon/zircon.dart';
void main() {
print('Launching two-flutter view');
MyApp app = MyApp();
app.run();
}
class MyApp {
static const _red = Color.fromARGB(255, 244, 67, 54);
static const _orange = Color.fromARGB(255, 255, 152, 0);
static const _yellow = Color.fromARGB(255, 255, 235, 59);
static const _green = Color.fromARGB(255, 76, 175, 80);
static const _blue = Color.fromARGB(255, 33, 150, 143);
static const _purple = Color.fromARGB(255, 156, 39, 176);
final List<Color> _colors = <Color>[
_red,
_orange,
_yellow,
_green,
_blue,
_purple,
];
// Each tap will increment the counter, we then determine what color to choose
int _touchCounter = 0;
final _responseListener = test_touch.TouchInputListenerProxy();
void run() {
// Set up window callbacks.
window.onPointerDataPacket = (PointerDataPacket packet) {
this.pointerDataPacket(packet);
};
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();
}
void beginFrame(Duration duration) {
// Convert physical screen size of device to values
final pixelRatio = window.devicePixelRatio;
final size = window.physicalSize / pixelRatio;
final physicalBounds = Offset.zero & size * pixelRatio;
// Set up Canvas that uses the screen size
final recorder = PictureRecorder();
final canvas = Canvas(recorder, physicalBounds);
canvas.scale(pixelRatio, pixelRatio);
// Draw something
// Color of the screen is set initially to the first value in _colors
// Incrementing _touchCounter will change screen color
final paint = Paint()..color = _colors[_touchCounter % _colors.length];
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
// Build the scene
final picture = recorder.endRecording();
final sceneBuilder = SceneBuilder()
..pushClipRect(physicalBounds)
..addPicture(Offset.zero, picture)
..pop();
window.render(sceneBuilder.build());
}
void pointerDataPacket(PointerDataPacket packet) async {
int nowNanos = System.clockGetMonotonic();
for (PointerData data in packet.data) {
print('touch-input-view received tap: ${data.toStringFull()}');
if (data.change == PointerChange.down) {
_touchCounter++;
}
if (data.change == PointerChange.down || data.change == PointerChange.move) {
Incoming.fromSvcPath()
..connectToService(_responseListener)
..close();
_respond(test_touch.TouchInputListenerReportTouchInputRequest(
localX: data.physicalX,
localY: data.physicalY,
timeReceived: nowNanos,
componentName: 'touch-input-view',
));
}
}
window.scheduleFrame();
}
void _respond(test_touch.TouchInputListenerReportTouchInputRequest request) async {
print('touch-input-view reporting touch input to TouchInputListener');
await _responseListener.reportTouchInput(request);
}
}

View File

@@ -2,12 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
{
include: [
"sys/component/realm_builder_absolute.shard.cml",
"syslog/client.shard.cml",
],
include: [ "syslog/client.shard.cml" ],
program: {
data: "data/one-flutter",
data: "data/touch-input-view",
// Always use the jit runner for now.
// TODO(fxbug.dev/106577): Implement manifest merging build rules for V2 components.
@@ -18,6 +15,12 @@
protocol: [ "fuchsia.ui.app.ViewProvider" ],
},
],
expose: [
{
protocol: [ "fuchsia.ui.app.ViewProvider" ],
from: "self",
},
],
use: [
{
protocol: [
@@ -26,13 +29,7 @@
"fuchsia.ui.scenic.Scenic",
"fuchsia.ui.test.input.TouchInputListener",
"fuchsia.vulkan.loader.Loader",
],
},
],
expose: [
{
protocol: [ "fuchsia.ui.app.ViewProvider" ],
from: "self",
},
],
]
}
]
}

View File

@@ -0,0 +1,8 @@
# 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.
name: one-flutter
environment:
sdk: '>=2.12.0 <3.0.0'

View File

@@ -50,7 +50,13 @@ source_set("portable_ui_test") {
deps = [
":check_view",
"$fuchsia_sdk_root/fidl:fuchsia.ui.app",
"$fuchsia_sdk_root/fidl:fuchsia.ui.input",
"$fuchsia_sdk_root/fidl:fuchsia.ui.observation.geometry",
"$fuchsia_sdk_root/fidl:fuchsia.ui.policy",
"$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-loop-testing",
"$fuchsia_sdk_root/pkg:sys_component_cpp_testing",
"//flutter/fml",

View File

@@ -18,6 +18,7 @@ namespace fuchsia_test_utils {
namespace {
// Types imported for the realm_builder library.
using component_testing::ChildOptions;
using component_testing::ChildRef;
using component_testing::ParentRef;
using component_testing::Protocol;
@@ -39,10 +40,36 @@ void PortableUITest::SetUp() {
void PortableUITest::SetUpRealmBase() {
FML_LOG(INFO) << "Setting up realm base";
// Add Flutter JIT runner as a child of the RealmBuilder
realm_builder_.AddChild(kFlutterJitRunner, kFlutterJitRunnerUrl);
// Add environment providing the Flutter JIT runner
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();
// Add Flutter JIT runner to the environment
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));
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, GetTestUIStackUrl());
// Route base system services to flutter and the test UI stack.
// // Route base system services to flutter and the test UI stack.
realm_builder_.AddRoute(
Route{.capabilities =
{
@@ -50,18 +77,29 @@ void PortableUITest::SetUpRealmBase() {
Protocol{fuchsia::sys::Environment::Name_},
Protocol{fuchsia::sysmem::Allocator::Name_},
Protocol{fuchsia::tracing::provider::Registry::Name_},
Protocol{fuchsia::ui::input::ImeService::Name_},
Protocol{kPointerInjectorRegistryName},
Protocol{kPosixSocketProviderName},
Protocol{kVulkanLoaderServiceName},
Protocol{kProfileProviderServiceName},
component_testing::Directory{"config-data"},
},
.source = ParentRef{},
.targets = {kTestUIStackRef}});
.source = ParentRef(),
.targets = {kFlutterJitRunnerRef, kTestUIStackRef}});
// Capabilities routed 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::test::scene::Controller::Name_},
Protocol{fuchsia::ui::scenic::Scenic::Name_}},
.source = kTestUIStackRef,
.targets = {ParentRef{}}});
.targets = {ParentRef()}});
// 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}});
}
void PortableUITest::ProcessViewGeometryResponse(

View File

@@ -6,6 +6,10 @@
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_INTEGRATION_UTILS_PORTABLE_UI_TEST_H_
#include <fuchsia/sysmem/cpp/fidl.h>
#include <fuchsia/ui/app/cpp/fidl.h>
#include <fuchsia/ui/input/cpp/fidl.h>
#include <fuchsia/ui/policy/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <fuchsia/ui/test/input/cpp/fidl.h>
#include <fuchsia/ui/test/scene/cpp/fidl.h>
#include <lib/async-loop/testing/cpp/real_loop.h>
@@ -23,11 +27,22 @@ class PortableUITest : public ::loop_fixture::RealLoop {
// we must encode the names manually here.
static constexpr auto kVulkanLoaderServiceName =
"fuchsia.vulkan.loader.Loader";
static constexpr auto kProfileProviderServiceName =
"fuchsia.sheduler.ProfileProvider";
static constexpr auto kPosixSocketProviderName =
"fuchsia.posix.socket.Provider";
static constexpr auto kPointerInjectorRegistryName =
"fuchsia.ui.pointerinjector.Registry";
// The naming and references used by Realm Builder
static constexpr auto kTestUIStack = "ui";
static constexpr auto kTestUIStackRef =
component_testing::ChildRef{kTestUIStack};
static constexpr auto kFlutterJitRunner = "flutter_jit_runner";
static constexpr auto kFlutterJitRunnerRef =
component_testing::ChildRef{kFlutterJitRunner};
static constexpr auto kFlutterJitRunnerUrl =
"fuchsia-pkg://fuchsia.com/oot_flutter_jit_runner#meta/"
"flutter_jit_runner.cm";
static constexpr auto kFlutterRunnerEnvironment = "flutter_runner_env";
void SetUp();
@@ -59,7 +74,8 @@ class PortableUITest : public ::loop_fixture::RealLoop {
// Configures the test-specific component topology.
virtual void ExtendRealm() = 0;
// Returns the test-ui-stack component url to use in this test.
// Returns the test-specific test-ui-stack component url to use.
// Usually overriden to return a value from gtest GetParam()
virtual std::string GetTestUIStackUrl() = 0;
// Helper method to watch watch for view geometry updates.

View File

@@ -47,6 +47,8 @@ shift # past argument
# Ensure we know about the test and look up its packages.
# The first package listed here should be the main package for the test
# (the package that gets passed to `ffx test run`).
# Note: You do not need to include oot_flutter_jit_runner-0.far, the script
# automatically publishes it.
test_packages=
case $test_name in
embedder)
@@ -57,6 +59,9 @@ case $test_name in
engine-warning "This test currently hangs because the Dart view hasn't been implemented yet. https://fxbug.dev/107917"
test_packages=("text-input-test-0.far" "text-input-view.far")
;;
touch-input)
test_packages=("touch-input-test-0.far" "touch-input-view.far")
;;
*)
engine-error "Unknown test name $test_name. You may need to add it to $0"
exit 1