Unverified Commit 137ec45d authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Call onTapCancel when down pointer gets cancelled (#28546)

parent 3054a935
...@@ -174,6 +174,9 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { ...@@ -174,6 +174,9 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
_finalPosition = event.position; _finalPosition = event.position;
_checkUp(); _checkUp();
} else if (event is PointerCancelEvent) { } else if (event is PointerCancelEvent) {
if (_sentTapDown && onTapCancel != null) {
invokeCallback<void>('onTapCancel', onTapCancel);
}
_reset(); _reset();
} }
} }
...@@ -183,6 +186,7 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { ...@@ -183,6 +186,7 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
if (_wonArenaForPrimaryPointer && disposition == GestureDisposition.rejected) { if (_wonArenaForPrimaryPointer && disposition == GestureDisposition.rejected) {
// This can happen if the superclass decides the primary pointer // This can happen if the superclass decides the primary pointer
// exceeded the touch slop, or if the recognizer is disposed. // exceeded the touch slop, or if the recognizer is disposed.
assert(_sentTapDown);
if (onTapCancel != null) if (onTapCancel != null)
invokeCallback<void>('spontaneous onTapCancel', onTapCancel); invokeCallback<void>('spontaneous onTapCancel', onTapCancel);
_reset(); _reset();
...@@ -211,7 +215,7 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer { ...@@ -211,7 +215,7 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
if (pointer == primaryPointer) { if (pointer == primaryPointer) {
// Another gesture won the arena. // Another gesture won the arena.
assert(state != GestureRecognizerState.possible); assert(state != GestureRecognizerState.possible);
if (onTapCancel != null) if (_sentTapDown && onTapCancel != null)
invokeCallback<void>('forced onTapCancel', onTapCancel); invokeCallback<void>('forced onTapCancel', onTapCancel);
_reset(); _reset();
} }
......
...@@ -388,7 +388,6 @@ void main() { ...@@ -388,7 +388,6 @@ void main() {
'tapA onTapDown', 'tapA onTapDown',
'tapA onTapUp', 'tapA onTapUp',
'tapA onTap', 'tapA onTap',
'tapB onTapCancel',
'swept 1', 'swept 1',
'down 2 to A', 'down 2 to A',
'down 2 to B', 'down 2 to B',
...@@ -398,10 +397,74 @@ void main() { ...@@ -398,10 +397,74 @@ void main() {
'tapA onTapDown', 'tapA onTapDown',
'tapA onTapUp', 'tapA onTapUp',
'tapA onTap', 'tapA onTap',
'tapB onTapCancel',
'swept 2', 'swept 2',
'disposed A', 'disposed A',
'disposed B', 'disposed B',
]); ]);
}); });
testGesture('PointerCancelEvent cancels tap', (GestureTester tester) {
const PointerDownEvent down = PointerDownEvent(
pointer: 5,
position: Offset(10.0, 10.0)
);
const PointerCancelEvent cancel = PointerCancelEvent(
pointer: 5,
position: Offset(10.0, 10.0)
);
final TapGestureRecognizer tap = TapGestureRecognizer();
final List<String> recognized = <String>[];
tap.onTapDown = (_) {
recognized.add('down');
};
tap.onTapUp = (_) {
recognized.add('up');
};
tap.onTap = () {
recognized.add('tap');
};
tap.onTapCancel = () {
recognized.add('cancel');
};
tap.addPointer(down);
tester.closeArena(5);
tester.async.elapse(const Duration(milliseconds: 5000));
expect(recognized, <String>['down']);
tester.route(cancel);
expect(recognized, <String>['down', 'cancel']);
tap.dispose();
});
testGesture('losing tap gesture recognizer does not send onTapCancel', (GestureTester tester) {
final TapGestureRecognizer tap = TapGestureRecognizer();
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
final List<String> recognized = <String>[];
tap.onTapDown = (_) {
recognized.add('down');
};
tap.onTapUp = (_) {
recognized.add('up');
};
tap.onTap = () {
recognized.add('tap');
};
tap.onTapCancel = () {
recognized.add('cancel');
};
tap.addPointer(down3);
drag.addPointer(down3);
tester.closeArena(3);
tester.route(move3);
GestureBinding.instance.gestureArena.sweep(3);
expect(recognized, isEmpty);
tap.dispose();
drag.dispose();
});
} }
...@@ -54,7 +54,7 @@ void main() { ...@@ -54,7 +54,7 @@ void main() {
await tester.tap(find.byType(InkWell), pointer: 2); await tester.tap(find.byType(InkWell), pointer: 2);
await tester.tap(find.byType(InkWell), pointer: 3); await tester.tap(find.byType(InkWell), pointer: 3);
expect(log, equals(<String>['tap-cancel', 'double-tap'])); expect(log, equals(<String>['double-tap']));
log.clear(); log.clear();
await tester.longPress(find.byType(InkWell), pointer: 4); await tester.longPress(find.byType(InkWell), pointer: 4);
......
...@@ -287,33 +287,32 @@ void main() { ...@@ -287,33 +287,32 @@ void main() {
); );
// Pointer is dragged from the center of the 800x100 gesture detector // Pointer is dragged from the center of the 800x100 gesture detector
// to a point (400,300) below it. This always causes onTapCancel to be // to a point (400,300) below it. This should never call onTap.
// called; onTap should never be called.
Future<void> dragOut(Duration timeout) async { Future<void> dragOut(Duration timeout) async {
final TestGesture gesture = await tester.startGesture(const Offset(400.0, 50.0)); final TestGesture gesture = await tester.startGesture(const Offset(400.0, 50.0));
// If the timeout is less than kPressTimeout the recognizer will just trigger // If the timeout is less than kPressTimeout the recognizer will not
// the onTapCancel callback. If the timeout is greater than kLongPressTimeout // trigger any callbacks. If the timeout is greater than kLongPressTimeout
// then onTapDown, onLongPress, and onCancel will be called. // then onTapDown, onLongPress, and onCancel will be called.
await tester.pump(timeout); await tester.pump(timeout);
await gesture.moveTo(const Offset(400.0, 300.0)); await gesture.moveTo(const Offset(400.0, 300.0));
await gesture.up(); await gesture.up();
} }
await dragOut(kPressTimeout * 0.5); // generates tapCancel await dragOut(kPressTimeout * 0.5); // generates nothing
expect(tapDown, 0); expect(tapDown, 0);
expect(tapCancel, 1); expect(tapCancel, 0);
expect(tap, 0); expect(tap, 0);
expect(longPress, 0); expect(longPress, 0);
await dragOut(kPressTimeout); // generates tapDown, tapCancel await dragOut(kPressTimeout); // generates tapDown, tapCancel
expect(tapDown, 1); expect(tapDown, 1);
expect(tapCancel, 2); expect(tapCancel, 1);
expect(tap, 0); expect(tap, 0);
expect(longPress, 0); expect(longPress, 0);
await dragOut(kLongPressTimeout); // generates tapDown, longPress, tapCancel await dragOut(kLongPressTimeout); // generates tapDown, longPress, tapCancel
expect(tapDown, 2); expect(tapDown, 2);
expect(tapCancel, 3); expect(tapCancel, 2);
expect(tap, 0); expect(tap, 0);
expect(longPress, 1); expect(longPress, 1);
}); });
......
...@@ -119,7 +119,7 @@ void main() { ...@@ -119,7 +119,7 @@ void main() {
expect(singleLongTapStartCount, 0); expect(singleLongTapStartCount, 0);
}); });
testWidgets('a very quick swipe is just a canceled tap', (WidgetTester tester) async { testWidgets('a very quick swipe is ignored', (WidgetTester tester) async {
await pumpGestureDetector(tester); await pumpGestureDetector(tester);
final TestGesture gesture = await tester.startGesture(const Offset(200, 200)); final TestGesture gesture = await tester.startGesture(const Offset(200, 200));
await tester.pump(const Duration(milliseconds: 20)); await tester.pump(const Duration(milliseconds: 20));
...@@ -127,7 +127,7 @@ void main() { ...@@ -127,7 +127,7 @@ void main() {
await tester.pump(); await tester.pump();
expect(singleTapUpCount, 0); expect(singleTapUpCount, 0);
expect(tapCount, 0); expect(tapCount, 0);
expect(singleTapCancelCount, 1); expect(singleTapCancelCount, 0);
expect(doubleTapDownCount, 0); expect(doubleTapDownCount, 0);
expect(singleLongTapStartCount, 0); expect(singleLongTapStartCount, 0);
...@@ -135,7 +135,7 @@ void main() { ...@@ -135,7 +135,7 @@ void main() {
// Nothing else happens on up. // Nothing else happens on up.
expect(singleTapUpCount, 0); expect(singleTapUpCount, 0);
expect(tapCount, 0); expect(tapCount, 0);
expect(singleTapCancelCount, 1); expect(singleTapCancelCount, 0);
expect(doubleTapDownCount, 0); expect(doubleTapDownCount, 0);
expect(singleLongTapStartCount, 0); expect(singleLongTapStartCount, 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