Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[fuchsia] embedding-flutter test #37052

Merged
merged 11 commits into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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" ]
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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",
},
]
}
Original file line number Diff line number Diff line change
@@ -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'
Loading