Commit 7925e060 authored by Hixie's avatar Hixie

Fix double tap constants, add a doubletap test

Document the Gesture Detector constants.

Remove kEdgeSlop since it's obsolete on Android.

Add a test that verifies that when the first tap is canceled, the second
tap can become the first tap of a subsequent two-tap sequence.
parent 055b6426
...@@ -5,21 +5,86 @@ ...@@ -5,21 +5,86 @@
// Modeled after Android's ViewConfiguration: // Modeled after Android's ViewConfiguration:
// 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
/// The time that must elapse before a tap gesture sends onTapDown, if there's
/// any doubt that the gesture is a tap.
const Duration kPressTimeout = const Duration(milliseconds: 100); const Duration kPressTimeout = const Duration(milliseconds: 100);
/// Maximum length of time between a tap down and a tap up for the gesture to be
/// considered a tap. (Currently not honored by the TapGestureRecognizer.)
// TODO(ianh): Remove this, or implement a hover-tap gesture recogniser which
// uses this.
const Duration kHoverTapTimeout = const Duration(milliseconds: 150);
/// Maximum distance between the down and up pointers for a tap. (Currently not
/// honored by the [TapGestureRecognizer]; [PrimaryPointerGestureRecognizer],
/// which TapGestureRecognizer inherits from, uses [kTouchSlop].)
// TODO(ianh): Remove this or implement it correctly.
const double kHoverTapSlop = 20.0; // Logical pixels
/// The time before a long press gesture attempts to win.
const Duration kLongPressTimeout = const Duration(milliseconds: 500); const Duration kLongPressTimeout = const Duration(milliseconds: 500);
const Duration kJumpTapTimeout = const Duration(milliseconds: 500);
/// The maximum time from the start of the first tap to the start of the second
/// tap in a double-tap gesture.
// TODO(ianh): In Android, this is actually the time from the first's up event
// to the second's down event, according to the ViewConfiguration docs.
const Duration kDoubleTapTimeout = const Duration(milliseconds: 300); const Duration kDoubleTapTimeout = const Duration(milliseconds: 300);
/// The minimum time from the end of the first tap to the start of the second
/// tap in a double-tap gesture. (Currently not honored by the
/// DoubleTapGestureRecognizer.)
// TODO(ianh): Either implement this or remove the constant.
const Duration kDoubleTapMinTime = const Duration(milliseconds: 40); const Duration kDoubleTapMinTime = const Duration(milliseconds: 40);
const Duration kHoverTapTimeout = const Duration(milliseconds: 150);
/// The maximum distance that the first touch in a double-tap gesture can travel
/// before deciding that it is not part of a double-tap gesture.
/// DoubleTapGestureRecognizer also restricts the second touch to this distance.
const double kDoubleTapTouchSlop = kTouchSlop; // Logical pixels
/// Distance between the initial position of the first touch and the start
/// position of a potential second touch for the second touch to be considered
/// the second touch of a double-tap gesture.
const double kDoubleTapSlop = 100.0; // Logical pixels
/// The time for which zoom controls (e.g. in a map interface) are to be
/// displayed on the screen, from the moment they were last requested.
const Duration kZoomControlsTimeout = const Duration(milliseconds: 3000); const Duration kZoomControlsTimeout = const Duration(milliseconds: 3000);
const double kHoverTapSlop = 20.0; // Logical pixels
const double kEdgeSlop = 12.0; // Logical pixels /// The distance a touch has to travel for us to be confident that the gesture
/// is a scroll gesture.
const double kTouchSlop = 8.0; // Logical pixels const double kTouchSlop = 8.0; // Logical pixels
const double kDoubleTapTouchSlop = kTouchSlop; // Logical pixels
/// The distance a touch has to travel for us to be confident that the gesture
/// is a paging gesture. (Currently not used, because paging uses a regular drag
/// gesture, which uses kTouchSlop.)
// TODO(ianh): Create variants of HorizontalDragGestureRecognizer et al for
// paging, which use this constant.
const double kPagingTouchSlop = kTouchSlop * 2.0; // Logical pixels const double kPagingTouchSlop = kTouchSlop * 2.0; // Logical pixels
/// The distance a touch has to travel for us to be confident that the gesture
/// is a panning gesture.
const double kPanSlop = kTouchSlop * 2.0; // Logical pixels const double kPanSlop = kTouchSlop * 2.0; // Logical pixels
/// The distance a touch has to travel for us to be confident that the gesture
/// is a scale gesture.
const double kScaleSlop = kTouchSlop; // Logical pixels const double kScaleSlop = kTouchSlop; // Logical pixels
const double kDoubleTapSlop = 100.0; // Logical pixels
/// The margin around a dialog, popup menu, or other window-like widget inside
/// which we do not consider a tap to dismiss the widget. (Not currently used.)
// TODO(ianh): Make ModalBarrier support this.
const double kWindowTouchSlop = 16.0; // Logical pixels const double kWindowTouchSlop = 16.0; // Logical pixels
/// The minimum velocity for a touch to consider that touch to trigger a fling
/// gesture.
// TODO(ianh): Make sure nobody has their own version of this.
const double kMinFlingVelocity = 50.0; // Logical pixels / second const double kMinFlingVelocity = 50.0; // Logical pixels / second
/// The maximum velocity of a touch to consider that touch to trigger a fling
/// gesture.
// TODO(ianh): Make sure nobody has their own version of this.
const double kMaxFlingVelocity = 8000.0; // Logical pixels / second const double kMaxFlingVelocity = 8000.0; // Logical pixels / second
/// The maximum time from the start of the first tap to the start of the second
/// tap in a jump-tap gesture.
// TODO(ianh): Implement jump-tap gestures.
const Duration kJumpTapTimeout = const Duration(milliseconds: 500);
...@@ -84,7 +84,7 @@ class DoubleTapGestureRecognizer extends GestureArenaMember { ...@@ -84,7 +84,7 @@ class DoubleTapGestureRecognizer extends GestureArenaMember {
void addPointer(PointerInputEvent event) { void addPointer(PointerInputEvent event) {
// Ignore out-of-bounds second taps // Ignore out-of-bounds second taps
if (_firstTap != null && if (_firstTap != null &&
!_firstTap.isWithinTolerance(event, kDoubleTapTouchSlop)) !_firstTap.isWithinTolerance(event, kDoubleTapSlop))
return; return;
_stopDoubleTapTimer(); _stopDoubleTapTimer();
_TapTracker tracker = new _TapTracker( _TapTracker tracker = new _TapTracker(
...@@ -104,7 +104,7 @@ class DoubleTapGestureRecognizer extends GestureArenaMember { ...@@ -104,7 +104,7 @@ class DoubleTapGestureRecognizer extends GestureArenaMember {
else else
_registerSecondTap(tracker); _registerSecondTap(tracker);
} else if (event.type == 'pointermove' && } else if (event.type == 'pointermove' &&
!tracker.isWithinTolerance(event, kTouchSlop)) { !tracker.isWithinTolerance(event, kDoubleTapTouchSlop)) {
_reject(tracker); _reject(tracker);
} else if (event.type == 'pointercancel') { } else if (event.type == 'pointercancel') {
_reject(tracker); _reject(tracker);
......
...@@ -49,15 +49,15 @@ void main() { ...@@ -49,15 +49,15 @@ void main() {
final PointerInputEvent down3 = new PointerInputEvent( final PointerInputEvent down3 = new PointerInputEvent(
pointer: 3, pointer: 3,
type: 'pointerdown', type: 'pointerdown',
x: 30.0, x: 130.0,
y: 30.0 y: 130.0
); );
final PointerInputEvent up3 = new PointerInputEvent( final PointerInputEvent up3 = new PointerInputEvent(
pointer: 3, pointer: 3,
type: 'pointerup', type: 'pointerup',
x: 31.0, x: 131.0,
y: 29.0 y: 129.0
); );
// Down/move/up sequence 4: intervening motion // Down/move/up sequence 4: intervening motion
...@@ -82,6 +82,21 @@ void main() { ...@@ -82,6 +82,21 @@ void main() {
y: 25.0 y: 25.0
); );
// Down/up pair 5: normal tap sequence identical to pair 1 with different pointer
final PointerInputEvent down5 = new PointerInputEvent(
pointer: 5,
type: 'pointerdown',
x: 10.0,
y: 10.0
);
final PointerInputEvent up5 = new PointerInputEvent(
pointer: 5,
type: 'pointerup',
x: 11.0,
y: 9.0
);
test('Should recognize double tap', () { test('Should recognize double tap', () {
PointerRouter router = new PointerRouter(); PointerRouter router = new PointerRouter();
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router); DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
...@@ -223,6 +238,55 @@ void main() { ...@@ -223,6 +238,55 @@ void main() {
tap.dispose(); tap.dispose();
}); });
test('Inter-tap delay resets double tap, allowing third tap to be a double-tap', () {
PointerRouter router = new PointerRouter();
DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer(router: router);
bool doubleTapRecognized = false;
tap.onDoubleTap = () {
doubleTapRecognized = true;
};
new FakeAsync().run((FakeAsync async) {
tap.addPointer(down1);
GestureArena.instance.close(1);
expect(doubleTapRecognized, isFalse);
router.route(down1);
expect(doubleTapRecognized, isFalse);
router.route(up1);
expect(doubleTapRecognized, isFalse);
GestureArena.instance.sweep(1);
expect(doubleTapRecognized, isFalse);
async.elapse(new Duration(milliseconds: 5000));
tap.addPointer(down2);
GestureArena.instance.close(2);
expect(doubleTapRecognized, isFalse);
router.route(down2);
expect(doubleTapRecognized, isFalse);
router.route(up2);
expect(doubleTapRecognized, isFalse);
GestureArena.instance.sweep(2);
expect(doubleTapRecognized, isFalse);
async.elapse(new Duration(milliseconds: 100));
tap.addPointer(down5);
GestureArena.instance.close(5);
expect(doubleTapRecognized, isFalse);
router.route(down5);
expect(doubleTapRecognized, isFalse);
router.route(up5);
expect(doubleTapRecognized, isTrue);
GestureArena.instance.sweep(5);
expect(doubleTapRecognized, isTrue);
});
tap.dispose();
});
test('Intra-tap delay does not cancel 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);
......
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