Commit 5d0c090d authored by krisgiesing's avatar krisgiesing

Merge pull request #1799 from krisgiesing/tap-fix

Restore previous tap behaviors: no timeout, one pointer
parents b1b47435 f2fd5e32
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
// https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewConfiguration.java // https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewConfiguration.java
const Duration kLongPressTimeout = const Duration(milliseconds: 500); const Duration kLongPressTimeout = const Duration(milliseconds: 500);
const Duration kTapTimeout = const Duration(milliseconds: 100); const Duration kPressTimeout = const Duration(milliseconds: 100);
const Duration kJumpTapTimeout = const Duration(milliseconds: 500); const Duration kJumpTapTimeout = const Duration(milliseconds: 500);
const Duration kDoubleTapTimeout = const Duration(milliseconds: 300); const Duration kDoubleTapTimeout = const Duration(milliseconds: 300);
const Duration kDoubleTapMinTime = const Duration(milliseconds: 40); const Duration kDoubleTapMinTime = const Duration(milliseconds: 40);
......
...@@ -52,7 +52,6 @@ class DoubleTapGestureRecognizer extends DisposableArenaMember { ...@@ -52,7 +52,6 @@ class DoubleTapGestureRecognizer extends DisposableArenaMember {
entry: GestureArena.instance.add(event.pointer, this) entry: GestureArena.instance.add(event.pointer, this)
); );
_trackers[event.pointer] = tracker; _trackers[event.pointer] = tracker;
tracker.startTimer(() => _reject(tracker));
tracker.startTrackingPointer(router, handleEvent); tracker.startTrackingPointer(router, handleEvent);
} }
...@@ -145,7 +144,6 @@ class DoubleTapGestureRecognizer extends DisposableArenaMember { ...@@ -145,7 +144,6 @@ class DoubleTapGestureRecognizer extends DisposableArenaMember {
} }
void _freezeTracker(TapTracker tracker) { void _freezeTracker(TapTracker tracker) {
tracker.stopTimer();
tracker.stopTrackingPointer(router, handleEvent); tracker.stopTrackingPointer(router, handleEvent);
} }
......
...@@ -12,7 +12,7 @@ typedef void GestureLongPressCallback(); ...@@ -12,7 +12,7 @@ typedef void GestureLongPressCallback();
class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer { class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
LongPressGestureRecognizer({ PointerRouter router, this.onLongPress }) LongPressGestureRecognizer({ PointerRouter router, this.onLongPress })
: super(router: router, deadline: kTapTimeout + kLongPressTimeout); : super(router: router, deadline: kLongPressTimeout);
GestureLongPressCallback onLongPress; GestureLongPressCallback onLongPress;
......
...@@ -11,7 +11,7 @@ typedef void GestureShowPressCallback(); ...@@ -11,7 +11,7 @@ typedef void GestureShowPressCallback();
class ShowPressGestureRecognizer extends PrimaryPointerGestureRecognizer { class ShowPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
ShowPressGestureRecognizer({ PointerRouter router, this.onShowPress }) ShowPressGestureRecognizer({ PointerRouter router, this.onShowPress })
: super(router: router, deadline: kTapTimeout); : super(router: router, deadline: kPressTimeout);
GestureShowPressCallback onShowPress; GestureShowPressCallback onShowPress;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'arena.dart'; import 'arena.dart';
...@@ -13,9 +12,56 @@ import 'recognizer.dart'; ...@@ -13,9 +12,56 @@ import 'recognizer.dart';
typedef void GestureTapCallback(); typedef void GestureTapCallback();
enum TapResolution { /// TapGestureRecognizer is a tap recognizer that tracks only one primary
tap, /// pointer per gesture. That is, during tap recognition, extra pointer events
cancel /// are ignored: down-1, down-2, up-1, up-2 produces only one tap on up-1.
class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
TapGestureRecognizer({ PointerRouter router, this.onTap })
: super(router: router);
GestureTapCallback onTap;
GestureTapCallback onTapDown;
GestureTapCallback onTapCancel;
bool _wonArena = false;
bool _didTap = false;
void handlePrimaryPointer(PointerInputEvent event) {
if (event.type == 'pointerdown') {
if (onTapDown != null)
onTapDown();
} else if (event.type == 'pointerup') {
_didTap = true;
_check();
}
}
void acceptGesture(int pointer) {
super.acceptGesture(pointer);
if (pointer == primaryPointer) {
_wonArena = true;
_check();
}
}
void rejectGesture(int pointer) {
super.rejectGesture(pointer);
if (pointer == primaryPointer) {
assert(state == GestureRecognizerState.defunct);
_wonArena = false;
_didTap = false;
if (onTapCancel != null)
onTapCancel();
}
}
void _check() {
if (_wonArena && _didTap) {
resolve(GestureDisposition.accepted);
if (onTap != null)
onTap();
}
}
} }
/// TapTracker helps track individual tap sequences as part of a /// TapTracker helps track individual tap sequences as part of a
...@@ -33,18 +79,6 @@ class TapTracker { ...@@ -33,18 +79,6 @@ class TapTracker {
GestureArenaEntry entry; GestureArenaEntry entry;
ui.Point _initialPosition; ui.Point _initialPosition;
bool _isTrackingPointer; bool _isTrackingPointer;
Timer _timer;
void startTimer(void callback()) {
_timer ??= new Timer(kTapTimeout, callback);
}
void stopTimer() {
if (_timer != null) {
_timer.cancel();
_timer = null;
}
}
void startTrackingPointer(PointerRouter router, PointerRoute route) { void startTrackingPointer(PointerRouter router, PointerRoute route) {
if (!_isTrackingPointer) { if (!_isTrackingPointer) {
...@@ -67,6 +101,11 @@ class TapTracker { ...@@ -67,6 +101,11 @@ class TapTracker {
} }
enum TapResolution {
tap,
cancel
}
/// TapGesture represents a full gesture resulting from a single tap /// TapGesture represents a full gesture resulting from a single tap
/// sequence. Tap gestures are passive, meaning that they will not /// sequence. Tap gestures are passive, meaning that they will not
/// pre-empt any other arena member in play. /// pre-empt any other arena member in play.
...@@ -77,11 +116,10 @@ class TapGesture extends TapTracker { ...@@ -77,11 +116,10 @@ class TapGesture extends TapTracker {
entry = GestureArena.instance.add(event.pointer, gestureRecognizer); entry = GestureArena.instance.add(event.pointer, gestureRecognizer);
_wonArena = false; _wonArena = false;
_didTap = false; _didTap = false;
startTimer(cancel);
startTrackingPointer(gestureRecognizer.router, handleEvent); startTrackingPointer(gestureRecognizer.router, handleEvent);
} }
TapGestureRecognizer gestureRecognizer; MultiTapGestureRecognizer gestureRecognizer;
bool _wonArena; bool _wonArena;
bool _didTap; bool _didTap;
...@@ -93,7 +131,6 @@ class TapGesture extends TapTracker { ...@@ -93,7 +131,6 @@ class TapGesture extends TapTracker {
} else if (event.type == 'pointercancel') { } else if (event.type == 'pointercancel') {
cancel(); cancel();
} else if (event.type == 'pointerup') { } else if (event.type == 'pointerup') {
stopTimer();
stopTrackingPointer(gestureRecognizer.router, handleEvent); stopTrackingPointer(gestureRecognizer.router, handleEvent);
_didTap = true; _didTap = true;
_check(); _check();
...@@ -106,7 +143,6 @@ class TapGesture extends TapTracker { ...@@ -106,7 +143,6 @@ class TapGesture extends TapTracker {
} }
void reject() { void reject() {
stopTimer();
stopTrackingPointer(gestureRecognizer.router, handleEvent); stopTrackingPointer(gestureRecognizer.router, handleEvent);
gestureRecognizer._resolveTap(pointer, TapResolution.cancel); gestureRecognizer._resolveTap(pointer, TapResolution.cancel);
} }
...@@ -127,8 +163,12 @@ class TapGesture extends TapTracker { ...@@ -127,8 +163,12 @@ class TapGesture extends TapTracker {
} }
class TapGestureRecognizer extends DisposableArenaMember { /// MultiTapGestureRecognizer is a tap recognizer that treats taps
TapGestureRecognizer({ this.router, this.onTap, this.onTapDown, this.onTapCancel }); /// independently. That is, each pointer sequence that could resolve to a tap
/// does so independently of others: down-1, down-2, up-1, up-2 produces two
/// taps, on up-1 and up-2.
class MultiTapGestureRecognizer extends DisposableArenaMember {
MultiTapGestureRecognizer({ this.router, this.onTap, this.onTapDown, this.onTapCancel });
PointerRouter router; PointerRouter router;
GestureTapCallback onTap; GestureTapCallback onTap;
......
...@@ -35,8 +35,8 @@ class _InkSplash { ...@@ -35,8 +35,8 @@ class _InkSplash {
duration: new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor()) duration: new Duration(milliseconds: (_targetRadius / _kSplashUnconfirmedVelocity).floor())
)..addListener(_handleRadiusChange); )..addListener(_handleRadiusChange);
// Wait kTapTimeout to avoid creating tiny splashes during scrolls. // Wait kPressTimeout to avoid creating tiny splashes during scrolls.
_startTimer = new Timer(kTapTimeout, _play); _startTimer = new Timer(kPressTimeout, _play);
} }
final Point position; final Point position;
......
...@@ -223,7 +223,7 @@ void main() { ...@@ -223,7 +223,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Intra-tap delay cancels double tap', () { test('Intra-tap delay does not cancel double tap', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
...@@ -252,9 +252,9 @@ void main() { ...@@ -252,9 +252,9 @@ void main() {
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isFalse);
router.route(up2); router.route(up2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isTrue);
GestureArena.instance.sweep(2); GestureArena.instance.sweep(2);
expect(doubleTapRecognized, isFalse); expect(doubleTapRecognized, isTrue);
}); });
tap.dispose(); tap.dispose();
......
...@@ -84,7 +84,7 @@ void main() { ...@@ -84,7 +84,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Should recognize two overlapping taps', () { test('Should not recognize two overlapping taps', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
...@@ -112,9 +112,9 @@ void main() { ...@@ -112,9 +112,9 @@ void main() {
expect(tapsRecognized, 1); expect(tapsRecognized, 1);
router.route(up2); router.route(up2);
expect(tapsRecognized, 2); expect(tapsRecognized, 1);
GestureArena.instance.sweep(2); GestureArena.instance.sweep(2);
expect(tapsRecognized, 2); expect(tapsRecognized, 1);
tap.dispose(); tap.dispose();
}); });
...@@ -144,7 +144,7 @@ void main() { ...@@ -144,7 +144,7 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Timeout cancels tap', () { test('Timeout does not cancel tap', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
TapGestureRecognizer tap = new TapGestureRecognizer(router: router); TapGestureRecognizer tap = new TapGestureRecognizer(router: router);
...@@ -163,9 +163,9 @@ void main() { ...@@ -163,9 +163,9 @@ void main() {
async.elapse(new Duration(milliseconds: 500)); async.elapse(new Duration(milliseconds: 500));
expect(tapRecognized, isFalse); expect(tapRecognized, isFalse);
router.route(up1); router.route(up1);
expect(tapRecognized, isFalse); expect(tapRecognized, isTrue);
GestureArena.instance.sweep(1); GestureArena.instance.sweep(1);
expect(tapRecognized, isFalse); expect(tapRecognized, isTrue);
}); });
tap.dispose(); tap.dispose();
......
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