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:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -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",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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" ]
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
},
|
||||
],
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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",
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user