forked from firka/flutter
[fuchsia] embedding-flutter test (flutter/engine#37052)
* Add embedding-flutter test * Lint CC files * GN formatting * Remove changes to embedder * Minor refactor * Remove unused dependencies * Lint CC files * Remove comments * Rename pubspec
This commit is contained in:
@@ -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",
|
||||
"embedding-flutter-view:package",
|
||||
"touch-input-view:package",
|
||||
"//build/fuchsia/fidl:fuchsia.ui.gfx",
|
||||
"//flutter/fml",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# 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.
|
||||
the precise location of the touch event. We validate a touch event as valid through two ways:
|
||||
- By attaching the child view, injecting touch, and validating that the view reports the touch event back with the correct coordinates.
|
||||
- By embedding a child view into a parent view, injecting touch into both views, and validating that each view reports its touch event back with the correct coordinates.
|
||||
|
||||
```shell
|
||||
Injecting the tap event
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# 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/component.gni")
|
||||
import("//flutter/tools/fuchsia/gn-sdk/package.gni")
|
||||
|
||||
dart_library("lib") {
|
||||
package_name = "embedding-flutter-view"
|
||||
sources = [ "embedding-flutter-view.dart" ]
|
||||
|
||||
deps = [
|
||||
"//flutter/tools/fuchsia/dart:fuchsia_services",
|
||||
"//flutter/tools/fuchsia/dart:zircon",
|
||||
"//flutter/tools/fuchsia/fidl:fuchsia.ui.app",
|
||||
"//flutter/tools/fuchsia/fidl:fuchsia.ui.scenic",
|
||||
"//flutter/tools/fuchsia/fidl:fuchsia.ui.test.input",
|
||||
"//flutter/tools/fuchsia/fidl:fuchsia.ui.views",
|
||||
]
|
||||
}
|
||||
|
||||
flutter_component("component") {
|
||||
testonly = true
|
||||
component_name = "embedding-flutter-view"
|
||||
manifest = rebase_path("meta/embedding-flutter-view.cml")
|
||||
main_package = "embedding-flutter-view"
|
||||
main_dart = "embedding-flutter-view.dart"
|
||||
|
||||
deps = [ ":lib" ]
|
||||
}
|
||||
|
||||
fuchsia_package("package") {
|
||||
testonly = true
|
||||
package_name = "embedding-flutter-view"
|
||||
|
||||
deps = [ ":component" ]
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// 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 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:fidl_fuchsia_ui_app/fidl_async.dart';
|
||||
import 'package:fidl_fuchsia_ui_views/fidl_async.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(List<String> args) {
|
||||
print('Launching embedding-flutter-view');
|
||||
TestApp app = TestApp(ChildView.gfx(_launchGfxChildView()));
|
||||
app.run();
|
||||
}
|
||||
|
||||
class TestApp {
|
||||
static const _black = Color.fromARGB(255, 0, 0, 0);
|
||||
static const _blue = Color.fromARGB(255, 0, 0, 255);
|
||||
|
||||
final ChildView childView;
|
||||
final _responseListener = test_touch.TouchInputListenerProxy();
|
||||
|
||||
Color _backgroundColor = _blue;
|
||||
|
||||
TestApp(this.childView) {}
|
||||
|
||||
void run() {
|
||||
childView.create((ByteData reply) {
|
||||
// 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 & window.physicalSize;
|
||||
final windowBounds = Offset.zero & size;
|
||||
// Set up a Canvas that uses the screen size
|
||||
final recorder = PictureRecorder();
|
||||
final canvas = Canvas(recorder, physicalBounds);
|
||||
canvas.scale(pixelRatio);
|
||||
// Draw something
|
||||
final paint = Paint()..color = this._backgroundColor;
|
||||
canvas.drawRect(windowBounds, paint);
|
||||
final picture = recorder.endRecording();
|
||||
// Build the scene
|
||||
final sceneBuilder = SceneBuilder()
|
||||
..pushClipRect(physicalBounds)
|
||||
..addPicture(Offset.zero, picture);
|
||||
// Child view should take up half the screen
|
||||
final childPhysicalSize = window.physicalSize * 0.5;
|
||||
sceneBuilder
|
||||
..addPlatformView(childView.viewId,
|
||||
width: childPhysicalSize.width,
|
||||
height: size.height)
|
||||
..pop();
|
||||
sceneBuilder.pop();
|
||||
window.render(sceneBuilder.build());
|
||||
}
|
||||
|
||||
void pointerDataPacket(PointerDataPacket packet) async {
|
||||
int nowNanos = System.clockGetMonotonic();
|
||||
|
||||
for (PointerData data in packet.data) {
|
||||
print('embedding-flutter-view received tap: ${data.toStringFull()}');
|
||||
|
||||
if (data.change == PointerChange.down) {
|
||||
this._backgroundColor = _black;
|
||||
}
|
||||
|
||||
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: 'embedding-flutter-view',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
window.scheduleFrame();
|
||||
}
|
||||
|
||||
void _respond(test_touch.TouchInputListenerReportTouchInputRequest request) async {
|
||||
print('embedding-flutter-view reporting touch input to TouchInputListener');
|
||||
await _responseListener.reportTouchInput(request);
|
||||
}
|
||||
}
|
||||
|
||||
class ChildView {
|
||||
final ViewHolderToken viewHolderToken;
|
||||
final ViewportCreationToken viewportCreationToken;
|
||||
final int viewId;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void create(PlatformMessageResponseCallback callback) {
|
||||
// Construct the dart:ui platform message to create the view, and when the
|
||||
// return callback is invoked, build the scene. At that point, it is safe
|
||||
// to embed the child view in the scene.
|
||||
final viewOcclusionHint = Rect.zero;
|
||||
final Map<String, dynamic> args = <String, dynamic>{
|
||||
'viewId': viewId,
|
||||
'hitTestable': true,
|
||||
'focusable': true,
|
||||
'viewOcclusionHintLTRB': <double>[
|
||||
viewOcclusionHint.left,
|
||||
viewOcclusionHint.top,
|
||||
viewOcclusionHint.right,
|
||||
viewOcclusionHint.bottom
|
||||
],
|
||||
};
|
||||
|
||||
final ByteData createViewMessage = utf8.encoder.convert(
|
||||
json.encode(<String, Object>{
|
||||
'method': 'View.create',
|
||||
'args': args,
|
||||
})
|
||||
).buffer.asByteData();
|
||||
|
||||
final platformViewsChannel = 'flutter/platform_views';
|
||||
|
||||
PlatformDispatcher.instance.sendPlatformMessage(
|
||||
platformViewsChannel,
|
||||
createViewMessage,
|
||||
callback);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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: [ "syslog/client.shard.cml" ],
|
||||
program: {
|
||||
data: "data/embedding-flutter-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",
|
||||
},
|
||||
],
|
||||
use: [
|
||||
{
|
||||
protocol: [
|
||||
"fuchsia.ui.app.ViewProvider",
|
||||
"fuchsia.ui.scenic.Scenic",
|
||||
"fuchsia.ui.test.input.TouchInputListener",
|
||||
]
|
||||
},
|
||||
{
|
||||
directory: "config-data",
|
||||
rights: [ "r*" ],
|
||||
path: "/config/data",
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -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: embedding-flutter-view
|
||||
|
||||
environment:
|
||||
sdk: '>=2.18.0 <3.0.0'
|
||||
@@ -126,14 +126,24 @@ using RealmBuilder = component_testing::RealmBuilder;
|
||||
|
||||
// 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 zx::duration kTimeout = zx::min(1);
|
||||
|
||||
constexpr auto kTestUIStackUrl =
|
||||
"fuchsia-pkg://fuchsia.com/gfx-root-presenter-test-ui-stack#meta/"
|
||||
"test-ui-stack.cm";
|
||||
|
||||
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";
|
||||
constexpr auto kEmbeddingFlutterView = "embedding-flutter-view";
|
||||
constexpr auto kEmbeddingFlutterViewRef = ChildRef{kEmbeddingFlutterView};
|
||||
constexpr auto kEmbeddingFlutterViewUrl =
|
||||
"fuchsia-pkg://fuchsia.com/embedding-flutter-view#meta/"
|
||||
"embedding-flutter-view.cm";
|
||||
|
||||
bool CompareDouble(double f0, double f1, double epsilon) {
|
||||
return std::abs(f0 - f1) <= epsilon;
|
||||
@@ -195,11 +205,11 @@ class TouchInputListenerServer
|
||||
events_received_;
|
||||
};
|
||||
|
||||
class FlutterTapTest : public PortableUITest,
|
||||
public ::testing::Test,
|
||||
public ::testing::WithParamInterface<std::string> {
|
||||
class FlutterTapTestBase : public PortableUITest,
|
||||
public ::testing::Test,
|
||||
public ::testing::WithParamInterface<std::string> {
|
||||
protected:
|
||||
~FlutterTapTest() override {
|
||||
~FlutterTapTestBase() override {
|
||||
FML_CHECK(touch_injection_request_count() > 0)
|
||||
<< "Injection expected but didn't happen.";
|
||||
}
|
||||
@@ -251,24 +261,41 @@ class FlutterTapTest : public PortableUITest,
|
||||
|
||||
auto actual_x = pixel_scale * last_event.local_x();
|
||||
auto actual_y = pixel_scale * last_event.local_y();
|
||||
auto actual_component = last_event.component_name();
|
||||
|
||||
FML_LOG(INFO) << "Expecting event for component " << component_name
|
||||
<< " at (" << expected_x << ", " << expected_y << ")";
|
||||
FML_LOG(INFO) << "Received event for component " << component_name
|
||||
<< " at (" << actual_x << ", " << actual_y
|
||||
<< "), accounting for pixel scale of " << pixel_scale;
|
||||
bool last_event_matches =
|
||||
CompareDouble(actual_x, expected_x, pixel_scale) &&
|
||||
CompareDouble(actual_y, expected_y, pixel_scale) &&
|
||||
last_event.component_name() == component_name;
|
||||
|
||||
return CompareDouble(actual_x, expected_x, pixel_scale) &&
|
||||
CompareDouble(actual_y, expected_y, pixel_scale) &&
|
||||
last_event.component_name() == component_name;
|
||||
if (last_event_matches) {
|
||||
FML_LOG(INFO) << "Received event for component " << component_name
|
||||
<< " at (" << expected_x << ", " << expected_y << ")";
|
||||
} else {
|
||||
FML_LOG(WARNING) << "Expecting event for component " << component_name
|
||||
<< " at (" << expected_x << ", " << expected_y << "). "
|
||||
<< "Instead received event for component "
|
||||
<< actual_component << " at (" << actual_x << ", "
|
||||
<< actual_y << "), accounting for pixel scale of "
|
||||
<< pixel_scale;
|
||||
}
|
||||
|
||||
return last_event_matches;
|
||||
}
|
||||
|
||||
// Guaranteed to be initialized after SetUp().
|
||||
uint32_t display_width() const { return display_width_; }
|
||||
uint32_t display_height() const { return display_height_; }
|
||||
|
||||
ParamType GetTestUIStackUrl() override { return GetParam(); };
|
||||
|
||||
std::unique_ptr<TouchInputListenerServer> touch_input_listener_server_;
|
||||
};
|
||||
|
||||
class FlutterTapTest : public FlutterTapTestBase {
|
||||
private:
|
||||
void ExtendRealm() override {
|
||||
FML_LOG(INFO) << "Extending realm";
|
||||
// Key part of service setup: have this test component vend the
|
||||
// |TouchInputListener| service in the constructed realm.
|
||||
touch_input_listener_server_ =
|
||||
@@ -276,6 +303,7 @@ class FlutterTapTest : public PortableUITest,
|
||||
realm_builder()->AddLocalChild(kMockTouchInputListener,
|
||||
touch_input_listener_server_.get());
|
||||
|
||||
// Add touch-input-view to the Realm
|
||||
realm_builder()->AddChild(kTouchInputView, kTouchInputViewUrl,
|
||||
component_testing::ChildOptions{
|
||||
.environment = kFlutterRunnerEnvironment,
|
||||
@@ -293,26 +321,57 @@ class FlutterTapTest : public PortableUITest,
|
||||
.source = kTouchInputViewRef,
|
||||
.targets = {ParentRef()}});
|
||||
}
|
||||
};
|
||||
|
||||
ParamType GetTestUIStackUrl() override { return GetParam(); };
|
||||
class FlutterEmbedTapTest : public FlutterTapTestBase {
|
||||
private:
|
||||
void ExtendRealm() override {
|
||||
FML_LOG(INFO) << "Extending realm";
|
||||
// Key part of service setup: have this test component vend the
|
||||
// |TouchInputListener| service in the constructed realm.
|
||||
touch_input_listener_server_ =
|
||||
std::make_unique<TouchInputListenerServer>(dispatcher());
|
||||
realm_builder()->AddLocalChild(kMockTouchInputListener,
|
||||
touch_input_listener_server_.get());
|
||||
|
||||
std::unique_ptr<TouchInputListenerServer> touch_input_listener_server_;
|
||||
// Add touch-input-view to the Realm
|
||||
realm_builder()->AddChild(kTouchInputView, kTouchInputViewUrl,
|
||||
component_testing::ChildOptions{
|
||||
.environment = kFlutterRunnerEnvironment,
|
||||
});
|
||||
// Add embedding-flutter-view to the Realm
|
||||
// This component will embed touch-input-view as a child view
|
||||
realm_builder()->AddChild(kEmbeddingFlutterView, kEmbeddingFlutterViewUrl,
|
||||
component_testing::ChildOptions{
|
||||
.environment = kFlutterRunnerEnvironment,
|
||||
});
|
||||
|
||||
fuchsia::ui::scenic::ScenicPtr scenic_;
|
||||
uint32_t display_width_ = 0;
|
||||
uint32_t display_height_ = 0;
|
||||
// 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,
|
||||
kEmbeddingFlutterViewRef}});
|
||||
|
||||
realm_builder()->AddRoute(
|
||||
Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}},
|
||||
.source = kEmbeddingFlutterViewRef,
|
||||
.targets = {ParentRef()}});
|
||||
realm_builder()->AddRoute(
|
||||
Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}},
|
||||
.source = kTouchInputViewRef,
|
||||
.targets = {kEmbeddingFlutterViewRef}});
|
||||
}
|
||||
};
|
||||
|
||||
// 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,
|
||||
::testing::Values(
|
||||
"fuchsia-pkg://fuchsia.com/gfx-root-presenter-test-ui-stack#meta/"
|
||||
"test-ui-stack.cm"));
|
||||
INSTANTIATE_TEST_SUITE_P(FlutterTapTestParameterized,
|
||||
FlutterTapTest,
|
||||
::testing::Values(kTestUIStackUrl));
|
||||
|
||||
TEST_P(FlutterTapTest, FlutterTap) {
|
||||
// Launch client view, and wait until it's rendering to proceed with the test.
|
||||
@@ -335,5 +394,43 @@ TEST_P(FlutterTapTest, FlutterTap) {
|
||||
});
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(FlutterEmbedTapTestParameterized,
|
||||
FlutterEmbedTapTest,
|
||||
::testing::Values(kTestUIStackUrl));
|
||||
|
||||
TEST_P(FlutterEmbedTapTest, FlutterEmbedTap) {
|
||||
// Launch view
|
||||
FML_LOG(INFO) << "Initializing scene";
|
||||
LaunchClientWithEmbeddedView();
|
||||
FML_LOG(INFO) << "Client launched";
|
||||
|
||||
{
|
||||
// Embedded child view takes up the left side of the screen
|
||||
// Expect a response from the child view if we inject a tap there
|
||||
InjectTap(-500, -500);
|
||||
RunLoopUntil([this] {
|
||||
return LastEventReceivedMatches(
|
||||
/*expected_x=*/static_cast<float>(display_width() / 4.0f),
|
||||
/*expected_y=*/static_cast<float>(display_height() / 4.0f),
|
||||
/*component_name=*/"touch-input-view");
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
// Parent view takes up the right side of the screen
|
||||
// Validate that parent can still receive taps
|
||||
InjectTap(500, 500);
|
||||
RunLoopUntil([this] {
|
||||
return LastEventReceivedMatches(
|
||||
/*expected_x=*/static_cast<float>(display_width() / (4.0f / 3.0f)),
|
||||
/*expected_y=*/static_cast<float>(display_height() / (4.0f / 3.0f)),
|
||||
/*component_name=*/"embedding-flutter-view");
|
||||
});
|
||||
}
|
||||
|
||||
// There should be 2 injected taps
|
||||
ASSERT_EQ(touch_injection_request_count(), 2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace touch_input_test::testing
|
||||
|
||||
@@ -11,30 +11,17 @@ import 'package:fuchsia_services/services.dart';
|
||||
import 'package:zircon/zircon.dart';
|
||||
|
||||
void main() {
|
||||
print('Launching two-flutter view');
|
||||
MyApp app = MyApp();
|
||||
print('Launching touch-input-view');
|
||||
TestApp app = TestApp();
|
||||
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);
|
||||
class TestApp {
|
||||
static const _yellow = Color.fromARGB(255, 255, 255, 0);
|
||||
static const _pink = Color.fromARGB(255, 255, 0, 255);
|
||||
|
||||
final List<Color> _colors = <Color>[
|
||||
_red,
|
||||
_orange,
|
||||
_yellow,
|
||||
_green,
|
||||
_blue,
|
||||
_purple,
|
||||
];
|
||||
Color _backgroundColor = _pink;
|
||||
|
||||
// Each tap will increment the counter, we then determine what color to choose
|
||||
int _touchCounter = 0;
|
||||
final _responseListener = test_touch.TouchInputListenerProxy();
|
||||
|
||||
void run() {
|
||||
@@ -59,15 +46,14 @@ class MyApp {
|
||||
final pixelRatio = window.devicePixelRatio;
|
||||
final size = window.physicalSize / pixelRatio;
|
||||
final physicalBounds = Offset.zero & size * pixelRatio;
|
||||
// Set up Canvas that uses the screen size
|
||||
final windowBounds = Offset.zero & size;
|
||||
// Set up a 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);
|
||||
final paint = Paint()..color = this._backgroundColor;
|
||||
canvas.drawRect(windowBounds, paint);
|
||||
// Build the scene
|
||||
final picture = recorder.endRecording();
|
||||
final sceneBuilder = SceneBuilder()
|
||||
@@ -83,10 +69,6 @@ class MyApp {
|
||||
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)
|
||||
|
||||
@@ -24,11 +24,7 @@
|
||||
use: [
|
||||
{
|
||||
protocol: [
|
||||
"fuchsia.sysmem.Allocator",
|
||||
"fuchsia.tracing.provider.Registry",
|
||||
"fuchsia.ui.scenic.Scenic",
|
||||
"fuchsia.ui.test.input.TouchInputListener",
|
||||
"fuchsia.vulkan.loader.Loader",
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -31,9 +31,7 @@ using fuchsia_test_utils::CheckViewExistsInSnapshot;
|
||||
|
||||
void PortableUITest::SetUp() {
|
||||
SetUpRealmBase();
|
||||
|
||||
ExtendRealm();
|
||||
|
||||
realm_ = std::make_unique<RealmRoot>(realm_builder_.Build());
|
||||
}
|
||||
|
||||
@@ -142,6 +140,7 @@ void PortableUITest::LaunchClient() {
|
||||
FML_LOG(ERROR) << "Error from test scene provider: "
|
||||
<< &zx_status_get_string;
|
||||
});
|
||||
|
||||
fuchsia::ui::test::scene::ControllerAttachClientViewRequest request;
|
||||
request.set_view_provider(realm_->Connect<fuchsia::ui::app::ViewProvider>());
|
||||
scene_provider_->RegisterViewTreeWatcher(view_tree_watcher_.NewRequest(),
|
||||
@@ -157,11 +156,55 @@ void PortableUITest::LaunchClient() {
|
||||
WatchViewGeometry();
|
||||
|
||||
FML_LOG(INFO) << "Waiting for client view to connect";
|
||||
// Wait for the client view to get attached to the view tree.
|
||||
RunLoopUntil(
|
||||
[this] { return HasViewConnected(*client_root_view_ref_koid_); });
|
||||
FML_LOG(INFO) << "Client view has rendered";
|
||||
}
|
||||
|
||||
void PortableUITest::LaunchClientWithEmbeddedView() {
|
||||
LaunchClient();
|
||||
// At this point, the parent view must have rendered, so we just need to wait
|
||||
// for the embedded view.
|
||||
RunLoopUntil([this] {
|
||||
if (!last_view_tree_snapshot_.has_value() ||
|
||||
!last_view_tree_snapshot_->has_views()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!client_root_view_ref_koid_.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& view : last_view_tree_snapshot_->views()) {
|
||||
if (!view.has_view_ref_koid() ||
|
||||
view.view_ref_koid() != *client_root_view_ref_koid_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (view.children().empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: We can't rely on the presence of the child view in
|
||||
// `view.children()` to guarantee that it has rendered. The child view
|
||||
// also needs to be present in `last_view_tree_snapshot_->views`.
|
||||
return std::count_if(
|
||||
last_view_tree_snapshot_->views().begin(),
|
||||
last_view_tree_snapshot_->views().end(),
|
||||
[view_to_find =
|
||||
view.children().back()](const auto& view_to_check) {
|
||||
return view_to_check.has_view_ref_koid() &&
|
||||
view_to_check.view_ref_koid() == view_to_find;
|
||||
}) > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
FML_LOG(INFO) << "Embedded view has rendered";
|
||||
}
|
||||
|
||||
void PortableUITest::RegisterTouchScreen() {
|
||||
FML_LOG(INFO) << "Registering fake touch screen";
|
||||
input_registry_ = realm_->Connect<fuchsia::ui::test::input::Registry>();
|
||||
|
||||
@@ -48,6 +48,9 @@ class PortableUITest : public ::loop_fixture::RealLoop {
|
||||
|
||||
// Attaches a client view to the scene, and waits for it to render.
|
||||
void LaunchClient();
|
||||
// Attaches a view with an embedded child view to the scene, and waits for it
|
||||
// to render.
|
||||
void LaunchClientWithEmbeddedView();
|
||||
|
||||
// Returns true when the specified view is fully connected to the scene AND
|
||||
// has presented at least one frame of content.
|
||||
@@ -86,6 +89,10 @@ class PortableUITest : public ::loop_fixture::RealLoop {
|
||||
component_testing::RealmBuilder* realm_builder() { return &realm_builder_; }
|
||||
component_testing::RealmRoot* realm_root() { return realm_.get(); }
|
||||
|
||||
fuchsia::ui::scenic::ScenicPtr scenic_;
|
||||
uint32_t display_width_ = 0;
|
||||
uint32_t display_height_ = 0;
|
||||
|
||||
int touch_injection_request_count() const {
|
||||
return touch_injection_request_count_;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
- touch-input-test-0.far
|
||||
- oot_flutter_jit_runner-0.far
|
||||
- gen/flutter/shell/platform/fuchsia/flutter/tests/integration/touch-input/touch-input-view/touch-input-view/touch-input-view.far
|
||||
- gen/flutter/shell/platform/fuchsia/flutter/tests/integration/touch-input/embedding-flutter-view/embedding-flutter-view/embedding-flutter-view.far
|
||||
- test_command: run-test-suite fuchsia-pkg://fuchsia.com/mouse-input-test#meta/mouse-input-test.cm
|
||||
packages:
|
||||
- mouse-input-test-0.far
|
||||
|
||||
@@ -60,7 +60,7 @@ case $test_name in
|
||||
test_packages=("text-input-test-0.far" "text-input-view.far")
|
||||
;;
|
||||
touch-input)
|
||||
test_packages=("touch-input-test-0.far" "touch-input-view.far")
|
||||
test_packages=("touch-input-test-0.far" "touch-input-view.far" "embedding-flutter-view.far")
|
||||
;;
|
||||
*)
|
||||
engine-error "Unknown test name $test_name. You may need to add it to $0"
|
||||
|
||||
Reference in New Issue
Block a user