mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
WIP Commits separated as follows: - Update lints in analysis_options files - Run `dart fix --apply` - Clean up leftover analysis issues - Run `dart format .` in the right places. Local analysis and testing passes. Checking CI now. Part of https://github.com/flutter/flutter/issues/178827 - Adoption of flutter_lints in examples/api coming in a separate change (cc @loic-sharma) ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
592 lines
20 KiB
Dart
592 lines
20 KiB
Dart
// Copyright 2014 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:async';
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:fake_async/fake_async.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/gestures.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import '../services/fake_platform_views.dart';
|
|
import 'rendering_tester.dart';
|
|
|
|
void main() {
|
|
final TestRenderingFlutterBinding binding = TestRenderingFlutterBinding.ensureInitialized();
|
|
|
|
tearDown(() {
|
|
// Lay out a dummy RenderBox to make sure that anything that was laid out
|
|
// during the test gets detached.
|
|
final RenderBox emptyRenderBox = RenderCustomPaint(painter: _EmptyPainter());
|
|
layout(emptyRenderBox);
|
|
});
|
|
|
|
group('PlatformViewRenderBox', () {
|
|
late FakePlatformViewController fakePlatformViewController;
|
|
late PlatformViewRenderBox platformViewRenderBox;
|
|
setUp(() {
|
|
fakePlatformViewController = FakePlatformViewController(0);
|
|
platformViewRenderBox = PlatformViewRenderBox(
|
|
controller: fakePlatformViewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
|
|
Factory<VerticalDragGestureRecognizer>(() {
|
|
return VerticalDragGestureRecognizer();
|
|
}),
|
|
},
|
|
);
|
|
});
|
|
|
|
test('layout should size to max constraint', () {
|
|
layout(platformViewRenderBox);
|
|
platformViewRenderBox.layout(
|
|
const BoxConstraints(minWidth: 50, minHeight: 50, maxWidth: 100, maxHeight: 100),
|
|
);
|
|
expect(platformViewRenderBox.size, const Size(100, 100));
|
|
});
|
|
|
|
test('send semantics update if id is changed', () {
|
|
final tree = RenderConstrainedBox(
|
|
additionalConstraints: const BoxConstraints.tightFor(height: 20.0, width: 20.0),
|
|
child: platformViewRenderBox,
|
|
);
|
|
var semanticsUpdateCount = 0;
|
|
final SemanticsHandle semanticsHandle = TestRenderingFlutterBinding.instance
|
|
.ensureSemantics();
|
|
TestRenderingFlutterBinding.instance.pipelineOwner.semanticsOwner!.addListener(() {
|
|
++semanticsUpdateCount;
|
|
});
|
|
layout(tree, phase: EnginePhase.flushSemantics);
|
|
// Initial semantics update
|
|
expect(semanticsUpdateCount, 1);
|
|
|
|
semanticsUpdateCount = 0;
|
|
|
|
// Request semantics update even though nothing changed.
|
|
platformViewRenderBox.markNeedsSemanticsUpdate();
|
|
pumpFrame(phase: EnginePhase.flushSemantics);
|
|
expect(semanticsUpdateCount, 0);
|
|
|
|
semanticsUpdateCount = 0;
|
|
|
|
final updatedFakePlatformViewController = FakePlatformViewController(10);
|
|
platformViewRenderBox.controller = updatedFakePlatformViewController;
|
|
pumpFrame(phase: EnginePhase.flushSemantics);
|
|
// Update id should update the semantics.
|
|
expect(semanticsUpdateCount, 1);
|
|
|
|
semanticsHandle.dispose();
|
|
});
|
|
|
|
test('mouse hover events are dispatched via PlatformViewController.dispatchPointerEvent', () {
|
|
layout(platformViewRenderBox);
|
|
pumpFrame(phase: EnginePhase.flushSemantics);
|
|
|
|
RendererBinding.instance.platformDispatcher.onPointerDataPacket!(
|
|
ui.PointerDataPacket(
|
|
data: <ui.PointerData>[
|
|
_pointerData(ui.PointerChange.add, Offset.zero),
|
|
_pointerData(ui.PointerChange.hover, const Offset(10, 10)),
|
|
_pointerData(ui.PointerChange.remove, const Offset(10, 10)),
|
|
],
|
|
),
|
|
);
|
|
|
|
expect(fakePlatformViewController.dispatchedPointerEvents, isNotEmpty);
|
|
});
|
|
|
|
test('touch hover events are dispatched via PlatformViewController.dispatchPointerEvent', () {
|
|
layout(platformViewRenderBox);
|
|
pumpFrame(phase: EnginePhase.flushSemantics);
|
|
|
|
RendererBinding.instance.platformDispatcher.onPointerDataPacket!(
|
|
ui.PointerDataPacket(
|
|
data: <ui.PointerData>[
|
|
_pointerData(ui.PointerChange.add, Offset.zero),
|
|
_pointerData(ui.PointerChange.hover, const Offset(10, 10)),
|
|
_pointerData(ui.PointerChange.remove, const Offset(10, 10)),
|
|
],
|
|
),
|
|
);
|
|
|
|
expect(fakePlatformViewController.dispatchedPointerEvents, isNotEmpty);
|
|
});
|
|
});
|
|
|
|
// Regression test for https://github.com/flutter/flutter/issues/69431
|
|
test('multi-finger touch test', () {
|
|
final viewsController = FakeAndroidPlatformViewsController();
|
|
viewsController.registerViewType('webview');
|
|
final AndroidViewController viewController = PlatformViewsService.initAndroidView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.rtl,
|
|
);
|
|
final platformViewRenderBox = PlatformViewRenderBox(
|
|
controller: viewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
|
|
Factory<VerticalDragGestureRecognizer>(() => VerticalDragGestureRecognizer()),
|
|
},
|
|
);
|
|
layout(platformViewRenderBox);
|
|
pumpFrame(phase: EnginePhase.flushSemantics);
|
|
|
|
viewController.pointTransformer = (Offset offset) =>
|
|
platformViewRenderBox.globalToLocal(offset);
|
|
|
|
FakeAsync().run((FakeAsync async) {
|
|
// Put one pointer down.
|
|
RendererBinding.instance.platformDispatcher.onPointerDataPacket!(
|
|
ui.PointerDataPacket(
|
|
data: <ui.PointerData>[
|
|
_pointerData(
|
|
ui.PointerChange.add,
|
|
Offset.zero,
|
|
pointer: 1,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
_pointerData(
|
|
ui.PointerChange.down,
|
|
const Offset(10, 10),
|
|
pointer: 1,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
_pointerData(
|
|
ui.PointerChange.remove,
|
|
const Offset(10, 10),
|
|
pointer: 1,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
async.flushMicrotasks();
|
|
|
|
// Put another pointer down and then cancel it.
|
|
RendererBinding.instance.platformDispatcher.onPointerDataPacket!(
|
|
ui.PointerDataPacket(
|
|
data: <ui.PointerData>[
|
|
_pointerData(
|
|
ui.PointerChange.add,
|
|
Offset.zero,
|
|
pointer: 2,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
_pointerData(
|
|
ui.PointerChange.down,
|
|
const Offset(20, 10),
|
|
pointer: 2,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
_pointerData(
|
|
ui.PointerChange.cancel,
|
|
const Offset(20, 10),
|
|
pointer: 2,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
async.flushMicrotasks();
|
|
|
|
// The first pointer can still moving without crashing.
|
|
RendererBinding.instance.platformDispatcher.onPointerDataPacket!(
|
|
ui.PointerDataPacket(
|
|
data: <ui.PointerData>[
|
|
_pointerData(
|
|
ui.PointerChange.add,
|
|
Offset.zero,
|
|
pointer: 1,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
_pointerData(
|
|
ui.PointerChange.move,
|
|
const Offset(10, 10),
|
|
pointer: 1,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
_pointerData(
|
|
ui.PointerChange.remove,
|
|
const Offset(10, 10),
|
|
pointer: 1,
|
|
kind: PointerDeviceKind.touch,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
async.flushMicrotasks();
|
|
});
|
|
|
|
// Passes if no crashes.
|
|
});
|
|
|
|
test('created callback is reset when controller is changed', () {
|
|
final viewsController = FakeAndroidPlatformViewsController();
|
|
viewsController.registerViewType('webview');
|
|
final AndroidViewController firstController = PlatformViewsService.initAndroidView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.rtl,
|
|
);
|
|
final renderBox = RenderAndroidView(
|
|
viewController: firstController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
|
|
);
|
|
layout(renderBox);
|
|
pumpFrame(phase: EnginePhase.flushSemantics);
|
|
|
|
expect(firstController.createdCallbacks, isNotEmpty);
|
|
expect(firstController.createdCallbacks.length, 1);
|
|
|
|
final AndroidViewController secondController = PlatformViewsService.initAndroidView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.rtl,
|
|
);
|
|
// Reset controller.
|
|
renderBox.controller = secondController;
|
|
|
|
expect(firstController.createdCallbacks, isEmpty);
|
|
expect(secondController.createdCallbacks, isNotEmpty);
|
|
expect(secondController.createdCallbacks.length, 1);
|
|
});
|
|
|
|
test('render object changed its visual appearance after texture is created', () {
|
|
FakeAsync().run((FakeAsync async) {
|
|
final AndroidViewController viewController = PlatformViewsService.initAndroidView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.rtl,
|
|
);
|
|
final renderBox = RenderAndroidView(
|
|
viewController: viewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
|
|
);
|
|
|
|
final viewCreation = Completer<void>();
|
|
const channel = MethodChannel('flutter/platform_views');
|
|
binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (
|
|
MethodCall methodCall,
|
|
) async {
|
|
assert(methodCall.method == 'create', 'Unexpected method call');
|
|
await viewCreation.future;
|
|
return /*textureId=*/ 0;
|
|
});
|
|
|
|
layout(renderBox);
|
|
pumpFrame(phase: EnginePhase.paint);
|
|
|
|
expect(renderBox.debugLayer, isNotNull);
|
|
expect(renderBox.debugLayer!.hasChildren, isFalse);
|
|
expect(viewController.isCreated, isFalse);
|
|
expect(renderBox.debugNeedsPaint, isFalse);
|
|
|
|
viewCreation.complete();
|
|
async.flushMicrotasks();
|
|
|
|
expect(viewController.isCreated, isTrue);
|
|
expect(renderBox.debugNeedsPaint, isTrue);
|
|
expect(renderBox.debugLayer!.hasChildren, isFalse);
|
|
|
|
pumpFrame(phase: EnginePhase.paint);
|
|
expect(renderBox.debugLayer!.hasChildren, isTrue);
|
|
expect(renderBox.debugLayer!.firstChild, isA<TextureLayer>());
|
|
});
|
|
});
|
|
|
|
test('markNeedsPaint does not get called on a disposed RO', () async {
|
|
FakeAsync().run((FakeAsync async) {
|
|
final AndroidViewController viewController = PlatformViewsService.initAndroidView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.rtl,
|
|
);
|
|
final renderBox = RenderAndroidView(
|
|
viewController: viewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
|
|
);
|
|
|
|
final viewCreation = Completer<void>();
|
|
const channel = MethodChannel('flutter/platform_views');
|
|
binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (
|
|
MethodCall methodCall,
|
|
) async {
|
|
assert(methodCall.method == 'create', 'Unexpected method call');
|
|
await viewCreation.future;
|
|
return /*textureId=*/ 0;
|
|
});
|
|
|
|
layout(renderBox);
|
|
pumpFrame(phase: EnginePhase.paint);
|
|
|
|
expect(renderBox.debugLayer, isNotNull);
|
|
expect(renderBox.debugLayer!.hasChildren, isFalse);
|
|
expect(viewController.isCreated, isFalse);
|
|
expect(renderBox.debugNeedsPaint, isFalse);
|
|
|
|
renderBox.dispose();
|
|
viewCreation.complete();
|
|
async.flushMicrotasks();
|
|
|
|
expect(viewController.isCreated, isTrue);
|
|
expect(renderBox.debugNeedsPaint, isFalse);
|
|
expect(renderBox.debugLayer, isNull);
|
|
|
|
pumpFrame(phase: EnginePhase.paint);
|
|
expect(renderBox.debugLayer, isNull);
|
|
});
|
|
});
|
|
|
|
test('markNeedsPaint does not get called when setting the same viewController', () {
|
|
FakeAsync().run((FakeAsync async) {
|
|
final viewCreation = Completer<void>();
|
|
const channel = MethodChannel('flutter/platform_views');
|
|
binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (
|
|
MethodCall methodCall,
|
|
) async {
|
|
assert(methodCall.method == 'create', 'Unexpected method call');
|
|
await viewCreation.future;
|
|
return /*textureId=*/ 0;
|
|
});
|
|
|
|
var futureCallbackRan = false;
|
|
|
|
PlatformViewsService.initUiKitView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.ltr,
|
|
).then((UiKitViewController viewController) {
|
|
final renderBox = RenderUiKitView(
|
|
viewController: viewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
|
|
);
|
|
|
|
layout(renderBox);
|
|
pumpFrame(phase: EnginePhase.paint);
|
|
expect(renderBox.debugNeedsPaint, isFalse);
|
|
|
|
renderBox.viewController = viewController;
|
|
|
|
expect(renderBox.debugNeedsPaint, isFalse);
|
|
|
|
futureCallbackRan = true;
|
|
});
|
|
|
|
viewCreation.complete();
|
|
async.flushMicrotasks();
|
|
expect(futureCallbackRan, true);
|
|
});
|
|
});
|
|
|
|
group('RenderDarwinPlatformView', () {
|
|
const channel = MethodChannel('flutter/platform_views');
|
|
late int gestureRejections;
|
|
late Completer<void> viewCreation;
|
|
|
|
setUp(() {
|
|
gestureRejections = 0;
|
|
viewCreation = Completer<void>();
|
|
|
|
binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (
|
|
MethodCall methodCall,
|
|
) async {
|
|
switch (methodCall.method) {
|
|
case 'create':
|
|
await viewCreation.future;
|
|
case 'rejectGesture':
|
|
gestureRejections++;
|
|
default:
|
|
throw UnsupportedError('Unexpected method call ${methodCall.method}.');
|
|
}
|
|
return /*textureId=*/ 0;
|
|
});
|
|
});
|
|
|
|
tearDown(() {
|
|
binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, null);
|
|
});
|
|
|
|
// Regression test for https://github.com/flutter/flutter/issues/83481.
|
|
test('RenderUiKitView does not handle pointer events when not laid out', () async {
|
|
await FakeAsync().run((FakeAsync async) {
|
|
PlatformViewsService.initUiKitView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.ltr,
|
|
).then((UiKitViewController viewController) {
|
|
final renderBox = RenderUiKitView(
|
|
viewController: viewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
|
|
);
|
|
renderBox.attach(TestRenderingFlutterBinding.instance.pipelineOwner);
|
|
|
|
expect(renderBox.debugNeedsLayout, isTrue);
|
|
expect(gestureRejections, 0);
|
|
|
|
const event = PointerDownEvent(position: Offset(10, 10));
|
|
GestureBinding.instance.pointerRouter.route(event);
|
|
|
|
// Didn't receive the gesture because the RenderBox is not laid out,
|
|
// even though it's attached.
|
|
expect(gestureRejections, 0);
|
|
|
|
renderBox.detach();
|
|
});
|
|
|
|
viewCreation.complete();
|
|
async.flushMicrotasks();
|
|
});
|
|
});
|
|
|
|
test('RenderUiKitView handles pointer events when laid out', () async {
|
|
await FakeAsync().run((FakeAsync async) {
|
|
PlatformViewsService.initUiKitView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.ltr,
|
|
).then((UiKitViewController viewController) {
|
|
final renderBox = RenderUiKitView(
|
|
viewController: viewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
|
|
);
|
|
|
|
expect(renderBox.debugNeedsLayout, isTrue);
|
|
expect(gestureRejections, 0);
|
|
|
|
const event = PointerDownEvent(position: Offset(10, 10));
|
|
GestureBinding.instance.pointerRouter.route(event);
|
|
|
|
// Didn't receive the gesture because the RenderBox is not laid out.
|
|
expect(gestureRejections, 0);
|
|
|
|
layout(renderBox);
|
|
pumpFrame(phase: EnginePhase.flushSemantics);
|
|
expect(renderBox.debugNeedsLayout, isFalse);
|
|
|
|
const event2 = PointerDownEvent(position: Offset(10, 10));
|
|
GestureBinding.instance.pointerRouter.route(event2);
|
|
|
|
// Now that the RenderBox is laid out, received the gesture.
|
|
expect(gestureRejections, 1);
|
|
});
|
|
|
|
viewCreation.complete();
|
|
async.flushMicrotasks();
|
|
});
|
|
});
|
|
|
|
// Regression test for https://github.com/flutter/flutter/issues/83481.
|
|
test('RenderAppKitView does not handle pointer events when not laid out', () async {
|
|
await FakeAsync().run((FakeAsync async) {
|
|
PlatformViewsService.initAppKitView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.ltr,
|
|
).then((AppKitViewController viewController) {
|
|
final renderBox = RenderAppKitView(
|
|
viewController: viewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
|
|
);
|
|
renderBox.attach(TestRenderingFlutterBinding.instance.pipelineOwner);
|
|
|
|
expect(renderBox.debugNeedsLayout, isTrue);
|
|
expect(gestureRejections, 0);
|
|
|
|
const event = PointerDownEvent(position: Offset(10, 10));
|
|
GestureBinding.instance.pointerRouter.route(event);
|
|
|
|
// Didn't receive the gesture because the RenderBox is not laid out.
|
|
expect(gestureRejections, 0);
|
|
|
|
renderBox.detach();
|
|
});
|
|
|
|
viewCreation.complete();
|
|
async.flushMicrotasks();
|
|
});
|
|
});
|
|
|
|
// Regression test for https://github.com/flutter/flutter/issues/83481.
|
|
test('RenderAppKitView handles pointer events when laid out', () async {
|
|
await FakeAsync().run((FakeAsync async) {
|
|
PlatformViewsService.initAppKitView(
|
|
id: 0,
|
|
viewType: 'webview',
|
|
layoutDirection: TextDirection.ltr,
|
|
).then((AppKitViewController viewController) {
|
|
final renderBox = RenderAppKitView(
|
|
viewController: viewController,
|
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
|
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{},
|
|
);
|
|
|
|
expect(renderBox.debugNeedsLayout, isTrue);
|
|
expect(gestureRejections, 0);
|
|
|
|
const event = PointerDownEvent(position: Offset(10, 10));
|
|
GestureBinding.instance.pointerRouter.route(event);
|
|
|
|
// Didn't receive the gesture because the RenderBox is not laid out.
|
|
expect(gestureRejections, 0);
|
|
|
|
layout(renderBox);
|
|
pumpFrame(phase: EnginePhase.flushSemantics);
|
|
expect(renderBox.debugNeedsLayout, isFalse);
|
|
|
|
const event2 = PointerDownEvent(position: Offset(10, 10));
|
|
GestureBinding.instance.pointerRouter.route(event2);
|
|
|
|
// Now that the RenderBox is laid out, received the gesture.
|
|
expect(gestureRejections, 1);
|
|
});
|
|
|
|
viewCreation.complete();
|
|
async.flushMicrotasks();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
ui.PointerData _pointerData(
|
|
ui.PointerChange change,
|
|
Offset logicalPosition, {
|
|
int device = 0,
|
|
PointerDeviceKind kind = PointerDeviceKind.mouse,
|
|
int pointer = 0,
|
|
}) {
|
|
final double devicePixelRatio =
|
|
RendererBinding.instance.platformDispatcher.implicitView!.devicePixelRatio;
|
|
return ui.PointerData(
|
|
pointerIdentifier: pointer,
|
|
embedderId: pointer,
|
|
change: change,
|
|
physicalX: logicalPosition.dx * devicePixelRatio,
|
|
physicalY: logicalPosition.dy * devicePixelRatio,
|
|
kind: kind,
|
|
device: device,
|
|
);
|
|
}
|
|
|
|
class _EmptyPainter extends CustomPainter {
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final paint = Paint()..color = const Color(0x00000000);
|
|
canvas.drawRect(Offset.zero & size, paint);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
|
}
|