double_tap_test.dart 14.7 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7 8
import 'package:flutter/gestures.dart';
import 'package:quiver/testing/async.dart';
import 'package:test/test.dart';

9 10
import 'gesture_tester.dart';

11
class TestGestureArenaMember extends GestureArenaMember {
12
  @override
13
  void acceptGesture(int key) {
14 15
    accepted = true;
  }
16 17

  @override
18
  void rejectGesture(int key) {
19 20
    rejected = true;
  }
21

22 23
  bool accepted = false;
  bool rejected = false;
24 25 26
}

void main() {
27
  setUp(ensureGestureBinding);
28 29

  // Down/up pair 1: normal tap sequence
Ian Hickson's avatar
Ian Hickson committed
30
  const PointerDownEvent down1 = const PointerDownEvent(
31
    pointer: 1,
Ian Hickson's avatar
Ian Hickson committed
32
    position: const Point(10.0, 10.0)
33 34
  );

Ian Hickson's avatar
Ian Hickson committed
35
  const PointerUpEvent up1 = const PointerUpEvent(
36
    pointer: 1,
Ian Hickson's avatar
Ian Hickson committed
37
    position: const Point(11.0, 9.0)
38 39 40
  );

  // Down/up pair 2: normal tap sequence close to pair 1
Ian Hickson's avatar
Ian Hickson committed
41
  const PointerDownEvent down2 = const PointerDownEvent(
42
    pointer: 2,
Ian Hickson's avatar
Ian Hickson committed
43
    position: const Point(12.0, 12.0)
44 45
  );

Ian Hickson's avatar
Ian Hickson committed
46
  const PointerUpEvent up2 = const PointerUpEvent(
47
    pointer: 2,
Ian Hickson's avatar
Ian Hickson committed
48
    position: const Point(13.0, 11.0)
49 50 51
  );

  // Down/up pair 3: normal tap sequence far away from pair 1
Ian Hickson's avatar
Ian Hickson committed
52
  const PointerDownEvent down3 = const PointerDownEvent(
53
    pointer: 3,
Ian Hickson's avatar
Ian Hickson committed
54
    position: const Point(130.0, 130.0)
55 56
  );

Ian Hickson's avatar
Ian Hickson committed
57
  const PointerUpEvent up3 = const PointerUpEvent(
58
    pointer: 3,
Ian Hickson's avatar
Ian Hickson committed
59
    position: const Point(131.0, 129.0)
60 61 62
  );

  // Down/move/up sequence 4: intervening motion
Ian Hickson's avatar
Ian Hickson committed
63
  const PointerDownEvent down4 = const PointerDownEvent(
64
    pointer: 4,
Ian Hickson's avatar
Ian Hickson committed
65
    position: const Point(10.0, 10.0)
66 67
  );

Ian Hickson's avatar
Ian Hickson committed
68
  const PointerMoveEvent move4 = const PointerMoveEvent(
69
    pointer: 4,
Ian Hickson's avatar
Ian Hickson committed
70
    position: const Point(25.0, 25.0)
71 72
  );

Ian Hickson's avatar
Ian Hickson committed
73
  const PointerUpEvent up4 = const PointerUpEvent(
74
    pointer: 4,
Ian Hickson's avatar
Ian Hickson committed
75
    position: const Point(25.0, 25.0)
76 77
  );

78
  // Down/up pair 5: normal tap sequence identical to pair 1 with different pointer
Ian Hickson's avatar
Ian Hickson committed
79
  const PointerDownEvent down5 = const PointerDownEvent(
80
    pointer: 5,
Ian Hickson's avatar
Ian Hickson committed
81
    position: const Point(10.0, 10.0)
82 83
  );

Ian Hickson's avatar
Ian Hickson committed
84
  const PointerUpEvent up5 = const PointerUpEvent(
85
    pointer: 5,
Ian Hickson's avatar
Ian Hickson committed
86
    position: const Point(11.0, 9.0)
87 88
  );

89
  testGesture('Should recognize double tap', (GestureTester tester) {
90
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
91 92 93 94 95 96 97

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    tap.addPointer(down1);
98
    tester.closeArena(1);
99
    expect(doubleTapRecognized, isFalse);
100
    tester.route(down1);
101 102
    expect(doubleTapRecognized, isFalse);

103
    tester.route(up1);
104
    expect(doubleTapRecognized, isFalse);
105
    GestureBinding.instance.gestureArena.sweep(1);
106 107 108
    expect(doubleTapRecognized, isFalse);

    tap.addPointer(down2);
109
    tester.closeArena(2);
110
    expect(doubleTapRecognized, isFalse);
111
    tester.route(down2);
112 113
    expect(doubleTapRecognized, isFalse);

114
    tester.route(up2);
115
    expect(doubleTapRecognized, isTrue);
116
    GestureBinding.instance.gestureArena.sweep(2);
117 118 119 120 121
    expect(doubleTapRecognized, isTrue);

    tap.dispose();
  });

122
  testGesture('Inter-tap distance cancels double tap', (GestureTester tester) {
123
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
124 125 126 127 128 129 130

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    tap.addPointer(down1);
131
    tester.closeArena(1);
132
    expect(doubleTapRecognized, isFalse);
133
    tester.route(down1);
134 135
    expect(doubleTapRecognized, isFalse);

136
    tester.route(up1);
137
    expect(doubleTapRecognized, isFalse);
138
    GestureBinding.instance.gestureArena.sweep(1);
139 140 141
    expect(doubleTapRecognized, isFalse);

    tap.addPointer(down3);
142
    tester.closeArena(3);
143
    expect(doubleTapRecognized, isFalse);
144
    tester.route(down3);
145 146
    expect(doubleTapRecognized, isFalse);

147
    tester.route(up3);
148
    expect(doubleTapRecognized, isFalse);
149
    GestureBinding.instance.gestureArena.sweep(3);
150 151 152 153 154
    expect(doubleTapRecognized, isFalse);

    tap.dispose();
  });

155
  testGesture('Intra-tap distance cancels double tap', (GestureTester tester) {
156
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
157 158 159 160 161 162 163

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    tap.addPointer(down4);
164
    tester.closeArena(4);
165
    expect(doubleTapRecognized, isFalse);
166
    tester.route(down4);
167 168
    expect(doubleTapRecognized, isFalse);

169
    tester.route(move4);
170
    expect(doubleTapRecognized, isFalse);
171
    tester.route(up4);
172
    expect(doubleTapRecognized, isFalse);
173
    GestureBinding.instance.gestureArena.sweep(4);
174 175 176
    expect(doubleTapRecognized, isFalse);

    tap.addPointer(down1);
177
    tester.closeArena(1);
178
    expect(doubleTapRecognized, isFalse);
179
    tester.route(down2);
180 181
    expect(doubleTapRecognized, isFalse);

182
    tester.route(up1);
183
    expect(doubleTapRecognized, isFalse);
184
    GestureBinding.instance.gestureArena.sweep(1);
185 186 187 188 189
    expect(doubleTapRecognized, isFalse);

    tap.dispose();
  });

190
  testGesture('Inter-tap delay cancels double tap', (GestureTester tester) {
191
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
192 193 194 195 196 197

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

198 199 200 201 202
    tap.addPointer(down1);
    tester.closeArena(1);
    expect(doubleTapRecognized, isFalse);
    tester.route(down1);
    expect(doubleTapRecognized, isFalse);
203

204 205 206 207
    tester.route(up1);
    expect(doubleTapRecognized, isFalse);
    GestureBinding.instance.gestureArena.sweep(1);
    expect(doubleTapRecognized, isFalse);
208

209 210 211 212 213 214
    tester.async.elapse(new Duration(milliseconds: 5000));
    tap.addPointer(down2);
    tester.closeArena(2);
    expect(doubleTapRecognized, isFalse);
    tester.route(down2);
    expect(doubleTapRecognized, isFalse);
215

216 217 218 219
    tester.route(up2);
    expect(doubleTapRecognized, isFalse);
    GestureBinding.instance.gestureArena.sweep(2);
    expect(doubleTapRecognized, isFalse);
220 221 222 223

    tap.dispose();
  });

224
  testGesture('Inter-tap delay resets double tap, allowing third tap to be a double-tap', (GestureTester tester) {
225
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
226 227 228 229 230 231

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

232 233 234 235 236
    tap.addPointer(down1);
    tester.closeArena(1);
    expect(doubleTapRecognized, isFalse);
    tester.route(down1);
    expect(doubleTapRecognized, isFalse);
237

238 239 240 241
    tester.route(up1);
    expect(doubleTapRecognized, isFalse);
    GestureBinding.instance.gestureArena.sweep(1);
    expect(doubleTapRecognized, isFalse);
242

243 244 245 246 247 248
    tester.async.elapse(new Duration(milliseconds: 5000));
    tap.addPointer(down2);
    tester.closeArena(2);
    expect(doubleTapRecognized, isFalse);
    tester.route(down2);
    expect(doubleTapRecognized, isFalse);
249

250 251 252 253
    tester.route(up2);
    expect(doubleTapRecognized, isFalse);
    GestureBinding.instance.gestureArena.sweep(2);
    expect(doubleTapRecognized, isFalse);
254

255 256 257 258 259 260
    tester.async.elapse(new Duration(milliseconds: 100));
    tap.addPointer(down5);
    tester.closeArena(5);
    expect(doubleTapRecognized, isFalse);
    tester.route(down5);
    expect(doubleTapRecognized, isFalse);
261

262 263 264 265
    tester.route(up5);
    expect(doubleTapRecognized, isTrue);
    GestureBinding.instance.gestureArena.sweep(5);
    expect(doubleTapRecognized, isTrue);
266 267 268 269

    tap.dispose();
  });

270
  testGesture('Intra-tap delay does not cancel double tap', (GestureTester tester) {
271
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
272 273 274 275 276 277

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

278 279 280 281 282
    tap.addPointer(down1);
    tester.closeArena(1);
    expect(doubleTapRecognized, isFalse);
    tester.route(down1);
    expect(doubleTapRecognized, isFalse);
283

284 285 286 287 288
    tester.async.elapse(new Duration(milliseconds: 1000));
    tester.route(up1);
    expect(doubleTapRecognized, isFalse);
    GestureBinding.instance.gestureArena.sweep(1);
    expect(doubleTapRecognized, isFalse);
289

290 291 292 293 294
    tap.addPointer(down2);
    tester.closeArena(2);
    expect(doubleTapRecognized, isFalse);
    tester.route(down2);
    expect(doubleTapRecognized, isFalse);
295

296 297 298 299
    tester.route(up2);
    expect(doubleTapRecognized, isTrue);
    GestureBinding.instance.gestureArena.sweep(2);
    expect(doubleTapRecognized, isTrue);
300 301 302 303

    tap.dispose();
  });

304
  testGesture('Should not recognize two overlapping taps', (GestureTester tester) {
305
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
306 307 308 309 310 311 312

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    tap.addPointer(down1);
313
    tester.closeArena(1);
314
    expect(doubleTapRecognized, isFalse);
315
    tester.route(down1);
316 317 318
    expect(doubleTapRecognized, isFalse);

    tap.addPointer(down2);
319
    tester.closeArena(2);
320
    expect(doubleTapRecognized, isFalse);
321
    tester.route(down1);
322 323
    expect(doubleTapRecognized, isFalse);

324
    tester.route(up1);
325
    expect(doubleTapRecognized, isFalse);
326
    GestureBinding.instance.gestureArena.sweep(1);
327 328
    expect(doubleTapRecognized, isFalse);

329
    tester.route(up2);
330
    expect(doubleTapRecognized, isFalse);
331
    GestureBinding.instance.gestureArena.sweep(2);
332 333 334 335 336
    expect(doubleTapRecognized, isFalse);

    tap.dispose();
  });

337
  testGesture('Should recognize one tap of group followed by second tap', (GestureTester tester) {
338
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
339 340 341 342 343 344 345

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    tap.addPointer(down1);
346
    tester.closeArena(1);
347
    expect(doubleTapRecognized, isFalse);
348
    tester.route(down1);
349 350 351
    expect(doubleTapRecognized, isFalse);

    tap.addPointer(down2);
352
    tester.closeArena(2);
353
    expect(doubleTapRecognized, isFalse);
354
    tester.route(down1);
355 356
    expect(doubleTapRecognized, isFalse);

357
    tester.route(up1);
358
    expect(doubleTapRecognized, isFalse);
359
    GestureBinding.instance.gestureArena.sweep(1);
360 361
    expect(doubleTapRecognized, isFalse);

362
    tester.route(up2);
363
    expect(doubleTapRecognized, isFalse);
364
    GestureBinding.instance.gestureArena.sweep(2);
365 366 367
    expect(doubleTapRecognized, isFalse);

    tap.addPointer(down1);
368
    tester.closeArena(1);
369
    expect(doubleTapRecognized, isFalse);
370
    tester.route(down1);
371 372
    expect(doubleTapRecognized, isFalse);

373
    tester.route(up1);
374
    expect(doubleTapRecognized, isTrue);
375
    GestureBinding.instance.gestureArena.sweep(1);
376 377 378 379 380 381
    expect(doubleTapRecognized, isTrue);

    tap.dispose();

  });

382
  testGesture('Should cancel on arena reject during first tap', (GestureTester tester) {
383
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
384 385 386 387 388 389 390 391

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    tap.addPointer(down1);
    TestGestureArenaMember member = new TestGestureArenaMember();
392
    GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
393
    tester.closeArena(1);
394
    expect(doubleTapRecognized, isFalse);
395
    tester.route(down1);
396 397
    expect(doubleTapRecognized, isFalse);

398
    tester.route(up1);
399 400
    expect(doubleTapRecognized, isFalse);
    entry.resolve(GestureDisposition.accepted);
401
    expect(member.accepted, isTrue);
402
    expect(doubleTapRecognized, isFalse);
403
    GestureBinding.instance.gestureArena.sweep(1);
404 405 406
    expect(doubleTapRecognized, isFalse);

    tap.addPointer(down2);
407
    tester.closeArena(2);
408
    expect(doubleTapRecognized, isFalse);
409
    tester.route(down2);
410 411
    expect(doubleTapRecognized, isFalse);

412
    tester.route(up2);
413
    expect(doubleTapRecognized, isFalse);
414
    GestureBinding.instance.gestureArena.sweep(2);
415 416 417 418 419
    expect(doubleTapRecognized, isFalse);

    tap.dispose();
  });

420
  testGesture('Should cancel on arena reject between taps', (GestureTester tester) {
421
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
422 423 424 425 426 427 428 429

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    tap.addPointer(down1);
    TestGestureArenaMember member = new TestGestureArenaMember();
430
    GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
431
    tester.closeArena(1);
432
    expect(doubleTapRecognized, isFalse);
433
    tester.route(down1);
434 435
    expect(doubleTapRecognized, isFalse);

436
    tester.route(up1);
437
    expect(doubleTapRecognized, isFalse);
438
    GestureBinding.instance.gestureArena.sweep(1);
439 440 441
    expect(doubleTapRecognized, isFalse);

    entry.resolve(GestureDisposition.accepted);
442
    expect(member.accepted, isTrue);
443 444

    tap.addPointer(down2);
445
    tester.closeArena(2);
446
    expect(doubleTapRecognized, isFalse);
447
    tester.route(down2);
448 449
    expect(doubleTapRecognized, isFalse);

450
    tester.route(up2);
451
    expect(doubleTapRecognized, isFalse);
452
    GestureBinding.instance.gestureArena.sweep(2);
453 454 455 456 457
    expect(doubleTapRecognized, isFalse);

    tap.dispose();
  });

458
  testGesture('Should cancel on arena reject during last tap', (GestureTester tester) {
459
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
460 461 462 463 464 465 466 467

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    tap.addPointer(down1);
    TestGestureArenaMember member = new TestGestureArenaMember();
468
    GestureArenaEntry entry = GestureBinding.instance.gestureArena.add(1, member);
469
    tester.closeArena(1);
470
    expect(doubleTapRecognized, isFalse);
471
    tester.route(down1);
472 473
    expect(doubleTapRecognized, isFalse);

474
    tester.route(up1);
475
    expect(doubleTapRecognized, isFalse);
476
    GestureBinding.instance.gestureArena.sweep(1);
477 478 479
    expect(doubleTapRecognized, isFalse);

    tap.addPointer(down2);
480
    tester.closeArena(2);
481
    expect(doubleTapRecognized, isFalse);
482
    tester.route(down2);
483 484 485
    expect(doubleTapRecognized, isFalse);

    entry.resolve(GestureDisposition.accepted);
486
    expect(member.accepted, isTrue);
487

488
    tester.route(up2);
489
    expect(doubleTapRecognized, isFalse);
490
    GestureBinding.instance.gestureArena.sweep(2);
491 492 493 494 495
    expect(doubleTapRecognized, isFalse);

    tap.dispose();
  });

496
  testGesture('Passive gesture should trigger on double tap cancel', (GestureTester tester) {
497
    DoubleTapGestureRecognizer tap = new DoubleTapGestureRecognizer();
498 499 500 501 502 503 504 505 506

    bool doubleTapRecognized = false;
    tap.onDoubleTap = () {
      doubleTapRecognized = true;
    };

    new FakeAsync().run((FakeAsync async) {
      tap.addPointer(down1);
      TestGestureArenaMember member = new TestGestureArenaMember();
507
      GestureBinding.instance.gestureArena.add(1, member);
508
      tester.closeArena(1);
509
      expect(doubleTapRecognized, isFalse);
510
      tester.route(down1);
511 512
      expect(doubleTapRecognized, isFalse);

513
      tester.route(up1);
514
      expect(doubleTapRecognized, isFalse);
515
      GestureBinding.instance.gestureArena.sweep(1);
516 517 518 519
      expect(doubleTapRecognized, isFalse);

      expect(member.accepted, isFalse);

Ian Hickson's avatar
Ian Hickson committed
520
      async.elapse(const Duration(milliseconds: 5000));
521 522 523 524 525 526 527

      expect(member.accepted, isTrue);
    });

    tap.dispose();
  });

528
}