Unverified Commit f88d2d9c authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Revert 20917 platform view arena (#21086)

This reverts commit c594696f.
parent 3313f518
......@@ -42,13 +42,7 @@ enum _PlatformViewState {
/// Android [View](https://developer.android.com/reference/android/view/View).
///
/// The render object's layout behavior is to fill all available space, the parent of this object must
/// provide bounded layout constraints.
///
/// RenderAndroidView participates in Flutter's [GestureArena]s, and dispatches touch events to the
/// Android view iff it won the arena. Specific gestures that should be dispatched to the Android
/// view can be specified in [RenderAndroidView.gestureRecognizers]. If
/// [RenderAndroidView.gestureRecognizers] is empty, the gesture will be dispatched to the Android
/// view iff it was not claimed by any other gesture recognizer.
/// provide bounded layout constraints
///
/// See also:
/// * [AndroidView] which is a widget that is used to show an Android view.
......@@ -59,14 +53,10 @@ class RenderAndroidView extends RenderBox {
RenderAndroidView({
@required AndroidViewController viewController,
@required this.hitTestBehavior,
List<OneSequenceGestureRecognizer> gestureRecognizers = const <OneSequenceGestureRecognizer> [],
}) : assert(viewController != null),
assert(hitTestBehavior != null),
assert(gestureRecognizers != null),
_viewController = viewController
{
_viewController = viewController {
_motionEventsDispatcher = new _MotionEventsDispatcher(globalToLocal, viewController);
this.gestureRecognizers = gestureRecognizers;
}
_PlatformViewState _state = _PlatformViewState.uninitialized;
......@@ -90,18 +80,6 @@ class RenderAndroidView extends RenderBox {
// any newly arriving events there's nothing we need to invalidate.
PlatformViewHitTestBehavior hitTestBehavior;
/// Which gestures should be forwarded to the Android view.
///
/// The gesture recognizers on this list participate in the gesture arena for each pointer
/// that was put down on the render box. If any of the recognizers on this list wins the
/// gesture arena, the entire pointer event sequence starting from the pointer down event
/// will be dispatched to the Android view.
set gestureRecognizers(List<OneSequenceGestureRecognizer> recognizers) {
assert(recognizers != null);
_gestureRecognizer?.dispose();
_gestureRecognizer = new _AndroidViewGestureRecognizer(_motionEventsDispatcher, recognizers);
}
@override
bool get sizedByParent => true;
......@@ -113,8 +91,6 @@ class RenderAndroidView extends RenderBox {
_MotionEventsDispatcher _motionEventsDispatcher;
_AndroidViewGestureRecognizer _gestureRecognizer;
@override
void performResize() {
size = constraints.biggest;
......@@ -193,109 +169,7 @@ class RenderAndroidView extends RenderBox {
@override
void handleEvent(PointerEvent event, HitTestEntry entry) {
if (event is PointerDownEvent) {
_gestureRecognizer.addPointer(event);
}
}
@override
void detach() {
_gestureRecognizer.reset();
super.detach();
}
}
class _AndroidViewGestureRecognizer extends OneSequenceGestureRecognizer {
_AndroidViewGestureRecognizer(this.dispatcher, List<OneSequenceGestureRecognizer> gestureRecognizers) {
this.gestureRecognizers = gestureRecognizers;
}
final _MotionEventsDispatcher dispatcher;
// Maps a pointer to a list of its cached pointer events.
// Before the arena for a pointer is resolved all events are cached here, if we win the arena
// the cached events are dispatched to the view, if we lose the arena we clear the cache for
// the pointer.
final Map<int, List<PointerEvent>> cachedEvents = <int, List<PointerEvent>> {};
// Pointer for which we have already won the arena, events for pointers in this set are
// immediately dispatched to the Android view.
final Set<int> forwardedPointers = new Set<int>();
// We use OneSequenceGestureRecognizers as they support gesture arena teams.
// TODO(amirh): get a list of GestureRecognizers here.
// https://github.com/flutter/flutter/issues/20953
List<OneSequenceGestureRecognizer> _gestureRecognizers;
set gestureRecognizers(List<OneSequenceGestureRecognizer> recognizers) {
_gestureRecognizers = recognizers;
team = new GestureArenaTeam();
team.captain = this;
for (OneSequenceGestureRecognizer recognizer in _gestureRecognizers) {
recognizer.team = team;
}
}
@override
void addPointer(PointerDownEvent event) {
startTrackingPointer(event.pointer);
for (OneSequenceGestureRecognizer recognizer in _gestureRecognizers) {
recognizer.addPointer(event);
}
}
@override
String get debugDescription => 'Android view';
@override
void didStopTrackingLastPointer(int pointer) {
resolve(GestureDisposition.rejected);
}
@override
void handleEvent(PointerEvent event) {
if (!forwardedPointers.contains(event.pointer)) {
cacheEvent(event);
} else {
dispatcher.handlePointerEvent(event);
}
stopTrackingIfPointerNoLongerDown(event);
}
@override
void acceptGesture(int pointer) {
flushPointerCache(pointer);
forwardedPointers.add(pointer);
}
@override
void rejectGesture(int pointer) {
stopTrackingPointer(pointer);
cachedEvents.remove(pointer);
}
void cacheEvent(PointerEvent event) {
if (!cachedEvents.containsKey(event.pointer)) {
cachedEvents[event.pointer] = <PointerEvent> [];
}
cachedEvents[event.pointer].add(event);
}
void flushPointerCache(int pointer) {
cachedEvents.remove(pointer)?.forEach(dispatcher.handlePointerEvent);
}
@override
void stopTrackingPointer(int pointer) {
super.stopTrackingPointer(pointer);
forwardedPointers.remove(pointer);
}
void reset() {
forwardedPointers.forEach(super.stopTrackingPointer);
forwardedPointers.clear();
cachedEvents.keys.forEach(super.stopTrackingPointer);
cachedEvents.clear();
resolve(GestureDisposition.rejected);
_motionEventsDispatcher.handlePointerEvent(event);
}
}
......
......@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
......@@ -22,12 +21,6 @@ import 'framework.dart';
/// The widget fill all available space, the parent of this object must provide bounded layout
/// constraints.
///
/// AndroidView participates in Flutter's [GestureArena]s, and dispatches touch events to the
/// Android view iff it won the arena. Specific gestures that should be dispatched to the Android
/// view can be specified in [AndroidView.gestureRecognizers]. If
/// [AndroidView.gestureRecognizers] is empty, the gesture will be dispatched to the Android
/// view iff it was not claimed by any other gesture recognizer.
///
/// The Android view object is created using a [PlatformViewFactory](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html).
/// Plugins can register platform view factories with [PlatformViewRegistry#registerViewFactory](/javadoc/io/flutter/plugin/platform/PlatformViewRegistry.html#registerViewFactory-java.lang.String-io.flutter.plugin.platform.PlatformViewFactory-).
///
......@@ -48,7 +41,7 @@ import 'framework.dart';
class AndroidView extends StatefulWidget {
/// Creates a widget that embeds an Android view.
///
/// The `viewType`, `hitTestBehavior`, and `gestureRecognizers` parameters must not be null.
/// The `viewType` and `hitTestBehavior` parameters must not be null.
/// If `creationParams` is not null then `creationParamsCodec` must not be null.
AndroidView({
Key key,
......@@ -56,12 +49,10 @@ class AndroidView extends StatefulWidget {
this.onPlatformViewCreated,
this.hitTestBehavior = PlatformViewHitTestBehavior.opaque,
this.layoutDirection,
this.gestureRecognizers = const <OneSequenceGestureRecognizer> [],
this.creationParams,
this.creationParamsCodec
}) : assert(viewType != null),
assert(hitTestBehavior != null),
assert(gestureRecognizers != null),
assert(creationParams == null || creationParamsCodec != null),
super(key: key);
......@@ -87,17 +78,6 @@ class AndroidView extends StatefulWidget {
/// If this is null, the ambient [Directionality] is used instead.
final TextDirection layoutDirection;
/// Which gestures should be forwarded to the Android view.
///
/// The gesture recognizers on this list participate in the gesture arena for each pointer
/// that was put down on the widget. If any of the recognizers on this list wins the
/// gesture arena, the entire pointer event sequence starting from the pointer down event
/// will be dispatched to the Android view.
// We use OneSequenceGestureRecognizers as they support gesture arena teams.
// TODO(amirh): get a list of GestureRecognizers here.
// https://github.com/flutter/flutter/issues/20953
final List<OneSequenceGestureRecognizer> gestureRecognizers;
/// Passed as the args argument of [PlatformViewFactory#create](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html#create-android.content.Context-int-java.lang.Object-)
///
/// This can be used by plugins to pass constructor parameters to the embedded Android view.
......@@ -125,8 +105,7 @@ class _AndroidViewState extends State<AndroidView> {
Widget build(BuildContext context) {
return new _AndroidPlatformView(
controller: _controller,
hitTestBehavior: widget.hitTestBehavior,
gestureRecognizers: widget.gestureRecognizers,
hitTestBehavior: widget.hitTestBehavior
);
}
......@@ -203,28 +182,20 @@ class _AndroidPlatformView extends LeafRenderObjectWidget {
Key key,
@required this.controller,
@required this.hitTestBehavior,
@required this.gestureRecognizers,
}) : assert(controller != null),
assert(hitTestBehavior != null),
assert(gestureRecognizers != null),
super(key: key);
final AndroidViewController controller;
final PlatformViewHitTestBehavior hitTestBehavior;
final List<OneSequenceGestureRecognizer> gestureRecognizers;
@override
RenderObject createRenderObject(BuildContext context) =>
new RenderAndroidView(
viewController: controller,
hitTestBehavior: hitTestBehavior,
gestureRecognizers: gestureRecognizers,
);
new RenderAndroidView(viewController: controller, hitTestBehavior: hitTestBehavior);
@override
void updateRenderObject(BuildContext context, RenderAndroidView renderObject) {
renderObject.viewController = controller;
renderObject.hitTestBehavior = hitTestBehavior;
renderObject.gestureRecognizers = gestureRecognizers;
}
}
......@@ -513,75 +513,4 @@ void main() {
]),
);
});
testWidgets('Android view can lose gesture arenas', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakePlatformViewsController viewsController = new FakePlatformViewsController(TargetPlatform.android);
viewsController.registerViewType('webview');
bool verticalDragAcceptedByParent = false;
await tester.pumpWidget(
new Align(
alignment: Alignment.topLeft,
child: new Container(
margin: const EdgeInsets.all(10.0),
child: GestureDetector(
onVerticalDragStart: (DragStartDetails d) { verticalDragAcceptedByParent = true; },
child: SizedBox(
width: 200.0,
height: 100.0,
child: AndroidView(viewType: 'webview', layoutDirection: TextDirection.ltr),
),
),
),
),
);
final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0));
await gesture.moveBy(const Offset(0.0, 100.0));
await gesture.up();
expect(verticalDragAcceptedByParent, true);
expect(
viewsController.motionEvents[currentViewId + 1],
isNull,
);
});
testWidgets('Android view gesture recognizers', (WidgetTester tester) async {
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
final FakePlatformViewsController viewsController = new FakePlatformViewsController(TargetPlatform.android);
viewsController.registerViewType('webview');
bool verticalDragAcceptedByParent = false;
await tester.pumpWidget(
new Align(
alignment: Alignment.topLeft,
child: GestureDetector(
onVerticalDragStart: (DragStartDetails d) { verticalDragAcceptedByParent = true; },
child: SizedBox(
width: 200.0,
height: 100.0,
child: AndroidView(
viewType: 'webview',
gestureRecognizers: <OneSequenceGestureRecognizer> [new VerticalDragGestureRecognizer()],
layoutDirection: TextDirection.ltr,
),
),
),
),
);
final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0));
await gesture.moveBy(const Offset(0.0, 100.0));
await gesture.up();
expect(verticalDragAcceptedByParent, false);
expect(
viewsController.motionEvents[currentViewId + 1],
orderedEquals(<FakeMotionEvent> [
const FakeMotionEvent(AndroidViewController.kActionDown, <int> [0], <Offset> [Offset(50.0, 50.0)]),
const FakeMotionEvent(AndroidViewController.kActionMove, <int> [0], <Offset> [Offset(50.0, 150.0)]),
const FakeMotionEvent(AndroidViewController.kActionUp, <int> [0], <Offset> [Offset(50.0, 150.0)]),
]),
);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment