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.MotionEvent;
14 import android.view.MotionEvent.PointerCoords;
15 import android.view.MotionEvent.PointerProperties;
16 import android.view.ViewConfiguration;
18 import org.chromium.base.test.util.Feature;
19 import org.chromium.base.test.util.ScalableTimeout;
20 import org.chromium.content.browser.ContentViewGestureHandler.MotionEventDelegate;
21 import org.chromium.content.browser.third_party.GestureDetector;
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 MockListener mMockListener;
36 private MockMotionEventDelegate mMockMotionEventDelegate;
37 private MockGestureDetector mMockGestureDetector;
38 private MockZoomManager mMockZoomManager;
39 private ContentViewGestureHandler mGestureHandler;
40 private LongPressDetector mLongPressDetector;
42 static class MockListener extends GestureDetector.SimpleOnGestureListener {
43 MotionEvent mLastLongPress;
44 MotionEvent mLastShowPress;
45 MotionEvent mLastSingleTap;
46 MotionEvent mLastFling1;
47 CountDownLatch mLongPressCalled;
48 CountDownLatch mShowPressCalled;
50 public MockListener() {
51 mLongPressCalled = new CountDownLatch(1);
52 mShowPressCalled = new CountDownLatch(1);
56 public void onLongPress(MotionEvent e) {
57 mLastLongPress = MotionEvent.obtain(e);
58 mLongPressCalled.countDown();
62 public void onShowPress(MotionEvent e) {
63 mLastShowPress = MotionEvent.obtain(e);
64 mShowPressCalled.countDown();
65 Log.e("Overscroll", "OnShowPress");
69 public boolean onSingleTapConfirmed(MotionEvent e) {
75 public boolean onSingleTapUp(MotionEvent e) {
81 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
86 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
92 static class MockGestureDetector extends GestureDetector {
93 MotionEvent mLastEvent;
94 public MockGestureDetector(Context context, OnGestureListener listener) {
95 super(context, listener);
99 public boolean onTouchEvent(MotionEvent ev) {
100 mLastEvent = MotionEvent.obtain(ev);
101 return super.onTouchEvent(ev);
105 static class MockMotionEventDelegate implements MotionEventDelegate {
106 private ContentViewGestureHandler mSynchronousConfirmTarget;
107 private int mSynchronousConfirmAckResult;
109 public int mLastTouchAction;
110 public int mLastGestureType;
111 public int mTotalSentGestureCount;
114 public boolean sendTouchEvent(long timeMs, int action, TouchPoint[] pts) {
115 mLastTouchAction = action;
116 if (mSynchronousConfirmTarget != null) {
117 mSynchronousConfirmTarget.confirmTouchEvent(mSynchronousConfirmAckResult);
123 public boolean sendGesture(int type, long timeMs, int x, int y, Bundle extraParams) {
124 Log.i(TAG,"Gesture event received with type id " + type);
125 mLastGestureType = type;
126 mTotalSentGestureCount++;
131 public void sendSingleTapUMA(int type) {
136 public void sendActionAfterDoubleTapUMA(int type,
137 boolean clickDelayEnabled) {
142 public void invokeZoomPicker() {
146 public void enableSynchronousConfirmTouchEvent(
147 ContentViewGestureHandler handler, int ackResult) {
148 mSynchronousConfirmTarget = handler;
149 mSynchronousConfirmAckResult = ackResult;
152 public void disableSynchronousConfirmTouchEvent() {
153 mSynchronousConfirmTarget = null;
157 static class MockZoomManager extends ZoomManager {
158 private ContentViewGestureHandler mHandlerForMoveEvents;
160 MockZoomManager(Context context, ContentViewCore contentViewCore) {
161 super(context, contentViewCore);
164 public void pinchOnMoveEvents(ContentViewGestureHandler handler) {
165 mHandlerForMoveEvents = handler;
169 public boolean processTouchEvent(MotionEvent event) {
170 if (event.getActionMasked() == MotionEvent.ACTION_MOVE
171 && mHandlerForMoveEvents != null) {
172 mHandlerForMoveEvents.pinchBy(event.getEventTime(), 1, 1, 1.1f);
179 private static MotionEvent motionEvent(int action, long downTime, long eventTime) {
180 return MotionEvent.obtain(downTime, eventTime, action, FAKE_COORD_X, FAKE_COORD_Y, 0);
184 public void setUp() {
185 mMockListener = new MockListener();
186 mMockGestureDetector = new MockGestureDetector(
187 getInstrumentation().getTargetContext(), mMockListener);
188 mMockMotionEventDelegate = new MockMotionEventDelegate();
189 mMockZoomManager = new MockZoomManager(getInstrumentation().getTargetContext(), null);
190 mGestureHandler = new ContentViewGestureHandler(
191 getInstrumentation().getTargetContext(), mMockMotionEventDelegate,
193 mLongPressDetector = new LongPressDetector(
194 getInstrumentation().getTargetContext(), mGestureHandler);
195 mGestureHandler.setTestDependencies(
196 mLongPressDetector, mMockGestureDetector, mMockListener);
197 TouchPoint.initializeConstantsForTesting();
201 * Verify that a DOWN followed shortly by an UP will trigger a single tap.
206 @Feature({"Gestures"})
207 public void testGestureSingleClick() throws Exception {
208 final long downTime = SystemClock.uptimeMillis();
209 final long eventTime = SystemClock.uptimeMillis();
211 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
213 assertFalse(mGestureHandler.onTouchEvent(event));
214 assertTrue("Should have a pending gesture", mMockGestureDetector.mLastEvent != null);
215 assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
217 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
218 mLongPressDetector.cancelLongPressIfNeeded(event);
219 assertTrue("Should not have a pending LONG_PRESS", !mLongPressDetector.hasPendingMessage());
220 assertTrue(mGestureHandler.onTouchEvent(event));
221 // Synchronous, no need to wait.
222 assertTrue("Should have a single tap", mMockListener.mLastSingleTap != null);
226 * Verify that when a touch event handler is registered the touch events are queued
231 @Feature({"Gestures"})
232 public void testFlingOnTouchHandler() throws Exception {
233 final long downTime = SystemClock.uptimeMillis();
234 final long eventTime = SystemClock.uptimeMillis();
236 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
238 mGestureHandler.hasTouchEventHandlers(true);
240 assertTrue(mGestureHandler.onTouchEvent(event));
241 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
242 assertTrue("Should not have a pending gesture", mMockGestureDetector.mLastEvent == null);
243 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
245 event = MotionEvent.obtain(
246 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
247 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
248 assertTrue(mGestureHandler.onTouchEvent(event));
249 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
251 event = MotionEvent.obtain(
252 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
253 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
254 assertTrue(mGestureHandler.onTouchEvent(event));
255 assertEquals("We should have coalesced move events into one"
256 , 2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
258 event = MotionEvent.obtain(
259 downTime, eventTime + 15, MotionEvent.ACTION_UP,
260 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
261 assertTrue(mGestureHandler.onTouchEvent(event));
262 assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
264 mGestureHandler.confirmTouchEvent(
265 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
266 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
267 assertEquals(MotionEvent.ACTION_MOVE,
268 mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());
269 assertFalse("Pending LONG_PRESS should have been canceled",
270 mLongPressDetector.hasPendingMessage());
272 mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
273 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
274 assertEquals(MotionEvent.ACTION_UP,
275 mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());
277 mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
278 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
280 // Synchronous, no need to wait.
281 assertTrue("Should not have a fling", mMockListener.mLastFling1 == null);
282 assertTrue("Should not have a long press", mMockListener.mLastLongPress == null);
286 * Verify that after a touch event handlers starts handling a gesture, even though some event
287 * in the middle of the gesture returns with NOT_CONSUMED, we don't send that to the gesture
288 * detector to avoid falling to a faulty state.
292 @Feature({"Gestures"})
293 public void testFlingOnTouchHandlerWithOneEventNotConsumed() throws Exception {
294 final long downTime = SystemClock.uptimeMillis();
295 final long eventTime = SystemClock.uptimeMillis();
297 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
299 mGestureHandler.hasTouchEventHandlers(true);
301 assertTrue(mGestureHandler.onTouchEvent(event));
302 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
303 assertTrue("Should not have a pending gesture", mMockGestureDetector.mLastEvent == null);
304 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
306 event = MotionEvent.obtain(
307 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
308 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
309 assertTrue(mGestureHandler.onTouchEvent(event));
310 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
312 event = MotionEvent.obtain(
313 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
314 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
315 assertTrue(mGestureHandler.onTouchEvent(event));
316 assertEquals("We should have coalesced move events into one"
317 , 2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
319 event = MotionEvent.obtain(
320 downTime, eventTime + 15, MotionEvent.ACTION_UP,
321 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
322 assertTrue(mGestureHandler.onTouchEvent(event));
323 assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
325 mGestureHandler.confirmTouchEvent(
326 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
327 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
328 assertEquals(MotionEvent.ACTION_MOVE,
329 mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());
331 mGestureHandler.confirmTouchEvent(
332 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
333 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
334 assertEquals(MotionEvent.ACTION_UP,
335 mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());
336 assertTrue("Even though the last event was not consumed by JavaScript," +
337 "it shouldn't have been sent to the Gesture Detector",
338 mMockGestureDetector.mLastEvent == null);
340 mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
341 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
343 // Synchronous, no need to wait.
344 assertTrue("Should not have a fling", mMockListener.mLastFling1 == null);
345 assertTrue("Should not have a long press", mMockListener.mLastLongPress == null);
349 * Verify that when a registered touch event handler return NO_CONSUMER_EXISTS for down event
350 * all queue is drained until next down.
354 @Feature({"Gestures"})
355 public void testDrainWithFlingAndClickOutofTouchHandler() throws Exception {
356 final long downTime = SystemClock.uptimeMillis();
357 final long eventTime = SystemClock.uptimeMillis();
359 mGestureHandler = new ContentViewGestureHandler(
360 getInstrumentation().getTargetContext(), new MockMotionEventDelegate(),
362 mLongPressDetector = new LongPressDetector(
363 getInstrumentation().getTargetContext(), mGestureHandler);
365 mGestureHandler.hasTouchEventHandlers(true);
367 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
368 assertTrue(mGestureHandler.onTouchEvent(event));
369 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
370 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
372 event = MotionEvent.obtain(
373 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
374 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
375 assertTrue(mGestureHandler.onTouchEvent(event));
376 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
378 event = MotionEvent.obtain(
379 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
380 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
381 assertTrue(mGestureHandler.onTouchEvent(event));
382 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
384 event = MotionEvent.obtain(
385 downTime, eventTime + 15, MotionEvent.ACTION_UP,
386 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
387 assertTrue(mGestureHandler.onTouchEvent(event));
388 assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
390 event = motionEvent(MotionEvent.ACTION_DOWN, eventTime + 20, eventTime + 20);
391 assertTrue(mGestureHandler.onTouchEvent(event));
392 assertEquals(4, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
394 event = MotionEvent.obtain(
395 downTime, eventTime + 20, MotionEvent.ACTION_UP,
396 FAKE_COORD_X, FAKE_COORD_Y, 0);
397 assertTrue(mGestureHandler.onTouchEvent(event));
398 assertEquals(5, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
400 mGestureHandler.confirmTouchEvent(
401 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
402 assertEquals("The queue should have been drained until first down since no consumer exists",
403 2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
404 assertEquals(MotionEvent.ACTION_DOWN,
405 mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());
407 mGestureHandler.confirmTouchEvent(
408 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
409 assertEquals("The queue should have been drained",
410 0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
414 * Verify that when a touch event handler is registered the touch events stop getting queued
415 * after we received INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS.
419 @Feature({"Gestures"})
420 public void testFlingOutOfTouchHandler() throws Exception {
421 final long downTime = SystemClock.uptimeMillis();
422 final long eventTime = SystemClock.uptimeMillis();
424 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
426 mGestureHandler.hasTouchEventHandlers(true);
428 assertTrue(mGestureHandler.onTouchEvent(event));
429 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
430 assertTrue("Should not have a pending gesture", mMockGestureDetector.mLastEvent == null);
431 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
433 mGestureHandler.confirmTouchEvent(
434 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
435 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
436 assertEquals("The down touch event should have been sent to the Gesture Detector",
437 event.getEventTime(), mMockGestureDetector.mLastEvent.getEventTime());
438 assertEquals("The down touch event should have been sent to the Gesture Detector",
439 MotionEvent.ACTION_DOWN, mMockGestureDetector.mLastEvent.getActionMasked());
441 event = MotionEvent.obtain(
442 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
443 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
444 assertTrue(mGestureHandler.onTouchEvent(event));
445 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
446 assertEquals("Motion events should be going to the Gesture Detector directly",
447 event.getEventTime(), mMockGestureDetector.mLastEvent.getEventTime());
448 assertEquals("Motion events should be going to the Gesture Detector directly",
449 MotionEvent.ACTION_MOVE, mMockGestureDetector.mLastEvent.getActionMasked());
451 event = MotionEvent.obtain(
452 downTime, eventTime + 10, MotionEvent.ACTION_UP,
453 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
454 assertTrue(mGestureHandler.onTouchEvent(event));
455 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
456 assertEquals("Motion events should be going to the Gesture Detector directly",
457 event.getEventTime(), mMockGestureDetector.mLastEvent.getEventTime());
458 assertEquals("Motion events should be going to the Gesture Detector directly",
459 MotionEvent.ACTION_UP, mMockGestureDetector.mLastEvent.getActionMasked());
461 // Synchronous, no need to wait.
462 assertTrue("Should have a fling", mMockListener.mLastFling1 != null);
463 assertTrue("Should not have a long press", mMockListener.mLastLongPress == null);
467 * Verifies that a single tap doesn't cause a long press event to be sent.
471 @Feature({"Gestures"})
472 public void testNoLongPressIsSentForSingleTapOutOfTouchHandler() throws Exception {
473 final long downTime = SystemClock.uptimeMillis();
474 final long eventTime = SystemClock.uptimeMillis();
476 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
478 mGestureHandler.hasTouchEventHandlers(true);
480 assertTrue(mGestureHandler.onTouchEvent(event));
481 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
482 assertTrue("Should not have a pending gesture", mMockGestureDetector.mLastEvent == null);
483 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
485 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 5);
486 assertTrue(mGestureHandler.onTouchEvent(event));
487 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
489 mGestureHandler.confirmTouchEvent(
490 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
492 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
493 assertEquals("The down touch event should have been sent to the Gesture Detector",
494 event.getDownTime(), mMockGestureDetector.mLastEvent.getEventTime());
495 assertEquals("The next event should be ACTION_UP",
496 MotionEvent.ACTION_UP,
497 mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());
499 mGestureHandler.confirmTouchEvent(
500 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
502 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
503 assertEquals("The up touch event should have been sent to the Gesture Detector",
504 event.getEventTime(), mMockGestureDetector.mLastEvent.getEventTime());
506 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
510 * Verify that a DOWN followed by a MOVE will trigger fling (but not LONG).
514 @Feature({"Gestures"})
515 public void testGestureFlingAndCancelLongClick() throws Exception {
516 final long downTime = SystemClock.uptimeMillis();
517 final long eventTime = SystemClock.uptimeMillis();
519 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
521 assertFalse(mGestureHandler.onTouchEvent(event));
522 assertTrue("Should have a pending gesture", mMockGestureDetector.mLastEvent != null);
523 assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
525 event = MotionEvent.obtain(
526 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
527 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
528 mLongPressDetector.cancelLongPressIfNeeded(event);
529 assertTrue("Should not have a pending LONG_PRESS", !mLongPressDetector.hasPendingMessage());
530 assertTrue(mGestureHandler.onTouchEvent(event));
532 event = MotionEvent.obtain(
533 downTime, eventTime + 10, MotionEvent.ACTION_UP,
534 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
535 assertTrue(mGestureHandler.onTouchEvent(event));
537 // Synchronous, no need to wait.
538 assertTrue("Should have a fling", mMockListener.mLastFling1 != null);
539 assertTrue("Should not have a long press", mMockListener.mLastLongPress == null);
543 * Verify that for a normal scroll the following events are sent:
544 * - GESTURE_SCROLL_START
545 * - GESTURE_SCROLL_BY
546 * - GESTURE_SCROLL_END
550 @Feature({"Gestures"})
551 public void testScrollEventActionUpSequence() throws Exception {
552 checkScrollEventSequenceForEndActionType(MotionEvent.ACTION_UP);
556 * Verify that for a cancelled scroll the following events are sent:
557 * - GESTURE_SCROLL_START
558 * - GESTURE_SCROLL_BY
559 * - GESTURE_SCROLL_END
563 @Feature({"Gestures"})
564 public void testScrollEventActionCancelSequence() throws Exception {
565 checkScrollEventSequenceForEndActionType(MotionEvent.ACTION_CANCEL);
568 private void checkScrollEventSequenceForEndActionType(int endActionType) throws Exception {
569 final long downTime = SystemClock.uptimeMillis();
570 final long eventTime = SystemClock.uptimeMillis();
571 final int scrollToX = FAKE_COORD_X + 100;
572 final int scrollToY = FAKE_COORD_Y + 100;
574 GestureRecordingMotionEventDelegate mockDelegate =
575 new GestureRecordingMotionEventDelegate();
576 mGestureHandler = new ContentViewGestureHandler(
577 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
579 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
581 assertTrue(mGestureHandler.onTouchEvent(event));
583 event = MotionEvent.obtain(
584 downTime, eventTime + 1000, MotionEvent.ACTION_MOVE, scrollToX, scrollToY, 0);
585 assertTrue(mGestureHandler.onTouchEvent(event));
586 assertTrue(mGestureHandler.isNativeScrolling());
587 assertTrue("A scrollStart event should have been sent",
588 mockDelegate.mGestureTypeList.contains(
589 ContentViewGestureHandler.GESTURE_SCROLL_START));
590 assertEquals("We should have started scrolling",
591 ContentViewGestureHandler.GESTURE_SCROLL_BY,
592 mockDelegate.mMostRecentGestureEvent.mType);
593 assertEquals("Only tapDown, tapCancel, scrollBegin and scrollBy should have been sent",
594 4, mockDelegate.mGestureTypeList.size());
595 assertEquals("scrollBegin should be sent before scrollBy",
596 ContentViewGestureHandler.GESTURE_SCROLL_START,
597 (int) mockDelegate.mGestureTypeList.get(2));
598 assertEquals("scrollBegin should have the time of the ACTION_MOVE",
599 eventTime + 1000, (long) mockDelegate.mGestureTimeList.get(2));
601 event = MotionEvent.obtain(
602 downTime, eventTime + 1000, endActionType, scrollToX, scrollToY, 0);
603 mGestureHandler.onTouchEvent(event);
604 assertFalse(mGestureHandler.isNativeScrolling());
605 assertTrue("A scrollEnd event should have been sent",
606 mockDelegate.mGestureTypeList.contains(
607 ContentViewGestureHandler.GESTURE_SCROLL_END));
608 assertEquals("We should have stopped scrolling",
609 ContentViewGestureHandler.GESTURE_SCROLL_END,
610 mockDelegate.mMostRecentGestureEvent.mType);
611 assertEquals("Only tapDown, scrollBegin and scrollBy and scrollEnd should have been sent",
612 5, mockDelegate.mGestureTypeList.size());
616 * Verify that for a normal fling (fling after scroll) the following events are sent:
617 * - GESTURE_SCROLL_BEGIN
618 * - GESTURE_FLING_START
619 * and GESTURE_FLING_CANCEL is sent on the next touch.
623 @Feature({"Gestures"})
624 public void testFlingEventSequence() throws Exception {
625 final long downTime = SystemClock.uptimeMillis();
626 final long eventTime = SystemClock.uptimeMillis();
628 GestureRecordingMotionEventDelegate mockDelegate =
629 new GestureRecordingMotionEventDelegate();
630 mGestureHandler = new ContentViewGestureHandler(
631 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
633 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
635 assertTrue(mGestureHandler.onTouchEvent(event));
637 event = MotionEvent.obtain(
638 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
639 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
640 assertTrue(mGestureHandler.onTouchEvent(event));
641 assertTrue(mGestureHandler.isNativeScrolling());
642 assertTrue("A scrollStart event should have been sent",
643 mockDelegate.mGestureTypeList.contains(
644 ContentViewGestureHandler.GESTURE_SCROLL_START));
645 assertEquals("We should have started scrolling",
646 ContentViewGestureHandler.GESTURE_SCROLL_BY,
647 mockDelegate.mMostRecentGestureEvent.mType);
648 assertEquals("Only tapDown, tapCancel, scrollBegin and scrollBy should have been sent",
649 4, mockDelegate.mGestureTypeList.size());
650 assertEquals("scrollBegin should be sent before scrollBy",
651 ContentViewGestureHandler.GESTURE_SCROLL_START,
652 (int) mockDelegate.mGestureTypeList.get(2));
653 GestureRecordingMotionEventDelegate.GestureEvent startEvent =
654 mockDelegate.getActiveScrollStartEvent();
655 assertNotNull(startEvent);
656 assertEquals("scrollBegin should have the time of the ACTION_MOVE",
657 eventTime + 10, (long) startEvent.getTimeMs());
658 int hintX = startEvent.getExtraParams().getInt(ContentViewGestureHandler.DELTA_HINT_X);
659 int hintY = startEvent.getExtraParams().getInt(ContentViewGestureHandler.DELTA_HINT_Y);
660 // We don't want to take a dependency here on exactly how hints are calculated for a
661 // fling (eg. may depend on velocity), so just validate the direction.
662 assertTrue("scrollBegin hint should be in positive X axis",
663 hintX > 0 && hintY > 0 && hintX > hintY);
665 event = MotionEvent.obtain(
666 downTime, eventTime + 15, MotionEvent.ACTION_UP,
667 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
668 assertTrue(mGestureHandler.onTouchEvent(event));
669 assertFalse(mGestureHandler.isNativeScrolling());
670 assertEquals("We should have started flinging",
671 ContentViewGestureHandler.GESTURE_FLING_START,
672 mockDelegate.mMostRecentGestureEvent.mType);
673 assertTrue("A scroll end event should not have been sent",
674 !mockDelegate.mGestureTypeList.contains(
675 ContentViewGestureHandler.GESTURE_SCROLL_END));
676 assertEquals("The last up should have caused flingStart to be sent",
677 5, mockDelegate.mGestureTypeList.size());
678 assertEquals("flingStart should have the time of the ACTION_UP",
679 eventTime + 15, (long) mockDelegate.mGestureTimeList.get(4));
681 event = motionEvent(MotionEvent.ACTION_DOWN, downTime + 50, downTime + 50);
682 assertTrue(mGestureHandler.onTouchEvent(event));
683 assertTrue("A flingCancel should have been sent",
684 mockDelegate.mGestureTypeList.contains(
685 ContentViewGestureHandler.GESTURE_FLING_CANCEL));
686 assertEquals("Only tapDown and flingCancel should have been sent",
687 7, mockDelegate.mGestureTypeList.size());
691 * Verify that a zero-velocity fling is never forwarded, and cancels any
692 * previous fling or scroll sequence.
696 @Feature({"Gestures"})
697 public void testZeroVelocityFling() throws Exception {
698 final long downTime = SystemClock.uptimeMillis();
699 final long eventTime = SystemClock.uptimeMillis();
701 GestureRecordingMotionEventDelegate mockDelegate =
702 new GestureRecordingMotionEventDelegate();
703 mGestureHandler = new ContentViewGestureHandler(
704 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
706 mGestureHandler.fling(eventTime, 5, 5, 0, 0);
707 assertEquals("A zero-velocity fling should not be forwrded",
708 null, mockDelegate.mMostRecentGestureEvent);
710 mGestureHandler.fling(eventTime, 5, 5, 5, 0);
711 assertEquals("Subsequent flings should work properly",
712 ContentViewGestureHandler.GESTURE_FLING_START,
713 mockDelegate.mMostRecentGestureEvent.mType);
715 mGestureHandler.fling(eventTime, 5, 5, 0, 0);
716 assertEquals("A zero-velocity fling should cancel any outstanding fling",
717 ContentViewGestureHandler.GESTURE_FLING_CANCEL,
718 mockDelegate.mMostRecentGestureEvent.mType);
720 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
721 assertTrue(mGestureHandler.onTouchEvent(event));
722 event = MotionEvent.obtain(
723 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
724 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
725 assertTrue(mGestureHandler.onTouchEvent(event));
726 assertTrue(mGestureHandler.isNativeScrolling());
727 assertTrue("A scrollStart event should have been sent",
728 mockDelegate.mGestureTypeList.contains(
729 ContentViewGestureHandler.GESTURE_SCROLL_START));
730 assertEquals("We should have started scrolling",
731 ContentViewGestureHandler.GESTURE_SCROLL_BY,
732 mockDelegate.mMostRecentGestureEvent.mType);
734 mGestureHandler.fling(eventTime, 5, 5, 0, 0);
735 assertEquals("A zero-velicty fling should end the current scroll sequence",
736 ContentViewGestureHandler.GESTURE_SCROLL_END,
737 mockDelegate.mMostRecentGestureEvent.mType);
741 * Verify that a show pressed state gesture followed by a long press followed by the focus
742 * loss in the window due to context menu cancels show pressed.
746 @Feature({"Gestures"})
747 public void testShowPressCancelOnWindowFocusLost() throws Exception {
748 final long time = SystemClock.uptimeMillis();
749 GestureRecordingMotionEventDelegate mockDelegate =
750 new GestureRecordingMotionEventDelegate();
751 mGestureHandler = new ContentViewGestureHandler(
752 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
753 mLongPressDetector = new LongPressDetector(
754 getInstrumentation().getTargetContext(), mGestureHandler);
755 mGestureHandler.setTestDependencies(mLongPressDetector, null, null);
757 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, time, time);
758 mGestureHandler.onTouchEvent(event);
760 mGestureHandler.sendShowPressedStateGestureForTesting();
761 assertEquals("A show pressed state event should have been sent",
762 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
763 mockDelegate.mMostRecentGestureEvent.mType);
764 assertEquals("Only showPressedState and tapDown should have been sent",
765 2, mockDelegate.mGestureTypeList.size());
767 mLongPressDetector.startLongPressTimerIfNeeded(event);
768 mLongPressDetector.sendLongPressGestureForTest();
770 assertEquals("Only should have sent only LONG_PRESS event",
771 3, mockDelegate.mGestureTypeList.size());
772 assertEquals("Should have a long press event next",
773 ContentViewGestureHandler.GESTURE_LONG_PRESS,
774 mockDelegate.mGestureTypeList.get(2).intValue());
776 // The long press triggers window focus loss by opening a context menu
777 mGestureHandler.onWindowFocusLost();
779 assertEquals("Only should have sent only GESTURE_TAP_CANCEL event",
780 4, mockDelegate.mGestureTypeList.size());
781 assertEquals("Should have a gesture show press cancel event next",
782 ContentViewGestureHandler.GESTURE_TAP_CANCEL,
783 mockDelegate.mGestureTypeList.get(3).intValue());
787 * Verify that a recent show pressed state gesture is canceled when scrolling begins.
791 @Feature({"Gestures"})
792 public void testShowPressCancelWhenScrollBegins() throws Exception {
793 final long downTime = SystemClock.uptimeMillis();
794 final long eventTime = SystemClock.uptimeMillis();
796 GestureRecordingMotionEventDelegate mockDelegate =
797 new GestureRecordingMotionEventDelegate();
798 mGestureHandler = new ContentViewGestureHandler(
799 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
800 mLongPressDetector = new LongPressDetector(
801 getInstrumentation().getTargetContext(), mGestureHandler);
803 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
805 assertTrue(mGestureHandler.onTouchEvent(event));
806 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
808 mGestureHandler.sendShowPressedStateGestureForTesting();
810 assertEquals("A show pressed state event should have been sent",
811 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
812 mockDelegate.mMostRecentGestureEvent.mType);
813 assertEquals("Only tapDown and showPressedState should have been sent",
814 2, mockDelegate.mGestureTypeList.size());
816 event = MotionEvent.obtain(
817 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
818 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
819 assertTrue(mGestureHandler.onTouchEvent(event));
821 assertEquals("We should have started scrolling",
822 ContentViewGestureHandler.GESTURE_SCROLL_BY,
823 mockDelegate.mMostRecentGestureEvent.mType);
824 assertTrue("A show press cancel event should have been sent",
825 mockDelegate.mGestureTypeList.contains(
826 ContentViewGestureHandler.GESTURE_TAP_CANCEL));
827 assertEquals("Only tapDown, showPressedState, showPressCancel, scrollBegin and scrollBy" +
828 " should have been sent",
829 5, mockDelegate.mGestureTypeList.size());
831 event = MotionEvent.obtain(
832 downTime, eventTime + 15, MotionEvent.ACTION_UP,
833 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
834 assertTrue(mGestureHandler.onTouchEvent(event));
835 assertEquals("We should have started flinging",
836 ContentViewGestureHandler.GESTURE_FLING_START,
837 mockDelegate.mMostRecentGestureEvent.mType);
838 assertTrue("A scroll end event should not have been sent",
839 !mockDelegate.mGestureTypeList.contains(
840 ContentViewGestureHandler.GESTURE_SCROLL_END));
841 assertEquals("The last up should have caused flingStart to be sent",
842 6, mockDelegate.mGestureTypeList.size());
846 * Verify that double tap is correctly handled including the recent show pressed state gesture
851 @Feature({"Gestures"})
852 public void testDoubleTap() throws Exception {
853 final long downTime = SystemClock.uptimeMillis();
854 final long eventTime = SystemClock.uptimeMillis();
856 GestureRecordingMotionEventDelegate mockDelegate =
857 new GestureRecordingMotionEventDelegate();
858 mGestureHandler = new ContentViewGestureHandler(
859 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
860 mLongPressDetector = new LongPressDetector(
861 getInstrumentation().getTargetContext(), mGestureHandler);
863 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
864 assertTrue(mGestureHandler.onTouchEvent(event));
865 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
867 mGestureHandler.sendShowPressedStateGestureForTesting();
868 assertEquals("GESTURE_SHOW_PRESSED_STATE should have been sent",
869 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
870 mockDelegate.mMostRecentGestureEvent.mType);
871 assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SHOW_PRESSED_STATE should have been sent",
872 2, mockDelegate.mGestureTypeList.size());
874 event = MotionEvent.obtain(
875 downTime, eventTime + 5, MotionEvent.ACTION_UP,
876 FAKE_COORD_X, FAKE_COORD_Y, 0);
877 mGestureHandler.onTouchEvent(event);
878 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
879 ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED,
880 mockDelegate.mMostRecentGestureEvent.mType);
881 assertEquals("Only GESTURE_TAP_DOWN, " +
882 "GESTURE_SHOW_PRESSED_STATE and " +
883 "GESTURE_SINGLE_TAP_UNCONFIRMED should have been sent",
884 3, mockDelegate.mGestureTypeList.size());
886 event = MotionEvent.obtain(
887 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
888 FAKE_COORD_X, FAKE_COORD_Y, 0);
889 assertTrue(mGestureHandler.onTouchEvent(event));
890 assertEquals("A GESTURE_TAP_DOWN event should have been sent ",
891 ContentViewGestureHandler.GESTURE_TAP_DOWN,
892 mockDelegate.mMostRecentGestureEvent.mType);
893 assertEquals("Only GESTURE_TAP_DOWN, " +
894 "GESTURE_SHOW_PRESSED_STATE, " +
895 "GESTURE_SINGLE_TAP_UNCONFIRMED," +
896 "GESTURE_TAP_CANCEL and" +
897 "GESTURE_TAP_DOWN should have been sent",
898 5, mockDelegate.mGestureTypeList.size());
900 // Moving a very small amount of distance should not trigger the double tap drag zoom mode.
901 event = MotionEvent.obtain(
902 eventTime + 10, eventTime + 10, MotionEvent.ACTION_MOVE,
903 FAKE_COORD_X, FAKE_COORD_Y + 1, 0);
904 assertTrue(mGestureHandler.onTouchEvent(event));
905 assertEquals("Only GESTURE_TAP_DOWN, " +
906 "GESTURE_SHOW_PRESSED_STATE, " +
907 "GESTURE_SINGLE_TAP_UNCONFIRMED and" +
908 "GESTURE_TAP_CANCEL and" +
909 "GESTURE_TAP_DOWN should have been sent",
910 5, mockDelegate.mGestureTypeList.size());
912 event = MotionEvent.obtain(
913 eventTime + 10, eventTime + 15, MotionEvent.ACTION_UP,
914 FAKE_COORD_X, FAKE_COORD_Y + 1, 0);
915 assertTrue(mGestureHandler.onTouchEvent(event));
916 assertEquals("A double tap should have occurred",
917 ContentViewGestureHandler.GESTURE_DOUBLE_TAP,
918 mockDelegate.mMostRecentGestureEvent.mType);
919 assertEquals("Only GESTURE_TAP_DOWN, " +
920 "GESTURE_SHOW_PRESSED_STATE, " +
921 "GESTURE_SINGLE_TAP_UNCONFIRMED, " +
922 "GESTURE_TAP_CANCEL, " +
923 "GESTURE_TAP_DOWN, " +
924 "GESTURE_DOUBLE_TAP should have been sent",
925 6, mockDelegate.mGestureTypeList.size());
929 * Verify that double tap drag zoom feature is correctly executed.
933 @Feature({"Gestures"})
934 public void testDoubleTapDragZoom() throws Exception {
935 final long downTime1 = SystemClock.uptimeMillis();
936 final long downTime2 = downTime1 + 100;
938 GestureRecordingMotionEventDelegate mockDelegate =
939 new GestureRecordingMotionEventDelegate();
940 mGestureHandler = new ContentViewGestureHandler(
941 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
942 mLongPressDetector = new LongPressDetector(
943 getInstrumentation().getTargetContext(), mGestureHandler);
945 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
946 assertTrue(mGestureHandler.onTouchEvent(event));
947 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
949 mGestureHandler.sendShowPressedStateGestureForTesting();
950 assertEquals("GESTURE_SHOW_PRESSED_STATE should have been sent",
951 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
952 mockDelegate.mMostRecentGestureEvent.mType);
953 assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SHOW_PRESSED_STATE should have been sent",
954 2, mockDelegate.mGestureTypeList.size());
957 event = MotionEvent.obtain(
958 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
959 FAKE_COORD_X, FAKE_COORD_Y, 0);
960 mGestureHandler.onTouchEvent(event);
961 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
962 ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED,
963 mockDelegate.mMostRecentGestureEvent.mType);
964 assertEquals("Only GESTURE_TAP_DOWN, " +
965 "GESTURE_SHOW_PRESSED_STATE and " +
966 "GESTURE_TAP_UNCONFIRMED " +
967 "should have been sent",
968 3, mockDelegate.mGestureTypeList.size());
970 event = MotionEvent.obtain(
971 downTime2, downTime2, MotionEvent.ACTION_DOWN,
972 FAKE_COORD_X, FAKE_COORD_Y, 0);
973 assertTrue(mGestureHandler.onTouchEvent(event));
974 assertEquals("GESTURE_TAP_DOWN should have been sent",
975 ContentViewGestureHandler.GESTURE_TAP_DOWN,
976 mockDelegate.mMostRecentGestureEvent.mType);
977 assertEquals("Only GESTURE_TAP_DOWN, " +
978 "GESTURE_SHOW_PRESSED_STATE, " +
979 "GESTURE_TAP_UNCONFIRMED," +
980 "GESTURE_TAP_CANCEL and" +
981 "GESTURE_TAP_DOWN should have been sent",
982 5, mockDelegate.mGestureTypeList.size());
984 event = MotionEvent.obtain(
985 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
986 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
987 assertTrue(mGestureHandler.onTouchEvent(event));
988 assertTrue("GESTURE_SCROLL_START should have been sent",
989 mockDelegate.mGestureTypeList.contains(
990 ContentViewGestureHandler.GESTURE_SCROLL_START));
991 GestureRecordingMotionEventDelegate.GestureEvent startEvent =
992 mockDelegate.getActiveScrollStartEvent();
993 assertEquals(FAKE_COORD_X, startEvent.getX());
994 assertEquals(FAKE_COORD_Y + 100, startEvent.getY());
995 Bundle extraParams = startEvent.getExtraParams();
996 assertNotNull(extraParams);
997 assertEquals("GESTURE_SCROLL_START should have an X hint equal to the distance traveled",
998 0, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_X));
999 assertEquals("GESTURE_SCROLL_START should have an X hint equal to the distance traveled",
1000 100, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_Y));
1002 assertEquals("GESTURE_PINCH_BEGIN should have been sent",
1003 ContentViewGestureHandler.GESTURE_PINCH_BEGIN,
1004 mockDelegate.mMostRecentGestureEvent.mType);
1005 assertEquals("Only GESTURE_TAP_DOWN, " +
1006 "GESTURE_SHOW_PRESSED_STATE, " +
1007 "GESTURE_TAP_UNCONFIRMED," +
1008 "GESTURE_TAP_CANCEL, " +
1009 "GESTURE_TAP_DOWN, " +
1010 "GESTURE_TAP_CANCEL, " +
1011 "GESTURE_SCROLL_START, and " +
1012 "GESTURE_PINCH_BEGIN should have been sent",
1013 8, mockDelegate.mGestureTypeList.size());
1015 event = MotionEvent.obtain(
1016 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
1017 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1018 assertTrue(mGestureHandler.onTouchEvent(event));
1019 assertTrue("GESTURE_SCROLL_BY should have been sent",
1020 mockDelegate.mGestureTypeList.contains(
1021 ContentViewGestureHandler.GESTURE_SCROLL_BY));
1022 assertEquals("GESTURE_PINCH_BY should have been sent",
1023 ContentViewGestureHandler.GESTURE_PINCH_BY,
1024 mockDelegate.mMostRecentGestureEvent.mType);
1025 assertEquals("Only GESTURE_TAP_DOWN, " +
1026 "GESTURE_SHOW_PRESSED_STATE, " +
1027 "GESTURE_TAP_UNCONFIRMED," +
1028 "GESTURE_TAP_CANCEL, " +
1029 "GESTURE_TAP_DOWN, " +
1030 "GESTURE_TAP_CANCEL, " +
1031 "GESTURE_SCROLL_START," +
1032 "GESTURE_PINCH_BEGIN, " +
1033 "GESTURE_SCROLL_BY, and " +
1034 "GESTURE_PINCH_BY should have been sent",
1035 10, mockDelegate.mGestureTypeList.size());
1037 event = MotionEvent.obtain(
1038 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
1039 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1040 assertTrue(mGestureHandler.onTouchEvent(event));
1041 assertTrue("GESTURE_PINCH_END should have been sent",
1042 mockDelegate.mGestureTypeList.contains(
1043 ContentViewGestureHandler.GESTURE_PINCH_END));
1044 assertEquals("GESTURE_SCROLL_END should have been sent",
1045 ContentViewGestureHandler.GESTURE_SCROLL_END,
1046 mockDelegate.mMostRecentGestureEvent.mType);
1047 assertEquals("Only GESTURE_TAP_DOWN, " +
1048 "GESTURE_SHOW_PRESSED_STATE, " +
1049 "GESTURE_TAP_UNCONFIRMED," +
1050 "GESTURE_TAP_CANCEL, " +
1051 "GESTURE_TAP_DOWN, " +
1052 "GESTURE_TAP_CANCEL, " +
1053 "GESTURE_SCROLL_START," +
1054 "GESTURE_PINCH_BEGIN, " +
1055 "GESTURE_SCROLL_BY," +
1056 "GESTURE_PINCH_BY, " +
1057 "GESTURE_PINCH_END, and " +
1058 "GESTURE_SCROLL_END should have been sent",
1059 12, mockDelegate.mGestureTypeList.size());
1064 * Verify that double tap drag zoom is cancelled if the user presses a
1065 * secondary pointer.
1069 @Feature({"Gestures"})
1070 public void testDoubleTapDragZoomCancelledOnSecondaryPointerDown() throws Exception {
1071 final long downTime1 = SystemClock.uptimeMillis();
1072 final long downTime2 = downTime1 + 100;
1074 GestureRecordingMotionEventDelegate mockDelegate =
1075 new GestureRecordingMotionEventDelegate();
1076 mGestureHandler = new ContentViewGestureHandler(
1077 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
1078 mLongPressDetector = new LongPressDetector(
1079 getInstrumentation().getTargetContext(), mGestureHandler);
1081 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
1082 assertTrue(mGestureHandler.onTouchEvent(event));
1084 mGestureHandler.sendShowPressedStateGestureForTesting();
1085 assertEquals("GESTURE_SHOW_PRESSED_STATE should have been sent",
1086 ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
1087 mockDelegate.mMostRecentGestureEvent.mType);
1088 assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SHOW_PRESSED_STATE should have been sent",
1089 2, mockDelegate.mGestureTypeList.size());
1091 event = MotionEvent.obtain(
1092 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
1093 FAKE_COORD_X, FAKE_COORD_Y, 0);
1094 mGestureHandler.onTouchEvent(event);
1095 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED event should have been sent",
1096 ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED,
1097 mockDelegate.mMostRecentGestureEvent.mType);
1098 assertEquals("Only GESTURE_TAP_DOWN, " +
1099 "GESTURE_SHOW_PRESSED_STATE and " +
1100 "GESTURE_TAP_UNCONFIRMED " +
1101 "should have been sent",
1102 3, mockDelegate.mGestureTypeList.size());
1104 event = MotionEvent.obtain(
1105 downTime2, downTime2, MotionEvent.ACTION_DOWN,
1106 FAKE_COORD_X, FAKE_COORD_Y, 0);
1107 assertTrue(mGestureHandler.onTouchEvent(event));
1108 assertEquals("GESTURE_TAP_DOWN should have been sent",
1109 ContentViewGestureHandler.GESTURE_TAP_DOWN,
1110 mockDelegate.mMostRecentGestureEvent.mType);
1111 assertEquals("Only GESTURE_TAP_DOWN, " +
1112 "GESTURE_SHOW_PRESSED_STATE, " +
1113 "GESTURE_TAP_UNCONFIRMED," +
1114 "GESTURE_TAP_CANCEL and" +
1115 "GESTURE_TAP_DOWN should have been sent",
1116 5, mockDelegate.mGestureTypeList.size());
1118 event = MotionEvent.obtain(
1119 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
1120 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1121 assertTrue(mGestureHandler.onTouchEvent(event));
1122 assertTrue("GESTURE_SCROLL_START should have been sent",
1123 mockDelegate.mGestureTypeList.contains(
1124 ContentViewGestureHandler.GESTURE_SCROLL_START));
1126 assertEquals("GESTURE_PINCH_BEGIN should have been sent",
1127 ContentViewGestureHandler.GESTURE_PINCH_BEGIN,
1128 mockDelegate.mMostRecentGestureEvent.mType);
1129 assertEquals("Only GESTURE_TAP_DOWN, " +
1130 "GESTURE_SHOW_PRESSED_STATE, " +
1131 "GESTURE_TAP_UNCONFIRMED," +
1132 "GESTURE_TAP_CANCEL, " +
1133 "GESTURE_TAP_DOWN, " +
1134 "GESTURE_TAP_CANCEL, " +
1135 "GESTURE_SCROLL_START, and " +
1136 "GESTURE_PINCH_BEGIN should have been sent",
1137 8, mockDelegate.mGestureTypeList.size());
1139 event = MotionEvent.obtain(
1140 downTime2, downTime2 + 10, MotionEvent.ACTION_POINTER_DOWN,
1141 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1142 mGestureHandler.onTouchEvent(event);
1143 assertTrue("GESTURE_PINCH_END should have been sent",
1144 mockDelegate.mGestureTypeList.contains(
1145 ContentViewGestureHandler.GESTURE_PINCH_END));
1146 assertEquals("GESTURE_SCROLL_END should have been sent",
1147 ContentViewGestureHandler.GESTURE_SCROLL_END,
1148 mockDelegate.mMostRecentGestureEvent.mType);
1149 assertEquals("Only GESTURE_TAP_DOWN, " +
1150 "GESTURE_SHOW_PRESSED_STATE, " +
1151 "GESTURE_TAP_UNCONFIRMED," +
1152 "GESTURE_TAP_CANCEL, " +
1153 "GESTURE_TAP_DOWN, " +
1154 "GESTURE_TAP_CANCEL, " +
1155 "GESTURE_SCROLL_START," +
1156 "GESTURE_PINCH_BEGIN, " +
1157 "GESTURE_PINCH_END, and " +
1158 "GESTURE_SCROLL_END should have been sent",
1159 10, mockDelegate.mGestureTypeList.size());
1161 event = MotionEvent.obtain(
1162 downTime2, downTime2 + 15, MotionEvent.ACTION_POINTER_UP,
1163 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1164 mGestureHandler.onTouchEvent(event);
1165 assertEquals("No new gestures should have been sent",
1166 10, mockDelegate.mGestureTypeList.size());
1168 event = MotionEvent.obtain(
1169 downTime2, downTime2 + 20, MotionEvent.ACTION_UP,
1170 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1171 mGestureHandler.onTouchEvent(event);
1172 assertEquals("No new gestures should have been sent",
1173 10, mockDelegate.mGestureTypeList.size());
1177 * Verify that double tap drag zoom feature is not invoked
1178 * when it is disabled..
1182 @Feature({"Gestures"})
1183 public void testDoubleTapDragZoomNothingWhenDisabled() throws Exception {
1184 final long downTime1 = SystemClock.uptimeMillis();
1185 final long downTime2 = downTime1 + 100;
1187 GestureRecordingMotionEventDelegate mockDelegate =
1188 new GestureRecordingMotionEventDelegate();
1189 mGestureHandler = new ContentViewGestureHandler(
1190 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
1191 mGestureHandler.updateDoubleTapSupport(false);
1193 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
1194 assertTrue(mGestureHandler.onTouchEvent(event));
1196 event = MotionEvent.obtain(
1197 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
1198 FAKE_COORD_X, FAKE_COORD_Y, 0);
1199 mGestureHandler.onTouchEvent(event);
1201 event = MotionEvent.obtain(
1202 downTime2, downTime2, MotionEvent.ACTION_DOWN,
1203 FAKE_COORD_X, FAKE_COORD_Y, 0);
1204 assertTrue(mGestureHandler.onTouchEvent(event));
1206 event = MotionEvent.obtain(
1207 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
1208 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1210 // The move should become a scroll, as double tap and drag to zoom is
1212 assertTrue(mGestureHandler.onTouchEvent(event));
1213 assertTrue("GESTURE_SCROLL_START should have been sent",
1214 mockDelegate.mGestureTypeList.contains(
1215 ContentViewGestureHandler.GESTURE_SCROLL_START));
1216 assertFalse("No GESTURE_PINCH_BEGIN should have been sent",
1217 mockDelegate.mGestureTypeList.contains(
1218 ContentViewGestureHandler.GESTURE_PINCH_BEGIN));
1220 event = MotionEvent.obtain(
1221 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
1222 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1223 assertTrue(mGestureHandler.onTouchEvent(event));
1224 assertEquals("GESTURE_SCROLL_BY should have been sent",
1225 ContentViewGestureHandler.GESTURE_SCROLL_BY,
1226 mockDelegate.mMostRecentGestureEvent.mType);
1227 assertEquals("GESTURE_SCROLL_BY should have been sent",
1228 event.getEventTime(),
1229 mockDelegate.mMostRecentGestureEvent.getTimeMs());
1230 assertTrue("No GESTURE_PINCH_BY should have been sent",
1231 ContentViewGestureHandler.GESTURE_PINCH_BY !=
1232 mockDelegate.mMostRecentGestureEvent.mType);
1234 event = MotionEvent.obtain(
1235 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
1236 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
1237 assertTrue(mGestureHandler.onTouchEvent(event));
1238 assertFalse("No GESTURE_PINCH_END should have been sent",
1239 mockDelegate.mGestureTypeList.contains(
1240 ContentViewGestureHandler.GESTURE_PINCH_END));
1244 * Mock MotionEventDelegate that remembers the most recent gesture event and any
1245 * currently active scroll start event.
1247 static class GestureRecordingMotionEventDelegate implements MotionEventDelegate {
1248 static class GestureEvent {
1249 private final int mType;
1250 private final long mTimeMs;
1251 private final int mX;
1252 private final int mY;
1253 private final Bundle mExtraParams;
1255 public GestureEvent(int type, long timeMs, int x, int y, Bundle extraParams) {
1260 mExtraParams = extraParams;
1263 public int getType() {
1267 public long getTimeMs() {
1279 public Bundle getExtraParams() {
1280 return mExtraParams;
1283 private GestureEvent mMostRecentGestureEvent;
1284 private GestureEvent mActiveScrollStartEvent;
1285 private final ArrayList<Integer> mGestureTypeList = new ArrayList<Integer>();
1286 private final ArrayList<Long> mGestureTimeList = new ArrayList<Long>();
1289 public boolean sendTouchEvent(long timeMs, int action, TouchPoint[] pts) {
1294 public boolean sendGesture(int type, long timeMs, int x, int y, Bundle extraParams) {
1295 Log.i(TAG, "Gesture event received with type id " + type);
1296 mMostRecentGestureEvent = new GestureEvent(type, timeMs, x, y, extraParams);
1297 mGestureTypeList.add(mMostRecentGestureEvent.mType);
1298 mGestureTimeList.add(timeMs);
1299 if (type == ContentViewGestureHandler.GESTURE_SCROLL_START)
1300 mActiveScrollStartEvent = mMostRecentGestureEvent;
1301 else if (type == ContentViewGestureHandler.GESTURE_SCROLL_END ||
1302 type == ContentViewGestureHandler.GESTURE_FLING_CANCEL)
1303 mActiveScrollStartEvent = null;
1308 public void sendSingleTapUMA(int type) {
1313 public void sendActionAfterDoubleTapUMA(int type,
1314 boolean clickDelayEnabled) {
1319 public void invokeZoomPicker() {
1323 public GestureEvent getMostRecentGestureEvent() {
1324 return mMostRecentGestureEvent;
1327 public GestureEvent getActiveScrollStartEvent() {
1328 return mActiveScrollStartEvent;
1333 * Generate a scroll gesture and verify that the resulting scroll motion event has both absolute
1334 * and relative position information.
1337 @Feature({"Gestures"})
1338 public void testScrollUpdateCoordinates() {
1339 final int deltaX = 16;
1340 final int deltaY = 84;
1341 final long downTime = SystemClock.uptimeMillis();
1343 GestureRecordingMotionEventDelegate delegate = new GestureRecordingMotionEventDelegate();
1344 ContentViewGestureHandler gestureHandler = new ContentViewGestureHandler(
1345 getInstrumentation().getTargetContext(), delegate, mMockZoomManager);
1346 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1347 assertTrue(gestureHandler.onTouchEvent(event));
1349 // Move twice so that we get two GESTURE_SCROLL_BY events and can compare
1350 // the relative and absolute coordinates.
1351 event = MotionEvent.obtain(
1352 downTime, downTime + 5, MotionEvent.ACTION_MOVE,
1353 FAKE_COORD_X - deltaX / 2, FAKE_COORD_Y - deltaY / 2, 0);
1354 assertTrue(gestureHandler.onTouchEvent(event));
1356 event = MotionEvent.obtain(
1357 downTime, downTime + 10, MotionEvent.ACTION_MOVE,
1358 FAKE_COORD_X - deltaX, FAKE_COORD_Y - deltaY, 0);
1359 assertTrue(gestureHandler.onTouchEvent(event));
1361 // Make sure the reported gesture event has all the expected data.
1362 GestureRecordingMotionEventDelegate.GestureEvent gestureEvent =
1363 delegate.getMostRecentGestureEvent();
1364 assertNotNull(gestureEvent);
1365 assertEquals(ContentViewGestureHandler.GESTURE_SCROLL_BY, gestureEvent.getType());
1366 assertEquals(downTime + 10, gestureEvent.getTimeMs());
1367 assertEquals(FAKE_COORD_X - deltaX, gestureEvent.getX());
1368 assertEquals(FAKE_COORD_Y - deltaY, gestureEvent.getY());
1370 Bundle extraParams = gestureEvent.getExtraParams();
1371 assertNotNull(extraParams);
1372 // No horizontal delta because of snapping.
1373 assertEquals(0, extraParams.getInt(ContentViewGestureHandler.DISTANCE_X));
1374 assertEquals(deltaY / 2, extraParams.getInt(ContentViewGestureHandler.DISTANCE_Y));
1378 * Generate a scroll gesture and verify that the resulting scroll start event
1379 * has the expected hint values.
1382 @Feature({"Gestures"})
1383 public void testScrollStartValues() {
1384 final int deltaX = 13;
1385 final int deltaY = 89;
1386 final long downTime = SystemClock.uptimeMillis();
1388 GestureRecordingMotionEventDelegate delegate = new GestureRecordingMotionEventDelegate();
1389 ContentViewGestureHandler gestureHandler = new ContentViewGestureHandler(
1390 getInstrumentation().getTargetContext(), delegate, mMockZoomManager);
1391 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1392 assertTrue(gestureHandler.onTouchEvent(event));
1394 // Move twice such that the first event isn't sufficient to start
1395 // scrolling on it's own.
1396 event = MotionEvent.obtain(
1397 downTime, downTime + 5, MotionEvent.ACTION_MOVE,
1398 FAKE_COORD_X + 2, FAKE_COORD_Y + 1, 0);
1399 assertFalse(gestureHandler.onTouchEvent(event));
1400 assertNull("Expect scrolling hasn't yet started",
1401 delegate.getActiveScrollStartEvent());
1403 event = MotionEvent.obtain(
1404 downTime, downTime + 10, MotionEvent.ACTION_MOVE,
1405 FAKE_COORD_X + deltaX, FAKE_COORD_Y + deltaY, 0);
1406 assertTrue(gestureHandler.onTouchEvent(event));
1408 GestureRecordingMotionEventDelegate.GestureEvent startEvent =
1409 delegate.getActiveScrollStartEvent();
1410 assertNotNull(startEvent);
1411 assertEquals(ContentViewGestureHandler.GESTURE_SCROLL_START, startEvent.getType());
1412 assertEquals(downTime + 10, startEvent.getTimeMs());
1413 assertEquals(FAKE_COORD_X, startEvent.getX());
1414 assertEquals(FAKE_COORD_Y, startEvent.getY());
1416 Bundle extraParams = startEvent.getExtraParams();
1417 assertNotNull(extraParams);
1418 assertEquals(deltaX, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_X));
1419 assertEquals(deltaY, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_Y));
1423 * Verify that the timer of LONG_PRESS will be cancelled when scrolling begins so
1424 * LONG_PRESS and LONG_TAP won't be triggered.
1429 @Feature({"Gestures"})
1430 public void testLongPressAndTapCancelWhenScrollBegins() throws Exception {
1431 final long downTime = SystemClock.uptimeMillis();
1432 final long eventTime = SystemClock.uptimeMillis();
1434 GestureRecordingMotionEventDelegate mockDelegate =
1435 new GestureRecordingMotionEventDelegate();
1436 mGestureHandler = new ContentViewGestureHandler(
1437 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
1438 mLongPressDetector = mGestureHandler.getLongPressDetector();
1440 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1441 assertTrue(mGestureHandler.onTouchEvent(event));
1442 assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
1443 event = MotionEvent.obtain(
1444 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
1445 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
1446 assertTrue(mGestureHandler.onTouchEvent(event));
1447 event = MotionEvent.obtain(
1448 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1449 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
1450 assertTrue(mGestureHandler.onTouchEvent(event));
1451 assertTrue("Should not have a pending LONG_PRESS", !mLongPressDetector.hasPendingMessage());
1453 // No LONG_TAP because LONG_PRESS timer is cancelled.
1454 assertFalse("No LONG_PRESS should be sent",
1455 mockDelegate.mGestureTypeList.contains(
1456 ContentViewGestureHandler.GESTURE_LONG_PRESS));
1457 assertFalse("No LONG_TAP should be sent",
1458 mockDelegate.mGestureTypeList.contains(
1459 ContentViewGestureHandler.GESTURE_LONG_TAP));
1463 * Verifies that when hasTouchEventHandlers changes while in a gesture, that the pending
1464 * queue does not grow continually.
1467 @Feature({"Gestures"})
1468 public void testHasTouchEventHandlersChangesInGesture() {
1469 final long downTime = SystemClock.uptimeMillis();
1470 final long eventTime = SystemClock.uptimeMillis();
1472 mGestureHandler = new ContentViewGestureHandler(
1473 getInstrumentation().getTargetContext(), new MockMotionEventDelegate(),
1475 mLongPressDetector = new LongPressDetector(
1476 getInstrumentation().getTargetContext(), mGestureHandler);
1478 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1479 assertTrue(mGestureHandler.onTouchEvent(event));
1480 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1481 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
1483 event = MotionEvent.obtain(
1484 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
1485 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
1486 assertTrue(mGestureHandler.onTouchEvent(event));
1487 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1489 mGestureHandler.hasTouchEventHandlers(true);
1491 event = MotionEvent.obtain(
1492 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1493 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
1494 assertTrue(mGestureHandler.onTouchEvent(event));
1495 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1497 event = MotionEvent.obtain(
1498 downTime, eventTime + 15, MotionEvent.ACTION_MOVE,
1499 FAKE_COORD_X * 15, FAKE_COORD_Y * 15, 0);
1500 assertTrue(mGestureHandler.onTouchEvent(event));
1501 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1505 * Verify that LONG_TAP is triggered after LongPress followed by an UP.
1510 @Feature({"Gestures"})
1511 public void testGestureLongTap() throws Exception {
1512 final long downTime = SystemClock.uptimeMillis();
1513 final long eventTime = SystemClock.uptimeMillis();
1515 GestureRecordingMotionEventDelegate mockDelegate =
1516 new GestureRecordingMotionEventDelegate();
1517 mGestureHandler = new ContentViewGestureHandler(
1518 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
1519 mLongPressDetector = mGestureHandler.getLongPressDetector();
1521 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1522 assertTrue(mGestureHandler.onTouchEvent(event));
1523 assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
1525 mLongPressDetector.sendLongPressGestureForTest();
1527 assertEquals("A LONG_PRESS gesture should have been sent",
1528 ContentViewGestureHandler.GESTURE_LONG_PRESS,
1529 mockDelegate.mMostRecentGestureEvent.mType);
1531 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 1000);
1532 assertTrue(mGestureHandler.onTouchEvent(event));
1533 assertEquals("A LONG_TAP gesture should have been sent",
1534 ContentViewGestureHandler.GESTURE_LONG_TAP,
1535 mockDelegate.mMostRecentGestureEvent.mType);
1539 * Verify that the touch slop region is removed from the first scroll delta to avoid a jump when
1540 * starting to scroll.
1544 @Feature({"Gestures"})
1545 public void testTouchSlopRemovedFromScroll() throws Exception {
1546 Context context = getInstrumentation().getTargetContext();
1547 final long downTime = SystemClock.uptimeMillis();
1548 final long eventTime = SystemClock.uptimeMillis();
1549 final int scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
1550 final int scrollDelta = 5;
1552 GestureRecordingMotionEventDelegate mockDelegate =
1553 new GestureRecordingMotionEventDelegate();
1554 mGestureHandler = new ContentViewGestureHandler(
1555 context, mockDelegate, mMockZoomManager);
1557 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1558 assertTrue(mGestureHandler.onTouchEvent(event));
1560 event = MotionEvent.obtain(
1561 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1562 FAKE_COORD_X, FAKE_COORD_Y + scaledTouchSlop + scrollDelta, 0);
1563 assertTrue(mGestureHandler.onTouchEvent(event));
1565 assertEquals("We should have started scrolling",
1566 ContentViewGestureHandler.GESTURE_SCROLL_BY,
1567 mockDelegate.mMostRecentGestureEvent.mType);
1569 GestureRecordingMotionEventDelegate.GestureEvent gestureEvent =
1570 mockDelegate.getMostRecentGestureEvent();
1571 assertNotNull(gestureEvent);
1572 Bundle extraParams = gestureEvent.getExtraParams();
1573 assertEquals(0, extraParams.getInt(ContentViewGestureHandler.DISTANCE_X));
1574 assertEquals(-scrollDelta, extraParams.getInt(ContentViewGestureHandler.DISTANCE_Y));
1578 * Verify that touch moves are deferred if they are within the touch slop region
1579 * and the touch sequence is not being consumed.
1583 @Feature({"Gestures"})
1584 public void testTouchMoveWithinTouchSlopDeferred() throws Exception {
1585 Context context = getInstrumentation().getTargetContext();
1586 final long downTime = SystemClock.uptimeMillis();
1587 final long eventTime = SystemClock.uptimeMillis();
1588 final int scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
1589 final int lessThanSlopScrollDelta = scaledTouchSlop / 2;
1590 final int greaterThanSlopScrollDelta = scaledTouchSlop * 2;
1592 mGestureHandler.hasTouchEventHandlers(true);
1594 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1595 assertTrue(mGestureHandler.onTouchEvent(event));
1596 assertEquals("The touch down should have been forwarded",
1597 TouchPoint.TOUCH_EVENT_TYPE_START, mMockMotionEventDelegate.mLastTouchAction);
1598 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1600 event = MotionEvent.obtain(
1601 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1602 FAKE_COORD_X, FAKE_COORD_Y + lessThanSlopScrollDelta, 0);
1603 assertTrue(mGestureHandler.onTouchEvent(event));
1604 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1606 mGestureHandler.confirmTouchEvent(
1607 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
1608 assertEquals("The less-than-slop touch move should not have been forwarded",
1609 TouchPoint.TOUCH_EVENT_TYPE_START, mMockMotionEventDelegate.mLastTouchAction);
1610 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1612 event = MotionEvent.obtain(
1613 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1614 FAKE_COORD_X, FAKE_COORD_Y + greaterThanSlopScrollDelta, 0);
1615 assertTrue(mGestureHandler.onTouchEvent(event));
1616 assertEquals("The touch move should have been forwarded",
1617 TouchPoint.TOUCH_EVENT_TYPE_MOVE, mMockMotionEventDelegate.mLastTouchAction);
1618 mGestureHandler.confirmTouchEvent(
1619 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
1620 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1624 * Verify that touch moves are not deferred even if they are within the touch slop region
1625 * when the touch sequence is being consumed.
1629 @Feature({"Gestures"})
1630 public void testTouchMoveWithinTouchSlopNotDeferredIfJavascriptConsumingGesture()
1632 Context context = getInstrumentation().getTargetContext();
1633 final long downTime = SystemClock.uptimeMillis();
1634 final long eventTime = SystemClock.uptimeMillis();
1635 final int scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
1636 final int lessThanSlopScrollDelta = scaledTouchSlop / 2;
1638 mGestureHandler.hasTouchEventHandlers(true);
1640 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1641 assertTrue(mGestureHandler.onTouchEvent(event));
1642 assertEquals("The touch down should have been forwarded",
1643 TouchPoint.TOUCH_EVENT_TYPE_START, mMockMotionEventDelegate.mLastTouchAction);
1644 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1646 event = MotionEvent.obtain(
1647 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1648 FAKE_COORD_X, FAKE_COORD_Y + lessThanSlopScrollDelta, 0);
1649 assertTrue(mGestureHandler.onTouchEvent(event));
1650 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1652 mGestureHandler.confirmTouchEvent(
1653 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
1654 assertEquals("The less-than-slop touch move should have been forwarded",
1655 TouchPoint.TOUCH_EVENT_TYPE_MOVE, mMockMotionEventDelegate.mLastTouchAction);
1660 * Verify that touch moves are not deferred when the MotionEvent has multiple active pointers.
1664 @Feature({"Gestures"})
1665 public void testTouchMoveNotDeferredWithMultiplePointers()
1667 Context context = getInstrumentation().getTargetContext();
1668 final long downTime = SystemClock.uptimeMillis();
1669 final long eventTime = SystemClock.uptimeMillis();
1670 final int scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
1671 final int lessThanSlopScrollDelta = scaledTouchSlop / 2;
1673 mGestureHandler.hasTouchEventHandlers(true);
1675 final int secondaryCoordX = FAKE_COORD_X + 10 * scaledTouchSlop;
1676 final int secondaryCoordY = FAKE_COORD_Y + 10 * scaledTouchSlop;
1678 PointerProperties pp0 = new PointerProperties();
1680 pp0.toolType = MotionEvent.TOOL_TYPE_FINGER;
1681 PointerProperties pp1 = new PointerProperties();
1683 pp1.toolType = MotionEvent.TOOL_TYPE_FINGER;
1685 PointerCoords pc0 = new PointerCoords();
1686 pc0.x = FAKE_COORD_X;
1687 pc0.y = FAKE_COORD_Y;
1690 PointerCoords pc1 = new PointerCoords();
1691 pc1.x = secondaryCoordX;
1692 pc1.y = secondaryCoordY;
1696 MotionEvent event = MotionEvent.obtain(
1697 eventTime, eventTime, MotionEvent.ACTION_DOWN,
1698 1, new PointerProperties[] { pp0 }, new PointerCoords[] { pc0 },
1699 0, 0, 1.0f, 1.0f, 0, 0, 0, 0);
1700 assertTrue(mGestureHandler.onTouchEvent(event));
1701 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1702 assertEquals("The touch down should have been forwarded",
1703 TouchPoint.TOUCH_EVENT_TYPE_START, mMockMotionEventDelegate.mLastTouchAction);
1705 event = MotionEvent.obtain(
1706 eventTime, eventTime, MotionEvent.ACTION_POINTER_DOWN,
1707 2, new PointerProperties[] { pp0, pp1 }, new PointerCoords[] { pc0, pc1 },
1708 0, 0, 1.0f, 1.0f, 0, 0, 0, 0);
1709 assertTrue(mGestureHandler.onTouchEvent(event));
1710 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1712 mGestureHandler.confirmTouchEvent(
1713 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
1714 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1715 assertEquals("The secondary touch down should have been forwarded",
1716 TouchPoint.TOUCH_EVENT_TYPE_START, mMockMotionEventDelegate.mLastTouchAction);
1718 pc1.x = secondaryCoordX + lessThanSlopScrollDelta;
1719 pc1.y = secondaryCoordY + lessThanSlopScrollDelta;
1721 event = MotionEvent.obtain(
1722 eventTime, eventTime, MotionEvent.ACTION_MOVE,
1723 2, new PointerProperties[] { pp0, pp1 }, new PointerCoords[] { pc0, pc1 },
1724 0, 0, 1.0f, 1.0f, 0, 0, 0, 0);
1725 assertTrue(mGestureHandler.onTouchEvent(event));
1726 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1728 mGestureHandler.confirmTouchEvent(
1729 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
1730 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1731 assertEquals("The secondary touch move should have been forwarded",
1732 TouchPoint.TOUCH_EVENT_TYPE_MOVE, mMockMotionEventDelegate.mLastTouchAction);
1735 private static void sendLastScrollByEvent(ContentViewGestureHandler handler) {
1736 final long downTime = SystemClock.uptimeMillis();
1737 final long eventTime = SystemClock.uptimeMillis();
1738 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1739 assertTrue(handler.onTouchEvent(event));
1740 event = MotionEvent.obtain(
1741 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1742 FAKE_COORD_X, FAKE_COORD_Y + 30, 0);
1743 assertTrue(handler.onTouchEvent(event));
1746 private static void sendLastZoomEvent(
1747 ContentViewGestureHandler handler, MockZoomManager zoomManager) {
1748 zoomManager.pinchOnMoveEvents(handler);
1749 final long downTime = SystemClock.uptimeMillis();
1750 final long eventTime = SystemClock.uptimeMillis();
1751 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1752 assertTrue(handler.onTouchEvent(event));
1753 event = MotionEvent.obtain(
1754 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1755 FAKE_COORD_X, FAKE_COORD_Y + 30, 0);
1756 assertTrue(handler.onTouchEvent(event));
1759 private static void sendLastPinchEvent(ContentViewGestureHandler handler) {
1760 final long downTime = SystemClock.uptimeMillis();
1761 final long eventTime = SystemClock.uptimeMillis();
1762 handler.pinchBegin(downTime, FAKE_COORD_X, FAKE_COORD_Y);
1763 handler.pinchBy(eventTime + 10, FAKE_COORD_X, FAKE_COORD_Y, 2);
1767 * Verify that a DOWN followed shortly by an UP will trigger
1768 * a GESTURE_SINGLE_TAP_UNCONFIRMED event immediately.
1773 @Feature({"Gestures"})
1774 public void testGestureEventsSingleTapUnconfirmed() throws Exception {
1775 final long downTime = SystemClock.uptimeMillis();
1776 final long eventTime = SystemClock.uptimeMillis();
1778 GestureRecordingMotionEventDelegate mockDelegate =
1779 new GestureRecordingMotionEventDelegate();
1780 mGestureHandler = new ContentViewGestureHandler(
1781 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
1783 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1784 assertTrue(mGestureHandler.onTouchEvent(event));
1785 assertEquals("A TAP_DOWN gesture should have been sent",
1786 ContentViewGestureHandler.GESTURE_TAP_DOWN,
1787 mockDelegate.mMostRecentGestureEvent.mType);
1789 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
1790 assertFalse(mGestureHandler.onTouchEvent(event));
1791 assertEquals("A GESTURE_SINGLE_TAP_UNCONFIRMED gesture should have been sent",
1792 ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED,
1793 mockDelegate.mMostRecentGestureEvent.mType);
1795 assertTrue("Should not have confirmed a single tap yet",
1796 mMockListener.mLastSingleTap == null);
1800 * Verify that a tap-ending event will follow a TAP_DOWN event.
1805 @Feature({"Gestures"})
1806 public void testTapDownFollowedByTapEndingEvent() throws Exception {
1807 long downTime = SystemClock.uptimeMillis();
1808 long eventTime = SystemClock.uptimeMillis();
1810 GestureRecordingMotionEventDelegate mockDelegate =
1811 new GestureRecordingMotionEventDelegate();
1812 mGestureHandler = new ContentViewGestureHandler(
1813 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
1815 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1816 assertTrue(mGestureHandler.onTouchEvent(event));
1817 assertEquals(ContentViewGestureHandler.GESTURE_TAP_DOWN,
1818 mockDelegate.mMostRecentGestureEvent.mType);
1819 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1820 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 5);
1821 assertFalse(mGestureHandler.onTouchEvent(event));
1822 assertEquals(ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED,
1823 mockDelegate.mMostRecentGestureEvent.mType);
1824 assertTrue("An unconfirmed tap does not terminate the tap down.",
1825 mGestureHandler.needsTapEndingEventForTesting());
1827 // A confirmed tap is a tap-ending event.
1830 mockDelegate.mGestureTypeList.clear();
1831 mGestureHandler.updateShouldDisableDoubleTap(true);
1832 event = MotionEvent.obtain(
1833 downTime, downTime, MotionEvent.ACTION_DOWN,
1834 FAKE_COORD_X, FAKE_COORD_Y, 0);
1835 assertTrue(mGestureHandler.onTouchEvent(event));
1836 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1837 event = MotionEvent.obtain(
1838 downTime, eventTime + 5, MotionEvent.ACTION_UP,
1839 FAKE_COORD_X, FAKE_COORD_Y, 0);
1840 assertTrue(mGestureHandler.onTouchEvent(event));
1841 assertEquals(ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED,
1842 mockDelegate.mMostRecentGestureEvent.mType);
1843 assertFalse("A confirmed single tap should terminate the tap down.",
1844 mGestureHandler.needsTapEndingEventForTesting());
1846 // A double tap gesture is a tap-ending event.
1849 mockDelegate.mGestureTypeList.clear();
1850 mGestureHandler.updateShouldDisableDoubleTap(false);
1851 event = MotionEvent.obtain(
1852 downTime, downTime, MotionEvent.ACTION_DOWN,
1853 FAKE_COORD_X, FAKE_COORD_Y, 0);
1854 assertTrue(mGestureHandler.onTouchEvent(event));
1855 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1856 event = MotionEvent.obtain(
1857 downTime, eventTime + 5, MotionEvent.ACTION_UP,
1858 FAKE_COORD_X, FAKE_COORD_Y, 0);
1859 event = MotionEvent.obtain(
1860 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
1861 FAKE_COORD_X, FAKE_COORD_Y, 0);
1862 assertTrue(mGestureHandler.onTouchEvent(event));
1863 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1864 event = MotionEvent.obtain(
1865 eventTime + 10, eventTime + 15, MotionEvent.ACTION_UP,
1866 FAKE_COORD_X, FAKE_COORD_Y, 0);
1867 assertTrue(mGestureHandler.onTouchEvent(event));
1868 assertEquals(ContentViewGestureHandler.GESTURE_DOUBLE_TAP,
1869 mockDelegate.mMostRecentGestureEvent.mType);
1870 assertFalse("A double tap should terminate the tap down.",
1871 mGestureHandler.needsTapEndingEventForTesting());
1873 // A double tap drag gesture will trigger a tap-ending event.
1876 mockDelegate.mGestureTypeList.clear();
1877 mGestureHandler.updateShouldDisableDoubleTap(false);
1878 event = MotionEvent.obtain(
1879 downTime, downTime, MotionEvent.ACTION_DOWN,
1880 FAKE_COORD_X, FAKE_COORD_Y, 0);
1881 assertTrue(mGestureHandler.onTouchEvent(event));
1882 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1883 event = MotionEvent.obtain(
1884 downTime, eventTime + 5, MotionEvent.ACTION_UP,
1885 FAKE_COORD_X, FAKE_COORD_Y, 0);
1886 event = MotionEvent.obtain(
1887 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
1888 FAKE_COORD_X, FAKE_COORD_Y, 0);
1889 assertTrue(mGestureHandler.onTouchEvent(event));
1890 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1891 event = MotionEvent.obtain(
1892 eventTime + 10, eventTime + 15, MotionEvent.ACTION_MOVE,
1893 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1894 assertTrue(mGestureHandler.onTouchEvent(event));
1895 assertFalse("A double tap drag should terminate the tap down.",
1896 mGestureHandler.needsTapEndingEventForTesting());
1897 assertTrue(mockDelegate.mGestureTypeList.contains(
1898 ContentViewGestureHandler.GESTURE_SCROLL_START));
1899 assertTrue(mockDelegate.mGestureTypeList.contains(
1900 ContentViewGestureHandler.GESTURE_TAP_CANCEL));
1901 event = MotionEvent.obtain(
1902 eventTime + 10, eventTime + 20, MotionEvent.ACTION_UP,
1903 FAKE_COORD_X, FAKE_COORD_Y, 0);
1904 assertTrue(mGestureHandler.onTouchEvent(event));
1905 assertFalse(mGestureHandler.needsTapEndingEventForTesting());
1907 // A scroll event will trigger a tap-ending (cancel) event.
1910 mockDelegate.mGestureTypeList.clear();
1911 event = MotionEvent.obtain(
1912 downTime, downTime, MotionEvent.ACTION_DOWN,
1913 FAKE_COORD_X, FAKE_COORD_Y, 0);
1914 assertTrue(mGestureHandler.onTouchEvent(event));
1915 assertTrue(mGestureHandler.needsTapEndingEventForTesting());
1916 event = MotionEvent.obtain(
1917 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
1918 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
1919 assertTrue(mGestureHandler.onTouchEvent(event));
1920 assertTrue(mockDelegate.mGestureTypeList.contains(
1921 ContentViewGestureHandler.GESTURE_SCROLL_START));
1922 assertTrue(mockDelegate.mGestureTypeList.contains(
1923 ContentViewGestureHandler.GESTURE_TAP_CANCEL));
1924 assertFalse("A scroll should terminate the tap down.",
1925 mGestureHandler.needsTapEndingEventForTesting());
1926 assertFalse(mGestureHandler.needsTapEndingEventForTesting());
1930 * Verify that touch move events are properly coalesced.
1934 @Feature({"Gestures"})
1935 public void testTouchMoveCoalescing() throws Exception {
1936 final long downTime = SystemClock.uptimeMillis();
1937 final long eventTime = SystemClock.uptimeMillis();
1939 mGestureHandler.hasTouchEventHandlers(true);
1941 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
1942 assertTrue(mGestureHandler.onTouchEvent(event));
1943 mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
1944 assertEquals(TouchPoint.TOUCH_EVENT_TYPE_START, mMockMotionEventDelegate.mLastTouchAction);
1946 event = MotionEvent.obtain(
1947 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
1948 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
1949 assertTrue(mGestureHandler.onTouchEvent(event));
1950 assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
1951 assertEquals("Initial move events should offered to javascript and added to the queue",
1952 1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1953 assertEquals(TouchPoint.TOUCH_EVENT_TYPE_MOVE, mMockMotionEventDelegate.mLastTouchAction);
1955 event = MotionEvent.obtain(
1956 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
1957 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
1958 assertTrue(mGestureHandler.onTouchEvent(event));
1959 assertEquals("Move events already sent to javascript should not be coalesced",
1960 2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1962 event = MotionEvent.obtain(
1963 downTime, eventTime + 15, MotionEvent.ACTION_MOVE,
1964 FAKE_COORD_X * 15, FAKE_COORD_Y * 15, 0);
1965 assertTrue(mGestureHandler.onTouchEvent(event));
1966 assertEquals("Similar pending move events should be coalesced",
1967 2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1969 PointerProperties pp1 = new PointerProperties();
1971 pp1.toolType = MotionEvent.TOOL_TYPE_FINGER;
1972 PointerProperties pp2 = new PointerProperties();
1974 pp2.toolType = MotionEvent.TOOL_TYPE_FINGER;
1975 PointerProperties[] properties = new PointerProperties[] { pp1, pp2 };
1977 PointerCoords pc1 = new PointerCoords();
1978 pc1.x = FAKE_COORD_X * 10;
1979 pc1.y = FAKE_COORD_Y * 10;
1982 PointerCoords pc2 = new PointerCoords();
1983 pc2.x = FAKE_COORD_X * 15;
1984 pc2.y = FAKE_COORD_Y * 15;
1987 PointerCoords[] coords = new PointerCoords[] { pc1, pc2 };
1989 event = MotionEvent.obtain(
1990 downTime, eventTime + 20, MotionEvent.ACTION_MOVE,
1991 2, properties, coords, 0, 0, 1.0f, 1.0f, 0, 0, 0, 0);
1992 assertTrue(mGestureHandler.onTouchEvent(event));
1993 assertEquals("Move events with different pointer counts should not be coalesced",
1994 3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
1996 event = MotionEvent.obtain(
1997 downTime, eventTime + 25, MotionEvent.ACTION_MOVE,
1998 2, properties, coords, 0, 0, 1.0f, 1.0f, 0, 0, 0, 0);
1999 assertTrue(mGestureHandler.onTouchEvent(event));
2000 assertEquals("Move events with similar pointer counts should be coalesced",
2001 3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2003 event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
2004 assertTrue(mGestureHandler.onTouchEvent(event));
2005 assertEquals("Move events should not be coalesced with other events",
2006 4, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2010 * Verify that synchronous confirmTouchEvent() calls made from the MotionEventDelegate behave
2015 @Feature({"Gestures"})
2016 public void testSynchronousConfirmTouchEvent() throws Exception {
2017 final long downTime = SystemClock.uptimeMillis();
2018 final long eventTime = SystemClock.uptimeMillis();
2020 mGestureHandler.hasTouchEventHandlers(true);
2022 mMockMotionEventDelegate.disableSynchronousConfirmTouchEvent();
2024 // Queue an asynchronously handled event.
2025 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
2026 assertTrue(mGestureHandler.onTouchEvent(event));
2027 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2029 // Queue another event; this will remain in the queue until the first event is confirmed.
2030 event = MotionEvent.obtain(
2031 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
2032 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
2033 assertTrue(mGestureHandler.onTouchEvent(event));
2034 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2036 // Enable synchronous event confirmation upon dispatch.
2037 mMockMotionEventDelegate.enableSynchronousConfirmTouchEvent(
2038 mGestureHandler, ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
2040 // Confirm the original event; this should dispatch the second event and confirm it
2042 mGestureHandler.confirmTouchEvent(
2043 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
2044 assertTrue(mGestureHandler.onTouchEvent(event));
2045 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2046 assertEquals(TouchPoint.TOUCH_EVENT_TYPE_MOVE, mMockMotionEventDelegate.mLastTouchAction);
2048 // Adding events to any empty queue will trigger synchronous dispatch and confirmation.
2049 event = MotionEvent.obtain(
2050 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
2051 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
2052 assertTrue(mGestureHandler.onTouchEvent(event));
2053 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2057 * Verify that no double tap gestures are created if the gesture handler is
2058 * told to disable double tap gesture detection (according to the logic in
2059 * ContentViewCore.onRenderCoordinatesUpdated).
2063 @Feature({"Gestures"})
2064 public void testNoDoubleTapWhenDoubleTapDisabled() throws Exception {
2065 final long downTime = SystemClock.uptimeMillis();
2066 final long eventTime = SystemClock.uptimeMillis();
2068 GestureRecordingMotionEventDelegate mockDelegate =
2069 new GestureRecordingMotionEventDelegate();
2070 mGestureHandler = new ContentViewGestureHandler(
2071 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
2072 mGestureHandler.updateShouldDisableDoubleTap(true);
2074 MotionEvent event = MotionEvent.obtain(
2075 downTime, downTime, MotionEvent.ACTION_DOWN,
2076 FAKE_COORD_X, FAKE_COORD_Y, 0);
2077 assertTrue(mGestureHandler.onTouchEvent(event));
2078 assertEquals("Only GESTURE_TAP_DOWN should have been sent",
2079 1, mockDelegate.mGestureTypeList.size());
2081 event = MotionEvent.obtain(
2082 downTime, eventTime + 5, MotionEvent.ACTION_UP,
2083 FAKE_COORD_X, FAKE_COORD_Y, 0);
2084 assertTrue(mGestureHandler.onTouchEvent(event));
2085 assertEquals("A GESTURE_SINGLE_TAP_CONFIRMED event should have been sent",
2086 ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED,
2087 mockDelegate.mMostRecentGestureEvent.mType);
2088 assertEquals("Only GESTURE_TAP_DOWN and GESTURE_SINGLE_TAP_CONFIRMED " +
2089 "should have been sent",
2090 2, mockDelegate.mGestureTypeList.size());
2092 event = MotionEvent.obtain(
2093 eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN,
2094 FAKE_COORD_X, FAKE_COORD_Y, 0);
2095 assertTrue(mGestureHandler.onTouchEvent(event));
2096 assertEquals("Only GESTURE_TAP_DOWN, " +
2097 "GESTURE_SINGLE_TAP_CONFIRMED and " +
2098 "GESTURE_TAP_DOWN should have been sent",
2099 3, mockDelegate.mGestureTypeList.size());
2101 event = MotionEvent.obtain(
2102 eventTime + 10, eventTime + 15, MotionEvent.ACTION_UP,
2103 FAKE_COORD_X, FAKE_COORD_Y, 0);
2104 assertTrue(mGestureHandler.onTouchEvent(event));
2105 assertEquals("A double tap should not have occurred",
2106 ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED,
2107 mockDelegate.mMostRecentGestureEvent.mType);
2108 assertEquals("Only GESTURE_TAP_DOWN, " +
2109 "GESTURE_SINGLE_TAP_CONFIRMED, " +
2110 "GESTURE_TAP_DOWN and " +
2111 "GESTURE_SINGLE_TAP_CONFIRMED should have been sent",
2112 4, mockDelegate.mGestureTypeList.size());
2116 * Verify that double tap drag zoom feature is not invoked when the gesture
2117 * handler is told to disable double tap gesture detection (according to the
2118 * logic in ContentViewCore.onRenderCoordinatesUpdated).
2119 * The second tap sequence should be treated just as the first would be.
2123 @Feature({"Gestures"})
2124 public void testNoDoubleTapDragZoomWhenDoubleTapDisabled() throws Exception {
2125 final long downTime1 = SystemClock.uptimeMillis();
2126 final long downTime2 = downTime1 + 100;
2128 GestureRecordingMotionEventDelegate mockDelegate =
2129 new GestureRecordingMotionEventDelegate();
2130 mGestureHandler = new ContentViewGestureHandler(
2131 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
2132 mGestureHandler.updateShouldDisableDoubleTap(true);
2134 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
2135 assertTrue(mGestureHandler.onTouchEvent(event));
2137 event = MotionEvent.obtain(
2138 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
2139 FAKE_COORD_X, FAKE_COORD_Y, 0);
2140 mGestureHandler.onTouchEvent(event);
2142 event = MotionEvent.obtain(
2143 downTime2, downTime2, MotionEvent.ACTION_DOWN,
2144 FAKE_COORD_X, FAKE_COORD_Y, 0);
2145 assertTrue(mGestureHandler.onTouchEvent(event));
2147 event = MotionEvent.obtain(
2148 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
2149 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
2151 // The move should become a scroll, as double tap and drag to zoom is
2153 assertTrue(mGestureHandler.onTouchEvent(event));
2154 assertTrue("GESTURE_SCROLL_START should have been sent",
2155 mockDelegate.mGestureTypeList.contains(
2156 ContentViewGestureHandler.GESTURE_SCROLL_START));
2157 assertFalse("No GESTURE_PINCH_BEGIN should have been sent",
2158 mockDelegate.mGestureTypeList.contains(
2159 ContentViewGestureHandler.GESTURE_PINCH_BEGIN));
2161 event = MotionEvent.obtain(
2162 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
2163 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
2164 assertTrue(mGestureHandler.onTouchEvent(event));
2165 assertEquals("GESTURE_SCROLL_BY should have been sent",
2166 ContentViewGestureHandler.GESTURE_SCROLL_BY,
2167 mockDelegate.mMostRecentGestureEvent.mType);
2168 assertEquals("GESTURE_SCROLL_BY should have been sent",
2169 event.getEventTime(),
2170 mockDelegate.mMostRecentGestureEvent.getTimeMs());
2171 assertTrue("No GESTURE_PINCH_BY should have been sent",
2172 ContentViewGestureHandler.GESTURE_PINCH_BY !=
2173 mockDelegate.mMostRecentGestureEvent.mType);
2175 event = MotionEvent.obtain(
2176 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
2177 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
2178 assertTrue(mGestureHandler.onTouchEvent(event));
2179 assertFalse("No GESTURE_PINCH_END should have been sent",
2180 mockDelegate.mGestureTypeList.contains(
2181 ContentViewGestureHandler.GESTURE_PINCH_END));
2185 * Verify that setting a fixed page scale (or a mobile viewport) during a double
2186 * tap drag zoom disables double tap detection after the gesture has ended.
2190 @Feature({"Gestures"})
2191 public void testFixedPageScaleDuringDoubleTapDragZoom() throws Exception {
2192 long downTime1 = SystemClock.uptimeMillis();
2193 long downTime2 = downTime1 + 100;
2195 GestureRecordingMotionEventDelegate mockDelegate =
2196 new GestureRecordingMotionEventDelegate();
2197 mGestureHandler = new ContentViewGestureHandler(
2198 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
2199 mLongPressDetector = new LongPressDetector(
2200 getInstrumentation().getTargetContext(), mGestureHandler);
2202 // Start a double-tap drag gesture.
2203 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
2204 assertTrue(mGestureHandler.onTouchEvent(event));
2205 mGestureHandler.sendShowPressedStateGestureForTesting();
2206 event = MotionEvent.obtain(
2207 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
2208 FAKE_COORD_X, FAKE_COORD_Y, 0);
2209 mGestureHandler.onTouchEvent(event);
2210 event = MotionEvent.obtain(
2211 downTime2, downTime2, MotionEvent.ACTION_DOWN,
2212 FAKE_COORD_X, FAKE_COORD_Y, 0);
2213 assertTrue(mGestureHandler.onTouchEvent(event));
2214 event = MotionEvent.obtain(
2215 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
2216 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
2217 assertTrue(mGestureHandler.onTouchEvent(event));
2218 assertTrue("GESTURE_SCROLL_START should have been sent",
2219 mockDelegate.mGestureTypeList.contains(
2220 ContentViewGestureHandler.GESTURE_SCROLL_START));
2221 assertEquals("GESTURE_PINCH_BEGIN should have been sent",
2222 ContentViewGestureHandler.GESTURE_PINCH_BEGIN,
2223 mockDelegate.mMostRecentGestureEvent.mType);
2225 // Simulate setting a fixed page scale (or a mobile viewport);
2226 // this should not disrupt the current double-tap gesture.
2227 mGestureHandler.updateShouldDisableDoubleTap(true);
2229 // Double tap zoom updates should continue.
2230 event = MotionEvent.obtain(
2231 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
2232 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
2233 assertTrue(mGestureHandler.onTouchEvent(event));
2234 assertTrue("GESTURE_SCROLL_BY should have been sent",
2235 mockDelegate.mGestureTypeList.contains(
2236 ContentViewGestureHandler.GESTURE_SCROLL_BY));
2237 assertEquals("GESTURE_PINCH_BY should have been sent",
2238 ContentViewGestureHandler.GESTURE_PINCH_BY,
2239 mockDelegate.mMostRecentGestureEvent.mType);
2240 event = MotionEvent.obtain(
2241 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
2242 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
2243 assertTrue(mGestureHandler.onTouchEvent(event));
2244 assertTrue("GESTURE_PINCH_END should have been sent",
2245 mockDelegate.mGestureTypeList.contains(
2246 ContentViewGestureHandler.GESTURE_PINCH_END));
2247 assertEquals("GESTURE_SCROLL_END should have been sent",
2248 ContentViewGestureHandler.GESTURE_SCROLL_END,
2249 mockDelegate.mMostRecentGestureEvent.mType);
2251 // The double-tap gesture has finished, but the page scale is fixed.
2252 // The same event sequence should not generate any double tap getsures.
2253 mockDelegate.mGestureTypeList.clear();
2257 // Start a double-tap drag gesture.
2258 event = motionEvent(MotionEvent.ACTION_DOWN, downTime1, downTime1);
2259 assertTrue(mGestureHandler.onTouchEvent(event));
2260 event = MotionEvent.obtain(
2261 downTime1, downTime1 + 5, MotionEvent.ACTION_UP,
2262 FAKE_COORD_X, FAKE_COORD_Y, 0);
2263 mGestureHandler.onTouchEvent(event);
2264 event = MotionEvent.obtain(
2265 downTime2, downTime2, MotionEvent.ACTION_DOWN,
2266 FAKE_COORD_X, FAKE_COORD_Y, 0);
2267 assertTrue(mGestureHandler.onTouchEvent(event));
2268 event = MotionEvent.obtain(
2269 downTime2, downTime2 + 5, MotionEvent.ACTION_MOVE,
2270 FAKE_COORD_X, FAKE_COORD_Y + 100, 0);
2271 assertTrue(mGestureHandler.onTouchEvent(event));
2272 assertTrue("GESTURE_SCROLL_START should have been sent",
2273 mockDelegate.mGestureTypeList.contains(
2274 ContentViewGestureHandler.GESTURE_SCROLL_START));
2275 assertFalse("GESTURE_PINCH_BEGIN should not have been sent",
2276 mockDelegate.mGestureTypeList.contains(
2277 ContentViewGestureHandler.GESTURE_PINCH_BEGIN));
2279 // Double tap zoom updates should not be sent.
2280 // Instead, the second tap drag becomes a scroll gesture sequence.
2281 event = MotionEvent.obtain(
2282 downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
2283 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
2284 assertTrue(mGestureHandler.onTouchEvent(event));
2285 assertTrue("GESTURE_SCROLL_BY should have been sent",
2286 mockDelegate.mGestureTypeList.contains(
2287 ContentViewGestureHandler.GESTURE_SCROLL_BY));
2288 assertFalse("GESTURE_PINCH_BY should not have been sent",
2289 mockDelegate.mGestureTypeList.contains(
2290 ContentViewGestureHandler.GESTURE_PINCH_BY));
2291 event = MotionEvent.obtain(
2292 downTime2, downTime2 + 15, MotionEvent.ACTION_UP,
2293 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
2294 assertTrue(mGestureHandler.onTouchEvent(event));
2295 assertFalse("GESTURE_PINCH_END should not have been sent",
2296 mockDelegate.mGestureTypeList.contains(
2297 ContentViewGestureHandler.GESTURE_PINCH_END));
2301 * Verify that a secondary pointer press with no consumer does not interfere
2302 * with Javascript touch handling.
2307 @Feature({"Gestures"})
2308 public void testSecondaryPointerWithNoConsumer() throws Exception {
2309 final long downTime = SystemClock.uptimeMillis();
2310 final long eventTime = SystemClock.uptimeMillis();
2312 mGestureHandler.hasTouchEventHandlers(true);
2314 // Queue a primary pointer press, a secondary pointer press and release,
2315 // and a primary pointer move.
2316 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
2317 assertTrue(mGestureHandler.onTouchEvent(event));
2318 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2320 event = motionEvent(MotionEvent.ACTION_POINTER_DOWN, downTime, eventTime);
2321 assertTrue(mGestureHandler.onTouchEvent(event));
2322 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2324 event = motionEvent(MotionEvent.ACTION_POINTER_UP, downTime, eventTime + 10);
2325 assertTrue(mGestureHandler.onTouchEvent(event));
2326 assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2328 event = MotionEvent.obtain(
2329 downTime, eventTime + 15, MotionEvent.ACTION_MOVE,
2330 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
2331 assertTrue(mGestureHandler.onTouchEvent(event));
2332 assertEquals(4, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2334 // Simulate preventDefault from Javascript, forcing all touch events to Javascript
2335 // for the current sequence.
2336 mGestureHandler.confirmTouchEvent(
2337 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
2338 assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2340 mGestureHandler.confirmTouchEvent(
2341 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
2342 assertEquals("Even if the secondary pointer has no consumer, continue sending events",
2343 2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2345 mGestureHandler.confirmTouchEvent(
2346 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
2347 assertEquals("Even if the secondary pointer has no consumer, continue sending events",
2348 1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2350 mGestureHandler.confirmTouchEvent(
2351 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
2352 assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2354 assertEquals("No gestures should result from the Javascript-consumed sequence",
2355 0, mMockMotionEventDelegate.mTotalSentGestureCount);
2359 * Verify that multiple touch sequences in the queue are handled properly when
2360 * the Javascript response is different for each.
2365 @Feature({"Gestures"})
2366 public void testMultiplyEnqueuedTouches() throws Exception {
2367 final long downTime = SystemClock.uptimeMillis();
2368 final long eventTime = SystemClock.uptimeMillis();
2370 mGestureHandler.hasTouchEventHandlers(true);
2371 mGestureHandler.updateDoubleTapSupport(false);
2373 // Queue a tap sequence.
2374 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
2375 assertTrue(mGestureHandler.onTouchEvent(event));
2376 assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2378 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 5);
2379 assertTrue(mGestureHandler.onTouchEvent(event));
2380 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2382 // Queue a scroll sequence.
2383 event = motionEvent(MotionEvent.ACTION_DOWN, downTime + 10, downTime + 10);
2384 assertTrue(mGestureHandler.onTouchEvent(event));
2385 assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2387 event = MotionEvent.obtain(
2388 downTime + 10, eventTime + 15, MotionEvent.ACTION_MOVE,
2389 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
2390 assertTrue(mGestureHandler.onTouchEvent(event));
2391 assertFalse(mGestureHandler.isNativeScrolling());
2392 assertEquals(4, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2394 event = motionEvent(MotionEvent.ACTION_UP, downTime + 10, downTime + 20);
2395 assertTrue(mGestureHandler.onTouchEvent(event));
2396 assertEquals(5, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2398 // Consume the first gesture.
2399 mGestureHandler.confirmTouchEvent(
2400 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
2401 assertEquals(4, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2403 mGestureHandler.confirmTouchEvent(
2404 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
2405 assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2407 // Don't consume the second gesture; it should be fed to the gesture detector.
2408 mGestureHandler.confirmTouchEvent(
2409 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
2410 assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2411 assertEquals("The down touch event should have been sent to the gesture detector",
2412 MotionEvent.ACTION_DOWN, mMockGestureDetector.mLastEvent.getActionMasked());
2413 assertFalse(mGestureHandler.isNativeScrolling());
2415 mGestureHandler.confirmTouchEvent(
2416 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
2417 assertEquals("The move touch event should have been sent to the gesture detector",
2418 MotionEvent.ACTION_MOVE, mMockGestureDetector.mLastEvent.getActionMasked());
2422 * Verify that only complete gestures are forwarded to Javascript if we receive
2423 * a touch handler notification.
2427 @Feature({"Gestures"})
2428 public void testOnlyCompleteGesturesForwardedToTouchHandler() throws Exception {
2429 final long downTime = SystemClock.uptimeMillis();
2430 final long eventTime = SystemClock.uptimeMillis();
2432 mGestureHandler.hasTouchEventHandlers(false);
2434 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
2435 mGestureHandler.onTouchEvent(event);
2436 assertEquals("Initial down events should not be sent to Javascript without a touch handler",
2437 0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2438 assertTrue("Should have a pending gesture", mMockGestureDetector.mLastEvent != null);
2439 mMockGestureDetector.mLastEvent = null;
2441 mGestureHandler.hasTouchEventHandlers(true);
2443 event = MotionEvent.obtain(
2444 downTime, eventTime + 5, MotionEvent.ACTION_MOVE,
2445 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
2446 mGestureHandler.onTouchEvent(event);
2447 assertEquals("A move event should only be offered to javascript if the down was offered",
2448 0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2449 assertTrue("Should have a pending gesture", mMockGestureDetector.mLastEvent != null);
2451 event = motionEvent(MotionEvent.ACTION_POINTER_DOWN, downTime, eventTime + 10);
2452 mGestureHandler.onTouchEvent(event);
2453 assertEquals("A pointer event should only be offered to Javascript if the down was offered",
2454 0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2456 // Ensure that redundant notifications have no effect.
2457 mGestureHandler.hasTouchEventHandlers(true);
2459 event = motionEvent(MotionEvent.ACTION_POINTER_UP, downTime, eventTime + 15);
2460 mGestureHandler.onTouchEvent(event);
2461 assertEquals("A pointer event should only be offered to Javascript if the down was offered",
2462 0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2464 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 20);
2465 mGestureHandler.onTouchEvent(event);
2466 assertEquals("A pointer event should only be offered to Javascript if the down was offered",
2467 0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2469 event = motionEvent(MotionEvent.ACTION_DOWN, downTime + 25, downTime + 25);
2470 mGestureHandler.onTouchEvent(event);
2471 assertEquals("A down event should be offered to Javascript with a registered touch handler",
2472 1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
2476 * Verify that no timeout-based gestures are triggered after a touch event
2477 * is consumed. In particular, LONG_PRESS and SHOW_PRESS should not fire
2478 * if TouchStart went unconsumed, but subsequent TouchMoves are consumed.
2483 @Feature({"Gestures"})
2484 public void testNoTimeoutGestureAfterTouchConsumed() throws Exception {
2485 getInstrumentation().runOnMainSync(new Runnable() {
2490 final long downTime = SystemClock.uptimeMillis();
2491 final long eventTime = SystemClock.uptimeMillis();
2493 mGestureHandler.hasTouchEventHandlers(true);
2495 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime);
2496 assertTrue(mGestureHandler.onTouchEvent(event));
2497 mGestureHandler.confirmTouchEvent(
2498 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
2499 assertTrue("Should have a pending LONG_PRESS",
2500 mLongPressDetector.hasPendingMessage());
2502 event = MotionEvent.obtain(
2503 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
2504 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
2505 assertTrue(mGestureHandler.onTouchEvent(event));
2506 mGestureHandler.confirmTouchEvent(
2507 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
2508 assertFalse("Should not have a pending LONG_PRESS",
2509 mLongPressDetector.hasPendingMessage());
2512 assertFalse(mMockListener.mShowPressCalled.await(
2513 ScalableTimeout.ScaleTimeout(ViewConfiguration.getTapTimeout() + 10),
2514 TimeUnit.MILLISECONDS));
2515 assertFalse(mMockListener.mLongPressCalled.await(
2516 ScalableTimeout.ScaleTimeout(ViewConfiguration.getLongPressTimeout() + 10),
2517 TimeUnit.MILLISECONDS));
2521 * Verify that a TAP_DOWN will be followed by a TAP_CANCEL if the first
2522 * touch is unconsumed, but the subsequent touch is consumed.
2527 @Feature({"Gestures"})
2528 public void testTapCancelledAfterTouchConsumed() throws Exception {
2529 final long downTime = SystemClock.uptimeMillis();
2530 final long eventTime = SystemClock.uptimeMillis();
2532 GestureRecordingMotionEventDelegate mockDelegate =
2533 new GestureRecordingMotionEventDelegate();
2534 mGestureHandler = new ContentViewGestureHandler(
2535 getInstrumentation().getTargetContext(), mockDelegate, mMockZoomManager);
2536 mGestureHandler.hasTouchEventHandlers(true);
2538 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
2539 assertTrue(mGestureHandler.onTouchEvent(event));
2540 mGestureHandler.confirmTouchEvent(
2541 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
2542 assertEquals("A TAP_DOWN gesture should have been sent",
2543 ContentViewGestureHandler.GESTURE_TAP_DOWN,
2544 mockDelegate.mMostRecentGestureEvent.mType);
2546 event = MotionEvent.obtain(
2547 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
2548 FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
2549 assertTrue(mGestureHandler.onTouchEvent(event));
2550 mGestureHandler.confirmTouchEvent(
2551 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
2552 assertEquals("A TAP_CANCEL gesture should have been sent",
2553 ContentViewGestureHandler.GESTURE_TAP_CANCEL,
2554 mockDelegate.mMostRecentGestureEvent.mType);
2556 event = MotionEvent.obtain(
2557 downTime, eventTime + 15, MotionEvent.ACTION_MOVE,
2558 FAKE_COORD_X, FAKE_COORD_Y + 400, 0);
2559 assertTrue(mGestureHandler.onTouchEvent(event));
2560 mGestureHandler.confirmTouchEvent(
2561 ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
2562 assertEquals("No further gestures should be sent",
2563 ContentViewGestureHandler.GESTURE_TAP_CANCEL,
2564 mockDelegate.mMostRecentGestureEvent.mType);