Reland: Fix a multiple pointers bug
This relands #68587
diff --git a/packages/flutter/lib/src/gestures/monodrag.dart b/packages/flutter/lib/src/gestures/monodrag.dart
index 5edc715..82ab77d 100644
--- a/packages/flutter/lib/src/gestures/monodrag.dart
+++ b/packages/flutter/lib/src/gestures/monodrag.dart
@@ -386,12 +386,8 @@
void _giveUpPointer(int pointer, {bool reject = true}) {
stopTrackingPointer(pointer);
- if (reject) {
- if (_velocityTrackers.containsKey(pointer)) {
- _velocityTrackers.remove(pointer);
- resolvePointer(pointer, GestureDisposition.rejected);
- }
- }
+ if (reject)
+ resolvePointer(pointer, GestureDisposition.rejected);
}
void _checkDown() {
diff --git a/packages/flutter/lib/src/gestures/recognizer.dart b/packages/flutter/lib/src/gestures/recognizer.dart
index 7eb0b56..6231f79 100644
--- a/packages/flutter/lib/src/gestures/recognizer.dart
+++ b/packages/flutter/lib/src/gestures/recognizer.dart
@@ -268,8 +268,8 @@
void resolvePointer(int pointer, GestureDisposition disposition) {
final GestureArenaEntry? entry = _entries[pointer];
if (entry != null) {
- entry.resolve(disposition);
_entries.remove(pointer);
+ entry.resolve(disposition);
}
}
diff --git a/packages/flutter/test/gestures/drag_test.dart b/packages/flutter/test/gestures/drag_test.dart
index d7cc0f5..725581b 100644
--- a/packages/flutter/test/gestures/drag_test.dart
+++ b/packages/flutter/test/gestures/drag_test.dart
@@ -1151,4 +1151,75 @@
logs.clear();
},
);
+
+ testGesture(
+ 'On multiple pointers, the last tracking pointer can be rejected by [resolvePointer] when the '
+ 'other pointer already accepted the VerticalDragGestureRecognizer',
+ (GestureTester tester) {
+ // Regressing test for https://github.com/flutter/flutter/issues/68373
+ final List<String> logs = <String>[];
+ final VerticalDragGestureRecognizer drag = VerticalDragGestureRecognizer()
+ ..onDown = (DragDownDetails details) { logs.add('downD'); }
+ ..onStart = (DragStartDetails details) { logs.add('startD'); }
+ ..onUpdate = (DragUpdateDetails details) { logs.add('updateD'); }
+ ..onEnd = (DragEndDetails details) { logs.add('endD'); }
+ ..onCancel = () { logs.add('cancelD'); };
+ // Competitor
+ final TapGestureRecognizer tap = TapGestureRecognizer()
+ ..onTapDown = (TapDownDetails details) { logs.add('downT'); }
+ ..onTapUp = (TapUpDetails details) { logs.add('upT'); }
+ ..onTapCancel = () {};
+ addTearDown(tap.dispose);
+ addTearDown(drag.dispose);
+
+ final TestPointer pointer1 = TestPointer(1, PointerDeviceKind.touch);
+ final TestPointer pointer2 = TestPointer(2, PointerDeviceKind.touch);
+ final TestPointer pointer3 = TestPointer(3, PointerDeviceKind.touch);
+ final TestPointer pointer4 = TestPointer(4, PointerDeviceKind.touch);
+
+ final PointerDownEvent down1 = pointer1.down(const Offset(10.0, 10.0));
+ final PointerDownEvent down2 = pointer2.down(const Offset(11.0, 11.0));
+ final PointerDownEvent down3 = pointer3.down(const Offset(12.0, 12.0));
+ final PointerDownEvent down4 = pointer4.down(const Offset(13.0, 13.0));
+
+ tap.addPointer(down1);
+ drag.addPointer(down1);
+ tester.closeArena(pointer1.pointer);
+ tester.route(down1);
+ expect(logs, <String>['downD']);
+ logs.clear();
+
+ tap.addPointer(down2);
+ drag.addPointer(down2);
+ tester.closeArena(pointer2.pointer);
+ tester.route(down2);
+ expect(logs, <String>[]);
+
+ tap.addPointer(down3);
+ drag.addPointer(down3);
+ tester.closeArena(pointer3.pointer);
+ tester.route(down3);
+ expect(logs, <String>[]);
+
+ drag.addPointer(down4);
+ tester.closeArena(pointer4.pointer);
+ tester.route(down4);
+ expect(logs, <String>['startD']);
+ logs.clear();
+
+ tester.route(pointer2.up());
+ GestureBinding.instance!.gestureArena.sweep(pointer2.pointer);
+ expect(logs, <String>[]);
+
+ tester.route(pointer4.cancel());
+ expect(logs, <String>[]);
+
+ tester.route(pointer3.cancel());
+ expect(logs, <String>[]);
+
+ tester.route(pointer1.cancel());
+ expect(logs, <String>['endD']);
+ logs.clear();
+ },
+ );
}