1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.content.browser;
7 import android.content.Context;
8 import android.os.Bundle;
9 import android.os.SystemClock;
10 import android.test.InstrumentationTestCase;
11 import android.test.suitebuilder.annotation.SmallTest;
12 import android.util.Log;
13 import android.view.InputDevice;
14 import android.view.MotionEvent;
15 import android.view.MotionEvent.PointerCoords;
16 import android.view.MotionEvent.PointerProperties;
17 import android.view.ViewConfiguration;
19 import org.chromium.base.test.util.Feature;
20 import org.chromium.base.test.util.ScalableTimeout;
21 import org.chromium.content.browser.ContentViewGestureHandler.MotionEventDelegate;
23 import java.util.ArrayList;
24 import java.util.concurrent.CountDownLatch;
25 import java.util.concurrent.TimeUnit;
28 * Test suite for ContentViewGestureHandler.
30 public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
31 private static final int FAKE_COORD_X = 42;
32 private static final int FAKE_COORD_Y = 24;
34 private static final String TAG = "ContentViewGestureHandler";
35 private MockMotionEventDelegate mMockMotionEventDelegate;
36 private ContentViewGestureHandler mGestureHandler;
38 static class MockMotionEventDelegate implements MotionEventDelegate {
39 static class GestureEvent {
40 public final int mType;
41 public final long mTimeMs;
44 public final Bundle mExtraParams;
46 public GestureEvent(int type, long timeMs, int x, int y, Bundle extraParams) {
51 mExtraParams = extraParams;
54 public int getType() {
58 public long getTimeMs() {
70 public Bundle getExtraParams() {
74 GestureEvent mMostRecentGestureEvent;
75 GestureEvent mActiveScrollStartEvent;
76 int mMostRecentMotionEventAction = -1;
77 final ArrayList<Integer> mGestureTypeList = new ArrayList<Integer>();
78 final ArrayList<Long> mGestureTimeList = new ArrayList<Long>();
80 final CountDownLatch mLongPressCalled = new CountDownLatch(1);
81 final CountDownLatch mShowPressCalled = new CountDownLatch(1);
84 public void onTouchEventHandlingBegin(MotionEvent event) {
85 mMostRecentMotionEventAction = event.getActionMasked();
89 public void onTouchEventHandlingEnd() {
93 public boolean onGestureEventCreated(
94 int type, long timeMs, int x, int y, Bundle extraParams) {
95 Log.i(TAG, "Gesture event received with type id " + type);
96 mMostRecentGestureEvent = new GestureEvent(type, timeMs, x, y, extraParams);
97 mGestureTypeList.add(mMostRecentGestureEvent.mType);
98 mGestureTimeList.add(timeMs);
99 if (type == GestureEventType.SCROLL_START) {
100 mActiveScrollStartEvent = mMostRecentGestureEvent;
101 } else if (type == GestureEventType.SCROLL_END
102 || type == GestureEventType.FLING_CANCEL) {
103 mActiveScrollStartEvent = null;
104 } else if (type == GestureEventType.LONG_PRESS) {
105 mLongPressCalled.countDown();
106 } else if (type == GestureEventType.SHOW_PRESS) {
107 mShowPressCalled.countDown();
114 private static MotionEvent motionEvent(int action, long downTime, long eventTime) {
115 return MotionEvent.obtain(downTime, eventTime, action, FAKE_COORD_X, FAKE_COORD_Y, 0);
119 public void setUp() {
120 mMockMotionEventDelegate = new MockMotionEventDelegate();
121 mGestureHandler = new ContentViewGestureHandler(
122 getInstrumentation().getTargetContext(), mMockMotionEventDelegate);
123 mGestureHandler.updateMultiTouchSupport(false);
127 * Verify that a DOWN followed shortly by an UP will trigger a single tap.
132 @Feature({"Gestures"})
133 public void testGestureSingleClick() throws Exception {
134 final long downTime = SystemClock.uptimeMillis();
135 final long eventTime = SystemClock.uptimeMillis();
137 mGestureHandler.updateDoubleTapSupport(false);
139 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
140 assertTrue(mGestureHandler.onTouchEvent(event));
141 assertEquals(GestureEventType.TAP_DOWN,
142 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
144 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
145 assertTrue(mGestureHandler.onTouchEvent(event));
146 assertEquals(GestureEventType.SINGLE_TAP_CONFIRMED,
147 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
151 * Verify that a DOWN followed by a MOVE will trigger fling (but not LONG).
155 @Feature({"Gestures"})
156 public void testGestureFlingAndCancelLongClick() throws Exception {
157 final long downTime = SystemClock.uptimeMillis();
158 final long eventTime = SystemClock.uptimeMillis();
160 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
162 assertTrue(mGestureHandler.onTouchEvent(event));
163 assertEquals(GestureEventType.TAP_DOWN,
164 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
166 event = MotionEvent.obtain(
167 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
168 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
169 assertTrue(mGestureHandler.onTouchEvent(event));
171 event = MotionEvent.obtain(
172 downTime, eventTime + 10, MotionEvent.ACTION_UP,
173 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
174 assertTrue(mGestureHandler.onTouchEvent(event));
175 assertEquals(GestureEventType.FLING_START,
176 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
177 assertFalse(mMockMotionEventDelegate.mGestureTypeList.contains(
178 GestureEventType.LONG_PRESS));
182 * Verify that for a normal scroll the following events are sent:
183 * - GESTURE_SCROLL_START
184 * - GESTURE_SCROLL_BY
185 * - GESTURE_SCROLL_END
189 @Feature({"Gestures"})
190 public void testScrollEventActionUpSequence() throws Exception {
191 checkScrollEventSequenceForEndActionType(MotionEvent.ACTION_UP);
195 * Verify that for a cancelled scroll the following events are sent:
196 * - GESTURE_SCROLL_START
197 * - GESTURE_SCROLL_BY
198 * - GESTURE_SCROLL_END
202 @Feature({"Gestures"})
203 public void testScrollEventActionCancelSequence() throws Exception {
204 checkScrollEventSequenceForEndActionType(MotionEvent.ACTION_CANCEL);
207 private void checkScrollEventSequenceForEndActionType(int endActionType) throws Exception {
208 final long downTime = SystemClock.uptimeMillis();
209 final long eventTime = SystemClock.uptimeMillis();
210 final int scrollToX = FAKE_COORD_X + 100;
211 final int scrollToY = FAKE_COORD_Y + 100;
213 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
215 assertTrue(mGestureHandler.onTouchEvent(event));
217 event = MotionEvent.obtain(
218 downTime, eventTime + 1000, MotionEvent.ACTION_MOVE, scrollToX, scrollToY, 0);
219 assertTrue(mGestureHandler.onTouchEvent(event));
220 assertTrue(mGestureHandler.isNativeScrolling());
221 assertTrue("A scrollStart event should have been sent",
222 mMockMotionEventDelegate.mGestureTypeList.contains(
223 GestureEventType.SCROLL_START));
224 assertEquals("We should have started scrolling",
225 GestureEventType.SCROLL_BY,
226 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
227 assertEquals("Only tapDown, tapCancel, scrollBegin and scrollBy should have been sent",
228 4, mMockMotionEventDelegate.mGestureTypeList.size());
229 assertEquals("scrollBegin should be sent before scrollBy",
230 GestureEventType.SCROLL_START,
231 (int) mMockMotionEventDelegate.mGestureTypeList.get(2));
232 assertEquals("scrollBegin should have the time of the ACTION_MOVE",
233 eventTime + 1000, (long) mMockMotionEventDelegate.mGestureTimeList.get(2));
235 event = MotionEvent.obtain(
236 downTime, eventTime + 1000, endActionType, scrollToX, scrollToY, 0);
237 mGestureHandler.onTouchEvent(event);
238 assertFalse(mGestureHandler.isNativeScrolling());
239 assertTrue("A scrollEnd event should have been sent",
240 mMockMotionEventDelegate.mGestureTypeList.contains(
241 GestureEventType.SCROLL_END));
242 assertEquals("We should have stopped scrolling",
243 GestureEventType.SCROLL_END,
244 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
245 assertEquals("Only tapDown, scrollBegin and scrollBy and scrollEnd should have been sent",
246 5, mMockMotionEventDelegate.mGestureTypeList.size());
250 * Verify that for a normal fling (fling after scroll) the following events are sent:
251 * - GESTURE_SCROLL_BEGIN
252 * - GESTURE_FLING_START
253 * and GESTURE_FLING_CANCEL is sent on the next touch.
257 @Feature({"Gestures"})
258 public void testFlingEventSequence() throws Exception {
259 final long downTime = SystemClock.uptimeMillis();
260 final long eventTime = SystemClock.uptimeMillis();
262 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
264 assertTrue(mGestureHandler.onTouchEvent(event));
266 event = MotionEvent.obtain(
267 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
268 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
269 assertTrue(mGestureHandler.onTouchEvent(event));
270 assertTrue(mGestureHandler.isNativeScrolling());
271 assertTrue("A scrollStart event should have been sent",
272 mMockMotionEventDelegate.mGestureTypeList.contains(
273 GestureEventType.SCROLL_START));
274 assertEquals("We should have started scrolling",
275 GestureEventType.SCROLL_BY,
276 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
277 assertEquals("Only tapDown, tapCancel, scrollBegin and scrollBy should have been sent",
278 4, mMockMotionEventDelegate.mGestureTypeList.size());
279 assertEquals("scrollBegin should be sent before scrollBy",
280 GestureEventType.SCROLL_START,
281 (int) mMockMotionEventDelegate.mGestureTypeList.get(2));
282 MockMotionEventDelegate.GestureEvent startEvent =
283 mMockMotionEventDelegate.mActiveScrollStartEvent;
284 assertNotNull(startEvent);
285 assertEquals("scrollBegin should have the time of the ACTION_MOVE",
286 eventTime + 10, (long) startEvent.getTimeMs());
287 int hintX = startEvent.getExtraParams().getInt(ContentViewGestureHandler.DELTA_HINT_X);
288 int hintY = startEvent.getExtraParams().getInt(ContentViewGestureHandler.DELTA_HINT_Y);
289 // We don't want to take a dependency here on exactly how hints are calculated for a
290 // fling (eg. may depend on velocity), so just validate the direction.
291 assertTrue("scrollBegin hint should be in positive X axis",
292 hintX > 0 && hintY > 0 && hintX > hintY);
294 event = MotionEvent.obtain(
295 downTime, eventTime + 15, MotionEvent.ACTION_UP,
296 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
297 assertTrue(mGestureHandler.onTouchEvent(event));
298 assertFalse(mGestureHandler.isNativeScrolling());
299 assertEquals("We should have started flinging",
300 GestureEventType.FLING_START,
301 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
302 assertTrue("A scroll end event should not have been sent",
303 !mMockMotionEventDelegate.mGestureTypeList.contains(
304 GestureEventType.SCROLL_END));
305 assertEquals("The last up should have caused flingStart to be sent",
306 5, mMockMotionEventDelegate.mGestureTypeList.size());
307 assertEquals("flingStart should have the time of the ACTION_UP",
308 eventTime + 15, (long) mMockMotionEventDelegate.mGestureTimeList.get(4));
312 * Verify that a zero-velocity fling is never forwarded, and cancels any
313 * previous fling or scroll sequence.
317 @Feature({"Gestures"})
318 public void testZeroVelocityFling() throws Exception {
319 final long downTime = SystemClock.uptimeMillis();
320 final long eventTime = SystemClock.uptimeMillis();
322 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
323 assertTrue(mGestureHandler.onTouchEvent(event));
325 mGestureHandler.fling(eventTime, 5, 5, 0, 0);
326 assertEquals("A zero-velocity fling should not be forwarded",
327 GestureEventType.TAP_DOWN,
328 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
330 mGestureHandler.fling(eventTime, 5, 5, 5, 0);
331 assertEquals("Subsequent flings should work properly",
332 GestureEventType.FLING_START,
333 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
335 event = MotionEvent.obtain(
336 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
337 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
338 assertTrue(mGestureHandler.onTouchEvent(event));
339 assertTrue(mGestureHandler.isNativeScrolling());
340 assertTrue("A scrollStart event should have been sent",
341 mMockMotionEventDelegate.mGestureTypeList.contains(
342 GestureEventType.SCROLL_START));
343 assertEquals("We should have started scrolling",
344 GestureEventType.SCROLL_BY,
345 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
347 mGestureHandler.fling(eventTime, 5, 5, 0, 0);
348 assertEquals("A zero-velicty fling should end the current scroll sequence",
349 GestureEventType.SCROLL_END,
350 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
354 * Verify that a show pressed state gesture followed by a long press followed by the focus
355 * loss in the window due to context menu cancels show pressed.
359 @Feature({"Gestures"})
360 public void testShowPressCancelOnWindowFocusLost() throws Exception {
361 final long time = SystemClock.uptimeMillis();
363 getInstrumentation().runOnMainSync(new Runnable() {
367 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, time, time);
368 mGestureHandler.onTouchEvent(event);
372 assertTrue(mMockMotionEventDelegate.mShowPressCalled.await(
373 ScalableTimeout.scaleTimeout(ViewConfiguration.getTapTimeout() + 10),
374 TimeUnit.MILLISECONDS));
376 assertTrue(mMockMotionEventDelegate.mLongPressCalled.await(
377 ScalableTimeout.scaleTimeout(ViewConfiguration.getLongPressTimeout()
378 + ViewConfiguration.getTapTimeout() + 10),
379 TimeUnit.MILLISECONDS));
381 assertEquals("Should have sent SHOW_PRESS and LONG_PRESS events",
382 3, mMockMotionEventDelegate.mGestureTypeList.size());
383 assertEquals("Should have a show press event",
384 GestureEventType.SHOW_PRESS,
385 mMockMotionEventDelegate.mGestureTypeList.get(1).intValue());
386 assertEquals("Should have a long press event",
387 GestureEventType.LONG_PRESS,
388 mMockMotionEventDelegate.mGestureTypeList.get(2).intValue());
390 // The long press triggers window focus loss by opening a context menu
391 mGestureHandler.onWindowFocusLost();
393 assertEquals("Only should have sent only GESTURE_TAP_CANCEL event",
394 4, mMockMotionEventDelegate.mGestureTypeList.size());
395 assertEquals("Should have a gesture show press cancel event next",
396 GestureEventType.TAP_CANCEL,
397 mMockMotionEventDelegate.mGestureTypeList.get(3).intValue());
401 * Verify that a recent show pressed state gesture is canceled when scrolling begins.
405 @Feature({"Gestures"})
406 public void testShowPressCancelWhenScrollBegins() throws Exception {
407 final long downTime = SystemClock.uptimeMillis();
408 final long eventTime = SystemClock.uptimeMillis();
410 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
412 assertTrue(mGestureHandler.onTouchEvent(event));
414 mGestureHandler.sendShowPressedStateGestureForTesting();
416 assertEquals("A show pressed state event should have been sent",
417 GestureEventType.SHOW_PRESS,
418 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
419 assertEquals("Only tapDown and showPressedState should have been sent",
420 2, mMockMotionEventDelegate.mGestureTypeList.size());
422 event = MotionEvent.obtain(
423 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
424 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
425 assertTrue(mGestureHandler.onTouchEvent(event));
427 assertEquals("We should have started scrolling",
428 GestureEventType.SCROLL_BY,
429 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
430 assertTrue("A show press cancel event should have been sent",
431 mMockMotionEventDelegate.mGestureTypeList.contains(
432 GestureEventType.TAP_CANCEL));
433 assertEquals("Only tapDown, showPressedState, showPressCancel, scrollBegin and scrollBy" +
434 " should have been sent",
435 5, mMockMotionEventDelegate.mGestureTypeList.size());
437 event = MotionEvent.obtain(
438 downTime, eventTime + 15, MotionEvent.ACTION_UP,
439 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
440 assertTrue(mGestureHandler.onTouchEvent(event));
441 assertEquals("We should have started flinging",
442 GestureEventType.FLING_START,
443 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
444 assertTrue("A scroll end event should not have been sent",
445 !mMockMotionEventDelegate.mGestureTypeList.contains(
446 GestureEventType.SCROLL_END));
447 assertEquals("The last up should have caused flingStart to be sent",
448 6, mMockMotionEventDelegate.mGestureTypeList.size());
452 * Verify that double tap is correctly handled including the recent show pressed state gesture
457 @Feature({"Gestures"})
458 public void testDoubleTap() throws Exception {
459 final long downTime = SystemClock.uptimeMillis();
460 final long eventTime = SystemClock.uptimeMillis();
462 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
463 assertTrue(mGestureHandler.onTouchEvent(event));
465 mGestureHandler.sendShowPressedStateGestureForTesting();
466 assertEquals("GESTURE_SHOW_PRESS should have been sent",
467 GestureEventType.SHOW_PRESS,
468 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
469 assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SHOW_PRESS should have been sent",
470 2, mMockMotionEventDelegate.mGestureTypeList.size());
472 event = MotionEvent.obtain(
473 downTime, eventTime + 5, MotionEvent.ACTION_UP,
474 FAKE_COORD_X, FAKE_COORD_Y, 0);
475 mGestureHandler.onTouchEvent(event);
476 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
477 GestureEventType.SINGLE_TAP_UNCONFIRMED,
478 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
479 assertEquals("Only GESTURE_TAP_DOWN, " +
480 "GESTURE_SHOW_PRESS and " +
481 "GESTURE_SINGLE_TAP_UNCONFIRMED should have been sent",
482 3, mMockMotionEventDelegate.mGestureTypeList.size());
484 event = MotionEvent.obtain(
485 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
486 FAKE_COORD_X, FAKE_COORD_Y, 0);
487 assertTrue(mGestureHandler.onTouchEvent(event));
488 assertEquals("A GESTURE_TAP_DOWN event should have been sent ",
489 GestureEventType.TAP_DOWN,
490 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
491 assertEquals("Only GESTURE_TAP_DOWN, " +
492 "GESTURE_SHOW_PRESS, " +
493 "GESTURE_SINGLE_TAP_UNCONFIRMED," +
494 "GESTURE_TAP_CANCEL and" +
495 "GESTURE_TAP_DOWN should have been sent",
496 5, mMockMotionEventDelegate.mGestureTypeList.size());
498 // Moving a very small amount of distance should not trigger the double tap drag zoom mode.
499 event = MotionEvent.obtain(
500 eventTime + 10, eventTime + 10, MotionEvent.ACTION_MOVE,
501 FAKE_COORD_X, FAKE_COORD_Y + 1, 0);
502 assertTrue(mGestureHandler.onTouchEvent(event));
503 assertEquals("Only GESTURE_TAP_DOWN, " +
504 "GESTURE_SHOW_PRESS, " +
505 "GESTURE_SINGLE_TAP_UNCONFIRMED and" +
506 "GESTURE_TAP_CANCEL and " +
507 "GESTURE_TAP_DOWN should have been sent",
508 5, mMockMotionEventDelegate.mGestureTypeList.size());
510 event = MotionEvent.obtain(
511 eventTime + 10, eventTime + 15, MotionEvent.ACTION_UP,
512 FAKE_COORD_X, FAKE_COORD_Y + 1, 0);
513 assertTrue(mGestureHandler.onTouchEvent(event));
514 assertEquals("A double tap should have occurred",
515 GestureEventType.DOUBLE_TAP,
516 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
517 assertEquals("Only GESTURE_TAP_DOWN, " +
518 "GESTURE_SHOW_PRESS, " +
519 "GESTURE_SINGLE_TAP_UNCONFIRMED, " +
520 "GESTURE_TAP_CANCEL, " +
521 "GESTURE_TAP_DOWN, " +
522 "GESTURE_DOUBLE_TAP should have been sent",
523 6, mMockMotionEventDelegate.mGestureTypeList.size());
527 * Verify that double tap drag zoom feature is correctly executed.
531 @Feature({"Gestures"})
532 public void testDoubleTapDragZoom() throws Exception {
533 final long downTime1 = SystemClock.uptimeMillis();
534 final long downTime2 = downTime1 + 100;
536 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
537 assertTrue(mGestureHandler.onTouchEvent(event));
539 mGestureHandler.sendShowPressedStateGestureForTesting();
540 assertEquals("GESTURE_SHOW_PRESS should have been sent",
541 GestureEventType.SHOW_PRESS,
542 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
543 assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SHOW_PRESS should have been sent",
544 2, mMockMotionEventDelegate.mGestureTypeList.size());
547 event = MotionEvent.obtain(
548 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
549 FAKE_COORD_X, FAKE_COORD_Y, 0);
550 mGestureHandler.onTouchEvent(event);
551 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
552 GestureEventType.SINGLE_TAP_UNCONFIRMED,
553 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
554 assertEquals("Only GESTURE_TAP_DOWN, " +
555 "GESTURE_SHOW_PRESS and " +
556 "GESTURE_TAP_UNCONFIRMED " +
557 "should have been sent",
558 3, mMockMotionEventDelegate.mGestureTypeList.size());
560 event = MotionEvent.obtain(
561 downTime2, downTime2, MotionEvent.ACTION_DOWN,
562 FAKE_COORD_X, FAKE_COORD_Y, 0);
563 assertTrue(mGestureHandler.onTouchEvent(event));
564 assertEquals("GESTURE_TAP_DOWN should have been sent",
565 GestureEventType.TAP_DOWN,
566 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
567 assertEquals("Only GESTURE_TAP_DOWN, " +
568 "GESTURE_SHOW_PRESS, " +
569 "GESTURE_TAP_UNCONFIRMED," +
570 "GESTURE_TAP_CANCEL and" +
571 "GESTURE_TAP_DOWN should have been sent",
572 5, mMockMotionEventDelegate.mGestureTypeList.size());
574 event = MotionEvent.obtain(
575 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
576 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
577 assertTrue(mGestureHandler.onTouchEvent(event));
578 assertTrue("GESTURE_SCROLL_START should have been sent",
579 mMockMotionEventDelegate.mGestureTypeList.contains(
580 GestureEventType.SCROLL_START));
581 MockMotionEventDelegate.GestureEvent startEvent =
582 mMockMotionEventDelegate.mActiveScrollStartEvent;
583 assertEquals(FAKE_COORD_X, startEvent.getX());
584 assertEquals(FAKE_COORD_Y + 100, startEvent.getY());
585 Bundle extraParams = startEvent.getExtraParams();
586 assertNotNull(extraParams);
587 assertEquals("GESTURE_SCROLL_START should have an X hint equal to the distance traveled",
588 0, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_X));
589 assertEquals("GESTURE_SCROLL_START should have an X hint equal to the distance traveled",
590 100, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_Y));
592 assertEquals("GESTURE_PINCH_BEGIN should have been sent",
593 GestureEventType.PINCH_BEGIN,
594 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
595 assertEquals("Only GESTURE_TAP_DOWN, " +
596 "GESTURE_SHOW_PRESS, " +
597 "GESTURE_TAP_UNCONFIRMED," +
598 "GESTURE_TAP_CANCEL, " +
599 "GESTURE_TAP_DOWN, " +
600 "GESTURE_TAP_CANCEL, " +
601 "GESTURE_SCROLL_START, and " +
602 "GESTURE_PINCH_BEGIN should have been sent",
603 8, mMockMotionEventDelegate.mGestureTypeList.size());
605 event = MotionEvent.obtain(
606 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
607 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
608 assertTrue(mGestureHandler.onTouchEvent(event));
609 assertTrue("GESTURE_SCROLL_BY should have been sent",
610 mMockMotionEventDelegate.mGestureTypeList.contains(
611 GestureEventType.SCROLL_BY));
612 assertEquals("GESTURE_PINCH_BY should have been sent",
613 GestureEventType.PINCH_BY,
614 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
615 assertEquals("Only GESTURE_TAP_DOWN, " +
616 "GESTURE_SHOW_PRESS, " +
617 "GESTURE_TAP_UNCONFIRMED," +
618 "GESTURE_TAP_CANCEL, " +
619 "GESTURE_TAP_DOWN, " +
620 "GESTURE_TAP_CANCEL, " +
621 "GESTURE_SCROLL_START," +
622 "GESTURE_PINCH_BEGIN, " +
623 "GESTURE_SCROLL_BY, and " +
624 "GESTURE_PINCH_BY should have been sent",
625 10, mMockMotionEventDelegate.mGestureTypeList.size());
627 event = MotionEvent.obtain(
628 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
629 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
630 assertTrue(mGestureHandler.onTouchEvent(event));
631 assertTrue("GESTURE_PINCH_END should have been sent",
632 mMockMotionEventDelegate.mGestureTypeList.contains(
633 GestureEventType.PINCH_END));
634 assertEquals("GESTURE_SCROLL_END should have been sent",
635 GestureEventType.SCROLL_END,
636 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
637 assertEquals("Only GESTURE_TAP_DOWN, " +
638 "GESTURE_SHOW_PRESS, " +
639 "GESTURE_TAP_UNCONFIRMED," +
640 "GESTURE_TAP_CANCEL, " +
641 "GESTURE_TAP_DOWN, " +
642 "GESTURE_TAP_CANCEL, " +
643 "GESTURE_SCROLL_START," +
644 "GESTURE_PINCH_BEGIN, " +
645 "GESTURE_SCROLL_BY," +
646 "GESTURE_PINCH_BY, " +
647 "GESTURE_PINCH_END, and " +
648 "GESTURE_SCROLL_END should have been sent",
649 12, mMockMotionEventDelegate.mGestureTypeList.size());
654 * Verify that double tap drag zoom is cancelled if the user presses a
659 @Feature({"Gestures"})
660 public void testDoubleTapDragZoomCancelledOnSecondaryPointerDown() throws Exception {
661 final long downTime1 = SystemClock.uptimeMillis();
662 final long downTime2 = downTime1 + 100;
664 PointerProperties pp0 = new PointerProperties();
666 pp0.toolType = MotionEvent.TOOL_TYPE_FINGER;
667 PointerProperties pp1 = new PointerProperties();
669 pp1.toolType = MotionEvent.TOOL_TYPE_FINGER;
671 PointerCoords pc0 = new PointerCoords();
672 pc0.x = FAKE_COORD_X;
673 pc0.y = FAKE_COORD_Y;
676 PointerCoords pc1 = new PointerCoords();
677 pc1.x = FAKE_COORD_X + 50;
678 pc1.y = FAKE_COORD_Y + 50;
682 MotionEvent event = MotionEvent.obtain(
683 downTime1, downTime1, MotionEvent.ACTION_DOWN,
684 1, new PointerProperties[] { pp0 }, new PointerCoords[] { pc0 },
685 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
686 assertTrue(mGestureHandler.onTouchEvent(event));
688 mGestureHandler.sendShowPressedStateGestureForTesting();
689 assertEquals("GESTURE_SHOW_PRESS should have been sent",
690 GestureEventType.SHOW_PRESS,
691 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
692 assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SHOW_PRESS should have been sent",
693 2, mMockMotionEventDelegate.mGestureTypeList.size());
695 event = MotionEvent.obtain(
696 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
697 1, new PointerProperties[] { pp0 }, new PointerCoords[] { pc0 },
698 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
699 mGestureHandler.onTouchEvent(event);
700 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
701 GestureEventType.SINGLE_TAP_UNCONFIRMED,
702 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
703 assertEquals("Only GESTURE_TAP_DOWN, " +
704 "GESTURE_SHOW_PRESS and " +
705 "GESTURE_TAP_UNCONFIRMED " +
706 "should have been sent",
707 3, mMockMotionEventDelegate.mGestureTypeList.size());
709 event = MotionEvent.obtain(
710 downTime2, downTime2, MotionEvent.ACTION_DOWN,
711 1, new PointerProperties[] { pp0 }, new PointerCoords[] { pc0 },
712 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
713 assertTrue(mGestureHandler.onTouchEvent(event));
714 assertEquals("GESTURE_TAP_DOWN should have been sent",
715 GestureEventType.TAP_DOWN,
716 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
717 assertEquals("Only GESTURE_TAP_DOWN, " +
718 "GESTURE_SHOW_PRESS, " +
719 "GESTURE_TAP_UNCONFIRMED," +
720 "GESTURE_TAP_CANCEL and" +
721 "GESTURE_TAP_DOWN should have been sent",
722 5, mMockMotionEventDelegate.mGestureTypeList.size());
726 event = MotionEvent.obtain(
727 downTime2, downTime2 + 50, MotionEvent.ACTION_MOVE,
728 1, new PointerProperties[] { pp0 }, new PointerCoords[] { pc0 },
729 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
730 assertTrue(mGestureHandler.onTouchEvent(event));
731 assertTrue("GESTURE_SCROLL_START should have been sent",
732 mMockMotionEventDelegate.mGestureTypeList.contains(
733 GestureEventType.SCROLL_START));
735 assertEquals("GESTURE_PINCH_BEGIN should have been sent",
736 GestureEventType.PINCH_BEGIN,
737 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
738 assertEquals("Only GESTURE_TAP_DOWN, " +
739 "GESTURE_SHOW_PRESS, " +
740 "GESTURE_TAP_UNCONFIRMED," +
741 "GESTURE_TAP_CANCEL, " +
742 "GESTURE_TAP_DOWN, " +
743 "GESTURE_TAP_CANCEL, " +
744 "GESTURE_SCROLL_START, and " +
745 "GESTURE_PINCH_BEGIN should have been sent",
746 8, mMockMotionEventDelegate.mGestureTypeList.size());
748 event = MotionEvent.obtain(
749 downTime2, downTime2 + 100, MotionEvent.ACTION_POINTER_DOWN,
750 2, new PointerProperties[] { pp1, pp0 }, new PointerCoords[] { pc1, pc0 },
751 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
752 mGestureHandler.onTouchEvent(event);
753 assertTrue("GESTURE_PINCH_END should have been sent",
754 mMockMotionEventDelegate.mGestureTypeList.contains(
755 GestureEventType.PINCH_END));
756 assertEquals("GESTURE_SCROLL_END should have been sent",
757 GestureEventType.SCROLL_END,
758 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
759 assertEquals("Only GESTURE_TAP_DOWN, " +
760 "GESTURE_SHOW_PRESS, " +
761 "GESTURE_TAP_UNCONFIRMED," +
762 "GESTURE_TAP_CANCEL, " +
763 "GESTURE_TAP_DOWN, " +
764 "GESTURE_TAP_CANCEL, " +
765 "GESTURE_SCROLL_START," +
766 "GESTURE_PINCH_BEGIN, " +
767 "GESTURE_PINCH_END, and " +
768 "GESTURE_SCROLL_END should have been sent",
769 10, mMockMotionEventDelegate.mGestureTypeList.size());
771 event = MotionEvent.obtain(
772 downTime2, downTime2 + 150, MotionEvent.ACTION_POINTER_UP,
773 2, new PointerProperties[] { pp1, pp0 }, new PointerCoords[] { pc1, pc0 },
774 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
775 mGestureHandler.onTouchEvent(event);
776 assertEquals("No new gestures should have been sent",
777 10, mMockMotionEventDelegate.mGestureTypeList.size());
781 * Verify that double tap drag zoom feature is not invoked
782 * when it is disabled..
786 @Feature({"Gestures"})
787 public void testDoubleTapDragZoomNothingWhenDisabled() throws Exception {
788 final long downTime1 = SystemClock.uptimeMillis();
789 final long downTime2 = downTime1 + 100;
791 mGestureHandler.updateDoubleTapSupport(false);
793 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
794 assertTrue(mGestureHandler.onTouchEvent(event));
796 event = MotionEvent.obtain(
797 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
798 FAKE_COORD_X, FAKE_COORD_Y, 0);
799 mGestureHandler.onTouchEvent(event);
801 event = MotionEvent.obtain(
802 downTime2, downTime2, MotionEvent.ACTION_DOWN,
803 FAKE_COORD_X, FAKE_COORD_Y, 0);
804 assertTrue(mGestureHandler.onTouchEvent(event));
806 event = MotionEvent.obtain(
807 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
808 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
810 // The move should become a scroll, as double tap and drag to zoom is
812 assertTrue(mGestureHandler.onTouchEvent(event));
813 assertTrue("GESTURE_SCROLL_START should have been sent",
814 mMockMotionEventDelegate.mGestureTypeList.contains(
815 GestureEventType.SCROLL_START));
816 assertFalse("No GESTURE_PINCH_BEGIN should have been sent",
817 mMockMotionEventDelegate.mGestureTypeList.contains(
818 GestureEventType.PINCH_BEGIN));
820 event = MotionEvent.obtain(
821 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
822 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
823 assertTrue(mGestureHandler.onTouchEvent(event));
824 assertEquals("GESTURE_SCROLL_BY should have been sent",
825 GestureEventType.SCROLL_BY,
826 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
827 assertEquals("GESTURE_SCROLL_BY should have been sent",
828 event.getEventTime(),
829 mMockMotionEventDelegate.mMostRecentGestureEvent.getTimeMs());
830 assertTrue("No GESTURE_PINCH_BY should have been sent",
831 GestureEventType.PINCH_BY !=
832 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
834 event = MotionEvent.obtain(
835 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
836 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
837 assertTrue(mGestureHandler.onTouchEvent(event));
838 assertFalse("No GESTURE_PINCH_END should have been sent",
839 mMockMotionEventDelegate.mGestureTypeList.contains(
840 GestureEventType.PINCH_END));
844 * Generate a scroll gesture and verify that the resulting scroll motion event has both absolute
845 * and relative position information.
848 @Feature({"Gestures"})
849 public void testScrollUpdateCoordinates() {
850 final int deltaX = 16;
851 final int deltaY = 84;
852 final long downTime = SystemClock.uptimeMillis();
854 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
855 assertTrue(mGestureHandler.onTouchEvent(event));
857 // Move twice so that we get two GESTURE_SCROLL_BY events and can compare
858 // the relative and absolute coordinates.
859 event = MotionEvent.obtain(
860 downTime, downTime + 5, MotionEvent.ACTION_MOVE,
861 FAKE_COORD_X - deltaX / 2, FAKE_COORD_Y - deltaY / 2, 0);
862 assertTrue(mGestureHandler.onTouchEvent(event));
864 event = MotionEvent.obtain(
865 downTime, downTime + 10, MotionEvent.ACTION_MOVE,
866 FAKE_COORD_X - deltaX, FAKE_COORD_Y - deltaY, 0);
867 assertTrue(mGestureHandler.onTouchEvent(event));
869 // Make sure the reported gesture event has all the expected data.
870 MockMotionEventDelegate.GestureEvent gestureEvent =
871 mMockMotionEventDelegate.mMostRecentGestureEvent;
872 assertNotNull(gestureEvent);
873 assertEquals(GestureEventType.SCROLL_BY, gestureEvent.getType());
874 assertEquals(downTime + 10, gestureEvent.getTimeMs());
875 assertEquals(FAKE_COORD_X - deltaX, gestureEvent.getX());
876 assertEquals(FAKE_COORD_Y - deltaY, gestureEvent.getY());
878 Bundle extraParams = gestureEvent.getExtraParams();
879 assertNotNull(extraParams);
880 // No horizontal delta because of snapping.
881 assertEquals(0, extraParams.getInt(ContentViewGestureHandler.DISTANCE_X));
882 assertEquals(deltaY / 2, extraParams.getInt(ContentViewGestureHandler.DISTANCE_Y));
886 * Generate a scroll gesture and verify that the resulting scroll start event
887 * has the expected hint values.
890 @Feature({"Gestures"})
891 public void testScrollStartValues() {
892 final int deltaX = 13;
893 final int deltaY = 89;
894 final long downTime = SystemClock.uptimeMillis();
896 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
897 assertTrue(mGestureHandler.onTouchEvent(event));
899 // Move twice such that the first event isn't sufficient to start
900 // scrolling on it's own.
901 event = MotionEvent.obtain(
902 downTime, downTime + 5, MotionEvent.ACTION_MOVE,
903 FAKE_COORD_X + 2, FAKE_COORD_Y + 1, 0);
904 assertTrue(mGestureHandler.onTouchEvent(event));
905 assertNull("Expect scrolling hasn't yet started",
906 mMockMotionEventDelegate.mActiveScrollStartEvent);
908 event = MotionEvent.obtain(
909 downTime, downTime + 10, MotionEvent.ACTION_MOVE,
910 FAKE_COORD_X + deltaX, FAKE_COORD_Y + deltaY, 0);
911 assertTrue(mGestureHandler.onTouchEvent(event));
913 MockMotionEventDelegate.GestureEvent startEvent =
914 mMockMotionEventDelegate.mActiveScrollStartEvent;
915 assertNotNull(startEvent);
916 assertEquals(GestureEventType.SCROLL_START, startEvent.getType());
917 assertEquals(downTime + 10, startEvent.getTimeMs());
918 assertEquals(FAKE_COORD_X, startEvent.getX());
919 assertEquals(FAKE_COORD_Y, startEvent.getY());
921 Bundle extraParams = startEvent.getExtraParams();
922 assertNotNull(extraParams);
923 assertEquals(deltaX, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_X));
924 assertEquals(deltaY, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_Y));
928 * Verify that the timer of LONG_PRESS will be cancelled when scrolling begins so
929 * LONG_PRESS and LONG_TAP won't be triggered.
934 @Feature({"Gestures"})
935 public void testLongPressAndTapCancelWhenScrollBegins() throws Exception {
936 final long downTime = SystemClock.uptimeMillis();
937 final long eventTime = SystemClock.uptimeMillis();
939 getInstrumentation().runOnMainSync(new Runnable() {
944 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
945 assertTrue(mGestureHandler.onTouchEvent(event));
946 event = MotionEvent.obtain(
947 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
948 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
949 assertTrue(mGestureHandler.onTouchEvent(event));
950 event = MotionEvent.obtain(
951 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
952 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
953 assertTrue(mGestureHandler.onTouchEvent(event));
957 assertFalse(mMockMotionEventDelegate.mLongPressCalled.await(
958 ScalableTimeout.scaleTimeout(ViewConfiguration.getLongPressTimeout()
959 + ViewConfiguration.getTapTimeout() + 10),
960 TimeUnit.MILLISECONDS));
962 // No LONG_TAP because LONG_PRESS timer is cancelled.
963 assertFalse("No LONG_PRESS should be sent",
964 mMockMotionEventDelegate.mGestureTypeList.contains(
965 GestureEventType.LONG_PRESS));
966 assertFalse("No LONG_TAP should be sent",
967 mMockMotionEventDelegate.mGestureTypeList.contains(
968 GestureEventType.LONG_TAP));
972 * Verify that LONG_TAP is triggered after LongPress followed by an UP.
977 @Feature({"Gestures"})
978 public void testGestureLongTap() throws Exception {
979 final long downTime = SystemClock.uptimeMillis();
980 final long eventTime = SystemClock.uptimeMillis();
982 getInstrumentation().runOnMainSync(new Runnable() {
986 mGestureHandler = new ContentViewGestureHandler(
987 getInstrumentation().getTargetContext(), mMockMotionEventDelegate);
988 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
989 assertTrue(mGestureHandler.onTouchEvent(event));
993 assertTrue(mMockMotionEventDelegate.mLongPressCalled.await(
994 ScalableTimeout.scaleTimeout(ViewConfiguration.getLongPressTimeout()
995 + ViewConfiguration.getTapTimeout() + 10),
996 TimeUnit.MILLISECONDS));
998 assertEquals("A LONG_PRESS gesture should have been sent",
999 GestureEventType.LONG_PRESS,
1000 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1002 MotionEvent event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 1000);
1003 mGestureHandler.onTouchEvent(event);
1004 assertEquals("A LONG_TAP gesture should have been sent",
1005 GestureEventType.LONG_TAP,
1006 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1010 * Verify that a LONG_PRESS gesture does not prevent further scrolling.
1015 @Feature({"Gestures"})
1016 public void testGestureLongPressDoesNotPreventScrolling() throws Exception {
1017 final long downTime = SystemClock.uptimeMillis();
1018 final long eventTime = SystemClock.uptimeMillis();
1020 getInstrumentation().runOnMainSync(new Runnable() {
1024 mGestureHandler = new ContentViewGestureHandler(
1025 getInstrumentation().getTargetContext(), mMockMotionEventDelegate);
1026 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1027 assertTrue(mGestureHandler.onTouchEvent(event));
1031 final long longPressTimeoutMs = ViewConfiguration.getLongPressTimeout()
1032 + ViewConfiguration.getTapTimeout() + 10;
1033 assertTrue(mMockMotionEventDelegate.mLongPressCalled.await(
1034 ScalableTimeout.scaleTimeout(longPressTimeoutMs), TimeUnit.MILLISECONDS));
1036 assertEquals("A LONG_PRESS gesture should have been sent",
1037 GestureEventType.LONG_PRESS,
1038 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1040 MotionEvent event = MotionEvent.obtain(
1041 downTime, eventTime + longPressTimeoutMs, MotionEvent.ACTION_MOVE,
1042 FAKE_COORD_X + 100, FAKE_COORD_Y + 100, 0);
1043 mGestureHandler.onTouchEvent(event);
1045 assertEquals("Scrolling should have started",
1046 GestureEventType.SCROLL_BY,
1047 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1048 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1049 GestureEventType.SCROLL_START));
1050 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1051 GestureEventType.TAP_CANCEL));
1053 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + longPressTimeoutMs);
1054 mGestureHandler.onTouchEvent(event);
1055 assertFalse("Scrolling should have prevented the LONG_TAP",
1056 mMockMotionEventDelegate.mGestureTypeList.contains(
1057 GestureEventType.LONG_TAP));
1061 * Verify that LONG_PRESS is not fired during a double-tap sequence.
1066 @Feature({"Gestures"})
1067 public void testNoGestureLongPressDuringDoubleTap() throws Exception {
1068 final long downTime = SystemClock.uptimeMillis();
1069 final long eventTime = SystemClock.uptimeMillis();
1071 getInstrumentation().runOnMainSync(new Runnable() {
1075 mGestureHandler.updateDoubleTapSupport(true);
1077 MotionEvent event = MotionEvent.obtain(
1078 downTime, eventTime, MotionEvent.ACTION_DOWN,
1079 FAKE_COORD_X, FAKE_COORD_Y, 0);
1080 assertTrue(mGestureHandler.onTouchEvent(event));
1082 event = MotionEvent.obtain(
1083 downTime, eventTime + 1, MotionEvent.ACTION_UP,
1084 FAKE_COORD_X, FAKE_COORD_Y, 0);
1085 mGestureHandler.onTouchEvent(event);
1086 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
1087 GestureEventType.SINGLE_TAP_UNCONFIRMED,
1088 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1090 event = MotionEvent.obtain(
1091 downTime + 2, eventTime + 2, MotionEvent.ACTION_DOWN,
1092 FAKE_COORD_X, FAKE_COORD_Y, 0);
1093 assertTrue(mGestureHandler.onTouchEvent(event));
1094 assertEquals("A GESTURE_TAP_DOWN event should have been sent ",
1095 GestureEventType.TAP_DOWN,
1096 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1097 assertTrue(mGestureHandler.isDoubleTapActive());
1101 final int longPressTimeoutMs = ViewConfiguration.getLongPressTimeout()
1102 + ViewConfiguration.getTapTimeout() + 10;
1104 assertFalse(mMockMotionEventDelegate.mLongPressCalled.await(
1105 longPressTimeoutMs, TimeUnit.MILLISECONDS));
1107 assertFalse("A LONG_PRESS gesture should not have been sent",
1108 GestureEventType.LONG_PRESS
1109 == mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1111 MotionEvent event = MotionEvent.obtain(
1112 downTime + 2, eventTime + longPressTimeoutMs, MotionEvent.ACTION_MOVE,
1113 FAKE_COORD_X + 20, FAKE_COORD_Y + 20, 0);
1114 assertTrue(mGestureHandler.onTouchEvent(event));
1115 assertEquals("A double tap drag should have started",
1116 GestureEventType.PINCH_BEGIN,
1117 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1118 assertTrue(mGestureHandler.isDoubleTapActive());
1120 event = MotionEvent.obtain(
1121 downTime + 2, eventTime + longPressTimeoutMs, MotionEvent.ACTION_UP,
1122 FAKE_COORD_X, FAKE_COORD_Y + 1, 0);
1123 assertTrue(mGestureHandler.onTouchEvent(event));
1124 assertEquals("A double tap drag should have ended",
1125 GestureEventType.SCROLL_END,
1126 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1127 assertFalse(mGestureHandler.isDoubleTapActive());
1131 * Verify that the touch slop region is removed from the first scroll delta to avoid a jump when
1132 * starting to scroll.
1136 @Feature({"Gestures"})
1137 public void testTouchSlopRemovedFromScroll() throws Exception {
1138 Context context = getInstrumentation().getTargetContext();
1139 final long downTime = SystemClock.uptimeMillis();
1140 final long eventTime = SystemClock.uptimeMillis();
1141 final int scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
1142 final int scrollDelta = 5;
1144 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1145 assertTrue(mGestureHandler.onTouchEvent(event));
1147 event = MotionEvent.obtain(
1148 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1149 FAKE_COORD_X, FAKE_COORD_Y + scaledTouchSlop + scrollDelta, 0);
1150 assertTrue(mGestureHandler.onTouchEvent(event));
1152 assertEquals("We should have started scrolling",
1153 GestureEventType.SCROLL_BY,
1154 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1156 MockMotionEventDelegate.GestureEvent gestureEvent =
1157 mMockMotionEventDelegate.mMostRecentGestureEvent;
1158 assertNotNull(gestureEvent);
1159 Bundle extraParams = gestureEvent.getExtraParams();
1160 assertEquals(0, extraParams.getInt(ContentViewGestureHandler.DISTANCE_X));
1161 assertEquals(-scrollDelta, extraParams.getInt(ContentViewGestureHandler.DISTANCE_Y));
1165 * Verify that a DOWN followed shortly by an UP will trigger
1166 * a GESTURE_SINGLE_TAP_UNCONFIRMED event immediately.
1171 @Feature({"Gestures"})
1172 public void testGestureEventsSingleTapUnconfirmed() throws Exception {
1173 final long downTime = SystemClock.uptimeMillis();
1174 final long eventTime = SystemClock.uptimeMillis();
1176 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1177 assertTrue(mGestureHandler.onTouchEvent(event));
1178 assertEquals("A TAP_DOWN gesture should have been sent",
1179 GestureEventType.TAP_DOWN,
1180 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1182 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
1183 assertFalse(mGestureHandler.onTouchEvent(event));
1184 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED gesture should have been sent",
1185 GestureEventType.SINGLE_TAP_UNCONFIRMED,
1186 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1187 assertFalse(mMockMotionEventDelegate.mGestureTypeList.contains(
1188 GestureEventType.SINGLE_TAP_CONFIRMED));
1192 * Verify that a tap-ending event will follow a TAP_DOWN event.
1197 @Feature({"Gestures"})
1198 public void testTapDownFollowedByTapEndingEvent() throws Exception {
1199 long downTime = SystemClock.uptimeMillis();
1200 long eventTime = SystemClock.uptimeMillis();
1202 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1203 assertTrue(mGestureHandler.onTouchEvent(event));
1204 assertEquals(GestureEventType.TAP_DOWN,
1205 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1206 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1207 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 5);
1208 mGestureHandler.onTouchEvent(event);
1209 assertEquals(GestureEventType.SINGLE_TAP_UNCONFIRMED,
1210 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1211 assertTrue("An unconfirmed tap does not terminate the tap down.",
1212 mGestureHandler.needsTapEndingEventForTesting());
1214 // A confirmed tap is a tap-ending event.
1217 mMockMotionEventDelegate.mGestureTypeList.clear();
1218 mGestureHandler.updateShouldDisableDoubleTap(true);
1219 event = MotionEvent.obtain(
1220 downTime, downTime, MotionEvent.ACTION_DOWN,
1221 FAKE_COORD_X, FAKE_COORD_Y, 0);
1222 assertTrue(mGestureHandler.onTouchEvent(event));
1223 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1224 event = MotionEvent.obtain(
1225 downTime, eventTime + 5, MotionEvent.ACTION_UP,
1226 FAKE_COORD_X, FAKE_COORD_Y, 0);
1227 assertTrue(mGestureHandler.onTouchEvent(event));
1228 assertEquals(GestureEventType.SINGLE_TAP_CONFIRMED,
1229 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1230 assertFalse("A confirmed single tap should terminate the tap down.",
1231 mGestureHandler.needsTapEndingEventForTesting());
1233 // A double tap gesture is a tap-ending event.
1236 mMockMotionEventDelegate.mGestureTypeList.clear();
1237 mGestureHandler.updateShouldDisableDoubleTap(false);
1238 event = MotionEvent.obtain(
1239 downTime, downTime, MotionEvent.ACTION_DOWN,
1240 FAKE_COORD_X, FAKE_COORD_Y, 0);
1241 assertTrue(mGestureHandler.onTouchEvent(event));
1242 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1243 event = MotionEvent.obtain(
1244 downTime, eventTime + 5, MotionEvent.ACTION_UP,
1245 FAKE_COORD_X, FAKE_COORD_Y, 0);
1246 event = MotionEvent.obtain(
1247 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
1248 FAKE_COORD_X, FAKE_COORD_Y, 0);
1249 assertTrue(mGestureHandler.onTouchEvent(event));
1250 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1251 event = MotionEvent.obtain(
1252 eventTime + 10, eventTime + 15, MotionEvent.ACTION_UP,
1253 FAKE_COORD_X, FAKE_COORD_Y, 0);
1254 assertTrue(mGestureHandler.onTouchEvent(event));
1255 assertEquals(GestureEventType.DOUBLE_TAP,
1256 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1257 assertFalse("A double tap should terminate the tap down.",
1258 mGestureHandler.needsTapEndingEventForTesting());
1260 // A double tap drag gesture will trigger a tap-ending event.
1263 mMockMotionEventDelegate.mGestureTypeList.clear();
1264 mGestureHandler.updateShouldDisableDoubleTap(false);
1265 event = MotionEvent.obtain(
1266 downTime, downTime, MotionEvent.ACTION_DOWN,
1267 FAKE_COORD_X, FAKE_COORD_Y, 0);
1268 assertTrue(mGestureHandler.onTouchEvent(event));
1269 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1270 event = MotionEvent.obtain(
1271 downTime, eventTime + 5, MotionEvent.ACTION_UP,
1272 FAKE_COORD_X, FAKE_COORD_Y, 0);
1273 event = MotionEvent.obtain(
1274 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
1275 FAKE_COORD_X, FAKE_COORD_Y, 0);
1276 assertTrue(mGestureHandler.onTouchEvent(event));
1277 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1278 event = MotionEvent.obtain(
1279 eventTime + 10, eventTime + 15, MotionEvent.ACTION_MOVE,
1280 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1281 assertTrue(mGestureHandler.onTouchEvent(event));
1282 assertFalse("A double tap drag should terminate the tap down.",
1283 mGestureHandler.needsTapEndingEventForTesting());
1284 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1285 GestureEventType.SCROLL_START));
1286 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1287 GestureEventType.TAP_CANCEL));
1288 event = MotionEvent.obtain(
1289 eventTime + 10, eventTime + 20, MotionEvent.ACTION_UP,
1290 FAKE_COORD_X, FAKE_COORD_Y, 0);
1291 assertTrue(mGestureHandler.onTouchEvent(event));
1292 assertFalse(mGestureHandler.needsTapEndingEventForTesting());
1294 // A scroll event will trigger a tap-ending (cancel) event.
1297 mMockMotionEventDelegate.mGestureTypeList.clear();
1298 event = MotionEvent.obtain(
1299 downTime, downTime, MotionEvent.ACTION_DOWN,
1300 FAKE_COORD_X, FAKE_COORD_Y, 0);
1301 assertTrue(mGestureHandler.onTouchEvent(event));
1302 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1303 event = MotionEvent.obtain(
1304 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
1305 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1306 assertTrue(mGestureHandler.onTouchEvent(event));
1307 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1308 GestureEventType.SCROLL_START));
1309 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1310 GestureEventType.TAP_CANCEL));
1311 assertFalse("A scroll should terminate the tap down.",
1312 mGestureHandler.needsTapEndingEventForTesting());
1313 assertFalse(mGestureHandler.needsTapEndingEventForTesting());
1317 * Verify that no double tap gestures are created if the gesture handler is
1318 * told to disable double tap gesture detection (according to the logic in
1319 * ContentViewCore.onRenderCoordinatesUpdated).
1323 @Feature({"Gestures"})
1324 public void testNoDoubleTapWhenDoubleTapDisabled() throws Exception {
1325 final long downTime = SystemClock.uptimeMillis();
1326 final long eventTime = SystemClock.uptimeMillis();
1328 mGestureHandler.updateShouldDisableDoubleTap(true);
1330 MotionEvent event = MotionEvent.obtain(
1331 downTime, downTime, MotionEvent.ACTION_DOWN,
1332 FAKE_COORD_X, FAKE_COORD_Y, 0);
1333 assertTrue(mGestureHandler.onTouchEvent(event));
1334 assertEquals("Only GESTURE_TAP_DOWN should have been sent",
1335 1, mMockMotionEventDelegate.mGestureTypeList.size());
1337 event = MotionEvent.obtain(
1338 downTime, eventTime + 5, MotionEvent.ACTION_UP,
1339 FAKE_COORD_X, FAKE_COORD_Y, 0);
1340 assertTrue(mGestureHandler.onTouchEvent(event));
1341 assertEquals("A GESTURE_SINGLE_TAP_CONFIRMED event should have been sent",
1342 GestureEventType.SINGLE_TAP_CONFIRMED,
1343 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1344 assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SINGLE_TAP_CONFIRMED " +
1345 "should have been sent",
1346 2, mMockMotionEventDelegate.mGestureTypeList.size());
1348 event = MotionEvent.obtain(
1349 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
1350 FAKE_COORD_X, FAKE_COORD_Y, 0);
1351 assertTrue(mGestureHandler.onTouchEvent(event));
1352 assertEquals("Only GESTURE_TAP_DOWN, " +
1353 "GESTURE_SINGLE_TAP_CONFIRMED and " +
1354 "GESTURE_TAP_DOWN should have been sent",
1355 3, mMockMotionEventDelegate.mGestureTypeList.size());
1357 event = MotionEvent.obtain(
1358 eventTime + 10, eventTime + 15, MotionEvent.ACTION_UP,
1359 FAKE_COORD_X, FAKE_COORD_Y, 0);
1360 assertTrue(mGestureHandler.onTouchEvent(event));
1361 assertEquals("A double tap should not have occurred",
1362 GestureEventType.SINGLE_TAP_CONFIRMED,
1363 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1364 assertEquals("Only GESTURE_TAP_DOWN, " +
1365 "GESTURE_SINGLE_TAP_CONFIRMED, " +
1366 "GESTURE_TAP_DOWN and " +
1367 "GESTURE_SINGLE_TAP_CONFIRMED should have been sent",
1368 4, mMockMotionEventDelegate.mGestureTypeList.size());
1372 * Verify that double tap drag zoom feature is not invoked when the gesture
1373 * handler is told to disable double tap gesture detection (according to the
1374 * logic in ContentViewCore.onRenderCoordinatesUpdated).
1375 * The second tap sequence should be treated just as the first would be.
1379 @Feature({"Gestures"})
1380 public void testNoDoubleTapDragZoomWhenDoubleTapDisabled() throws Exception {
1381 final long downTime1 = SystemClock.uptimeMillis();
1382 final long downTime2 = downTime1 + 100;
1384 mGestureHandler.updateShouldDisableDoubleTap(true);
1386 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
1387 assertTrue(mGestureHandler.onTouchEvent(event));
1389 event = MotionEvent.obtain(
1390 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
1391 FAKE_COORD_X, FAKE_COORD_Y, 0);
1392 mGestureHandler.onTouchEvent(event);
1394 event = MotionEvent.obtain(
1395 downTime2, downTime2, MotionEvent.ACTION_DOWN,
1396 FAKE_COORD_X, FAKE_COORD_Y, 0);
1397 assertTrue(mGestureHandler.onTouchEvent(event));
1399 event = MotionEvent.obtain(
1400 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
1401 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1403 // The move should become a scroll, as double tap and drag to zoom is
1405 assertTrue(mGestureHandler.onTouchEvent(event));
1406 assertTrue("GESTURE_SCROLL_START should have been sent",
1407 mMockMotionEventDelegate.mGestureTypeList.contains(
1408 GestureEventType.SCROLL_START));
1409 assertFalse("No GESTURE_PINCH_BEGIN should have been sent",
1410 mMockMotionEventDelegate.mGestureTypeList.contains(
1411 GestureEventType.PINCH_BEGIN));
1413 event = MotionEvent.obtain(
1414 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
1415 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1416 assertTrue(mGestureHandler.onTouchEvent(event));
1417 assertEquals("GESTURE_SCROLL_BY should have been sent",
1418 GestureEventType.SCROLL_BY,
1419 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1420 assertEquals("GESTURE_SCROLL_BY should have been sent",
1421 event.getEventTime(),
1422 mMockMotionEventDelegate.mMostRecentGestureEvent.getTimeMs());
1423 assertTrue("No GESTURE_PINCH_BY should have been sent",
1424 GestureEventType.PINCH_BY !=
1425 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1427 event = MotionEvent.obtain(
1428 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
1429 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1430 assertTrue(mGestureHandler.onTouchEvent(event));
1431 assertFalse("No GESTURE_PINCH_END should have been sent",
1432 mMockMotionEventDelegate.mGestureTypeList.contains(
1433 GestureEventType.PINCH_END));
1437 * Verify that setting a fixed page scale (or a mobile viewport) during a double
1438 * tap drag zoom disables double tap detection after the gesture has ended.
1442 @Feature({"Gestures"})
1443 public void testFixedPageScaleDuringDoubleTapDragZoom() throws Exception {
1444 long downTime1 = SystemClock.uptimeMillis();
1445 long downTime2 = downTime1 + 100;
1447 // Start a double-tap drag gesture.
1448 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
1449 assertTrue(mGestureHandler.onTouchEvent(event));
1450 mGestureHandler.sendShowPressedStateGestureForTesting();
1451 event = MotionEvent.obtain(
1452 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
1453 FAKE_COORD_X, FAKE_COORD_Y, 0);
1454 mGestureHandler.onTouchEvent(event);
1455 event = MotionEvent.obtain(
1456 downTime2, downTime2, MotionEvent.ACTION_DOWN,
1457 FAKE_COORD_X, FAKE_COORD_Y, 0);
1458 assertTrue(mGestureHandler.onTouchEvent(event));
1459 event = MotionEvent.obtain(
1460 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
1461 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1462 assertTrue(mGestureHandler.onTouchEvent(event));
1463 assertTrue("GESTURE_SCROLL_START should have been sent",
1464 mMockMotionEventDelegate.mGestureTypeList.contains(
1465 GestureEventType.SCROLL_START));
1466 assertEquals("GESTURE_PINCH_BEGIN should have been sent",
1467 GestureEventType.PINCH_BEGIN,
1468 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1470 // Simulate setting a fixed page scale (or a mobile viewport);
1471 // this should not disrupt the current double-tap gesture.
1472 mGestureHandler.updateShouldDisableDoubleTap(true);
1474 // Double tap zoom updates should continue.
1475 event = MotionEvent.obtain(
1476 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
1477 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1478 assertTrue(mGestureHandler.onTouchEvent(event));
1479 assertTrue("GESTURE_SCROLL_BY should have been sent",
1480 mMockMotionEventDelegate.mGestureTypeList.contains(
1481 GestureEventType.SCROLL_BY));
1482 assertEquals("GESTURE_PINCH_BY should have been sent",
1483 GestureEventType.PINCH_BY,
1484 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1485 event = MotionEvent.obtain(
1486 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
1487 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1488 assertTrue(mGestureHandler.onTouchEvent(event));
1489 assertTrue("GESTURE_PINCH_END should have been sent",
1490 mMockMotionEventDelegate.mGestureTypeList.contains(
1491 GestureEventType.PINCH_END));
1492 assertEquals("GESTURE_SCROLL_END should have been sent",
1493 GestureEventType.SCROLL_END,
1494 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1496 // The double-tap gesture has finished, but the page scale is fixed.
1497 // The same event sequence should not generate any double tap getsures.
1498 mMockMotionEventDelegate.mGestureTypeList.clear();
1502 // Start a double-tap drag gesture.
1503 event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
1504 assertTrue(mGestureHandler.onTouchEvent(event));
1505 event = MotionEvent.obtain(
1506 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
1507 FAKE_COORD_X, FAKE_COORD_Y, 0);
1508 mGestureHandler.onTouchEvent(event);
1509 event = MotionEvent.obtain(
1510 downTime2, downTime2, MotionEvent.ACTION_DOWN,
1511 FAKE_COORD_X, FAKE_COORD_Y, 0);
1512 assertTrue(mGestureHandler.onTouchEvent(event));
1513 event = MotionEvent.obtain(
1514 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
1515 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1516 assertTrue(mGestureHandler.onTouchEvent(event));
1517 assertTrue("GESTURE_SCROLL_START should have been sent",
1518 mMockMotionEventDelegate.mGestureTypeList.contains(
1519 GestureEventType.SCROLL_START));
1520 assertFalse("GESTURE_PINCH_BEGIN should not have been sent",
1521 mMockMotionEventDelegate.mGestureTypeList.contains(
1522 GestureEventType.PINCH_BEGIN));
1524 // Double tap zoom updates should not be sent.
1525 // Instead, the second tap drag becomes a scroll gesture sequence.
1526 event = MotionEvent.obtain(
1527 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
1528 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1529 assertTrue(mGestureHandler.onTouchEvent(event));
1530 assertTrue("GESTURE_SCROLL_BY should have been sent",
1531 mMockMotionEventDelegate.mGestureTypeList.contains(
1532 GestureEventType.SCROLL_BY));
1533 assertFalse("GESTURE_PINCH_BY should not have been sent",
1534 mMockMotionEventDelegate.mGestureTypeList.contains(
1535 GestureEventType.PINCH_BY));
1536 event = MotionEvent.obtain(
1537 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
1538 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1539 assertTrue(mGestureHandler.onTouchEvent(event));
1540 assertFalse("GESTURE_PINCH_END should not have been sent",
1541 mMockMotionEventDelegate.mGestureTypeList.contains(
1542 GestureEventType.PINCH_END));
1546 * Verify that pinch zoom sends the proper event sequence.
1550 @Feature({"Gestures"})
1551 public void testPinchZoom() throws Exception {
1552 final long downTime = SystemClock.uptimeMillis();
1553 final long eventTime = SystemClock.uptimeMillis();
1554 final Context context = getInstrumentation().getTargetContext();
1555 final int scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
1557 mGestureHandler.updateMultiTouchSupport(true);
1559 final int secondaryCoordX = FAKE_COORD_X + 20 * scaledTouchSlop;
1560 final int secondaryCoordY = FAKE_COORD_Y + 20 * scaledTouchSlop;
1562 PointerProperties pp0 = new PointerProperties();
1564 pp0.toolType = MotionEvent.TOOL_TYPE_FINGER;
1565 PointerProperties pp1 = new PointerProperties();
1567 pp1.toolType = MotionEvent.TOOL_TYPE_FINGER;
1569 PointerCoords pc0 = new PointerCoords();
1570 pc0.x = FAKE_COORD_X;
1571 pc0.y = FAKE_COORD_Y;
1574 PointerCoords pc1 = new PointerCoords();
1575 pc1.x = secondaryCoordX;
1576 pc1.y = secondaryCoordY;
1580 MotionEvent event = MotionEvent.obtain(
1581 eventTime, eventTime, MotionEvent.ACTION_DOWN,
1582 1, new PointerProperties[] { pp0 }, new PointerCoords[] { pc0 },
1583 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
1584 assertTrue(mGestureHandler.onTouchEvent(event));
1585 assertEquals(GestureEventType.TAP_DOWN,
1586 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1587 assertEquals("Only GESTURE_TAP_DOWN should have been sent",
1588 1, mMockMotionEventDelegate.mGestureTypeList.size());
1590 event = MotionEvent.obtain(
1591 eventTime, eventTime, MotionEvent.ACTION_POINTER_DOWN,
1592 2, new PointerProperties[] { pp1, pp0 }, new PointerCoords[] { pc1, pc0 },
1593 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
1594 mGestureHandler.onTouchEvent(event);
1595 assertEquals("No additional gestures should be triggered on a secondary pointer press",
1596 1, mMockMotionEventDelegate.mGestureTypeList.size());
1598 pc1.x = secondaryCoordX + 5 * scaledTouchSlop;
1599 pc1.y = secondaryCoordY + 5 * scaledTouchSlop;
1601 event = MotionEvent.obtain(
1602 eventTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1603 2, new PointerProperties[] { pp1, pp0 }, new PointerCoords[] { pc1, pc0 },
1604 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
1605 assertTrue(mGestureHandler.onTouchEvent(event));
1606 assertEquals("Only GESTURE_TAP_DOWN, " +
1607 "GESTURE_TAP_CANCEL, " +
1608 "GESTURE_SCROLL_BEGIN, " +
1609 "GESTURE_PINCH_BEGIN, " +
1610 "GESTURE_SCROLL_BY, and " +
1611 "GESTURE_PINCH_BY should have been sent",
1612 6, mMockMotionEventDelegate.mGestureTypeList.size());
1613 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1614 GestureEventType.PINCH_BEGIN));
1615 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1616 GestureEventType.SCROLL_START));
1617 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1618 GestureEventType.PINCH_BY));
1619 assertTrue(mMockMotionEventDelegate.mGestureTypeList.contains(
1620 GestureEventType.SCROLL_BY));
1622 event = MotionEvent.obtain(
1623 eventTime, eventTime + 10, MotionEvent.ACTION_POINTER_UP,
1624 2, new PointerProperties[] { pp1, pp0 }, new PointerCoords[] { pc1, pc0 },
1625 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
1626 assertTrue(mGestureHandler.onTouchEvent(event));
1627 assertEquals(GestureEventType.PINCH_END,
1628 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1629 assertEquals("Only GESTURE_PINCH_END should have been sent",
1630 7, mMockMotionEventDelegate.mGestureTypeList.size());
1632 event = MotionEvent.obtain(
1633 eventTime, eventTime, MotionEvent.ACTION_UP,
1634 1, new PointerProperties[] { pp0 }, new PointerCoords[] { pc0 },
1635 0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
1636 mGestureHandler.onTouchEvent(event);
1637 assertEquals(GestureEventType.SCROLL_END,
1638 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1639 assertEquals("Only GESTURE_SCROLL_END should have been sent",
1640 8, mMockMotionEventDelegate.mGestureTypeList.size());
1644 * Verify that the timer of LONG_PRESS will be cancelled when scrolling begins so
1645 * LONG_PRESS and LONG_TAP won't be triggered.
1650 @Feature({"Gestures"})
1651 public void testGesturesCancelledAfterLongPressCausesLostFocus() throws Exception {
1652 final long downTime = SystemClock.uptimeMillis();
1653 final long eventTime = SystemClock.uptimeMillis();
1655 getInstrumentation().runOnMainSync(new Runnable() {
1659 mGestureHandler = new ContentViewGestureHandler(
1660 getInstrumentation().getTargetContext(), mMockMotionEventDelegate);
1661 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1662 assertTrue(mGestureHandler.onTouchEvent(event));
1666 final long longPressTimeoutMs = ViewConfiguration.getLongPressTimeout()
1667 + ViewConfiguration.getTapTimeout() + 10;
1668 assertTrue(mMockMotionEventDelegate.mLongPressCalled.await(
1669 ScalableTimeout.scaleTimeout(longPressTimeoutMs), TimeUnit.MILLISECONDS));
1671 assertEquals("A LONG_PRESS gesture should have been sent",
1672 GestureEventType.LONG_PRESS,
1673 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1675 mGestureHandler.onWindowFocusLost();
1677 assertEquals("The LONG_PRESS should have been cancelled by loss of focus",
1678 GestureEventType.TAP_CANCEL,
1679 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1681 MotionEvent event = motionEvent(
1682 MotionEvent.ACTION_UP, downTime, eventTime + longPressTimeoutMs);
1683 mGestureHandler.onTouchEvent(event);
1684 assertFalse("Tap cancellation should have prevented the LONG_TAP",
1685 mMockMotionEventDelegate.mGestureTypeList.contains(
1686 GestureEventType.LONG_TAP));
1690 * Verify that ignoring the remaining touch sequence triggers proper touch and gesture
1696 @Feature({"Gestures"})
1697 public void testSetIgnoreRemainingTouchEvents() throws Exception {
1698 final long downTime = SystemClock.uptimeMillis();
1699 final long eventTime = SystemClock.uptimeMillis();
1701 mGestureHandler.setIgnoreRemainingTouchEvents();
1702 assertTrue("If there was no active touch sequence, ignoring it should be a no-op",
1703 mMockMotionEventDelegate.mGestureTypeList.isEmpty());
1704 assertEquals("No MotionEvents should have been generated",
1705 -1, mMockMotionEventDelegate.mMostRecentMotionEventAction);
1707 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1708 assertTrue(mGestureHandler.onTouchEvent(event));
1709 assertEquals(GestureEventType.TAP_DOWN,
1710 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1712 mGestureHandler.setIgnoreRemainingTouchEvents();
1713 assertEquals("The TAP_DOWN should have been cancelled",
1714 GestureEventType.TAP_CANCEL,
1715 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);
1716 assertEquals("An ACTION_CANCEL MotionEvent should have been inserted",
1717 MotionEvent.ACTION_CANCEL, mMockMotionEventDelegate.mMostRecentMotionEventAction);
1719 // Subsequent MotionEvent's are dropped until ACTION_DOWN.
1720 event = motionEvent(MotionEvent.ACTION_MOVE, downTime, eventTime + 5);
1721 assertFalse(mGestureHandler.onTouchEvent(event));
1723 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
1724 assertFalse(mGestureHandler.onTouchEvent(event));
1726 event = motionEvent(MotionEvent.ACTION_DOWN, downTime + 15, downTime + 15);
1727 assertTrue(mGestureHandler.onTouchEvent(event));
1728 assertEquals(GestureEventType.TAP_DOWN,
1729 mMockMotionEventDelegate.mMostRecentGestureEvent.mType);