/**
   * Verify that LONG_TAP is triggered after LongPress followed by an UP.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testGestureLongTap() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    GestureRecordingMotionEventDelegate mockDelegate = new GestureRecordingMotionEventDelegate();
    mGestureHandler =
        new ContentViewGestureHandler(
            getInstrumentation().getTargetContext(),
            mockDelegate,
            new MockZoomManager(getInstrumentation().getTargetContext(), null));
    mLongPressDetector = mGestureHandler.getLongPressDetector();

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertNotNull(mockDelegate.getMostRecentGestureEvent());
    assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    mLongPressDetector.sendLongPressGestureForTest();

    assertEquals(
        "A LONG_PRESS gesture should have been sent",
        ContentViewGestureHandler.GESTURE_LONG_PRESS,
        mockDelegate.mMostRecentGestureEvent.mType);

    event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 1000);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(
        "A LONG_TAP gesture should have been sent",
        ContentViewGestureHandler.GESTURE_LONG_TAP,
        mockDelegate.mMostRecentGestureEvent.mType);
  }
  /**
   * Verify that a recent show pressed state gesture is canceled when double tap occurs.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testShowPressCancelOnDoubleTap() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    GestureRecordingMotionEventDelegate mockDelegate = new GestureRecordingMotionEventDelegate();
    mGestureHandler =
        new ContentViewGestureHandler(
            getInstrumentation().getTargetContext(),
            mockDelegate,
            new MockZoomManager(getInstrumentation().getTargetContext(), null));
    mLongPressDetector =
        new LongPressDetector(getInstrumentation().getTargetContext(), mGestureHandler);

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    assertTrue(mGestureHandler.onTouchEvent(event));
    assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    mGestureHandler.sendShowPressedStateGestureForTesting();

    assertEquals(
        "A show pressed state event should have been sent",
        ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
        mockDelegate.mMostRecentGestureEvent.mType);
    assertEquals(
        "Only flingCancel and showPressedState should have been sent",
        2,
        mockDelegate.mGestureTypeList.size());

    event =
        MotionEvent.obtain(
            downTime, eventTime + 5, MotionEvent.ACTION_UP, FAKE_COORD_X, FAKE_COORD_Y, 0);
    mGestureHandler.onTouchEvent(event);
    assertEquals("The first tap should not do anything", 2, mockDelegate.mGestureTypeList.size());

    event =
        MotionEvent.obtain(
            eventTime + 10, eventTime + 10, MotionEvent.ACTION_DOWN, FAKE_COORD_X, FAKE_COORD_Y, 0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(
        "A double tap should have occurred",
        ContentViewGestureHandler.GESTURE_DOUBLE_TAP,
        mockDelegate.mMostRecentGestureEvent.mType);
    assertTrue(
        "A show press cancel event should have been sent",
        mockDelegate.mGestureTypeList.contains(
            ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL));
    assertEquals(
        "Only flingCancel, showPressedState,"
            + "flingCancel, showPressCancel and doubleTap should have been sent",
        5,
        mockDelegate.mGestureTypeList.size());
  }
  /**
   * Verify that certain gesture events are sent with the "last for this vsync" flag set.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testFinalInputEventsForVSyncInterval() throws Exception {
    Context context = getInstrumentation().getTargetContext();
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();
    final boolean inputEventsDeliveredAtVSync =
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;

    GestureRecordingMotionEventDelegate mockDelegate = new GestureRecordingMotionEventDelegate();
    mGestureHandler =
        new ContentViewGestureHandler(context, mockDelegate, new MockZoomManager(context, null));

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
    assertTrue(mGestureHandler.onTouchEvent(event));
    event =
        MotionEvent.obtain(
            downTime, eventTime + 10, MotionEvent.ACTION_MOVE, FAKE_COORD_X, FAKE_COORD_Y + 30, 0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(
        "We should have started scrolling",
        ContentViewGestureHandler.GESTURE_SCROLL_BY,
        mockDelegate.mMostRecentGestureEvent.mType);

    if (inputEventsDeliveredAtVSync) {
      assertEquals(
          "Gesture should be last for vsync",
          true,
          mockDelegate.mostRecentGestureEventForLastForVSync());
    } else {
      assertEquals(
          "Gesture should not be last for vsync",
          false,
          mockDelegate.mostRecentGestureEventForLastForVSync());
    }

    mGestureHandler.pinchBegin(downTime, FAKE_COORD_X, FAKE_COORD_Y);
    mGestureHandler.pinchBy(eventTime + 10, FAKE_COORD_X, FAKE_COORD_Y, 2);
    assertEquals(
        "We should have started pinch-zooming",
        ContentViewGestureHandler.GESTURE_PINCH_BY,
        mockDelegate.mMostRecentGestureEvent.mType);

    if (inputEventsDeliveredAtVSync) {
      assertEquals(
          "Gesture should be last for vsync",
          true,
          mockDelegate.mostRecentGestureEventForLastForVSync());
    } else {
      assertEquals(
          "Gesture should not be last for vsync",
          false,
          mockDelegate.mostRecentGestureEventForLastForVSync());
    }
  }
  /**
   * Generate a scroll gesture and verify that the resulting scroll motion event has both absolute
   * and relative position information.
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testScrollUpdateCoordinates() {
    final int deltaX = 16;
    final int deltaY = 84;
    final long downTime = SystemClock.uptimeMillis();

    GestureRecordingMotionEventDelegate delegate = new GestureRecordingMotionEventDelegate();
    ContentViewGestureHandler gestureHandler =
        new ContentViewGestureHandler(
            getInstrumentation().getTargetContext(),
            delegate,
            new MockZoomManager(getInstrumentation().getTargetContext(), null));
    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
    assertTrue(gestureHandler.onTouchEvent(event));
    assertNotNull(delegate.getMostRecentGestureEvent());

    // Move twice, because the first move gesture is discarded.
    event =
        MotionEvent.obtain(
            downTime,
            downTime + 5,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X - deltaX / 2,
            FAKE_COORD_Y - deltaY / 2,
            0);
    assertTrue(gestureHandler.onTouchEvent(event));

    event =
        MotionEvent.obtain(
            downTime,
            downTime + 10,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X - deltaX,
            FAKE_COORD_Y - deltaY,
            0);
    assertTrue(gestureHandler.onTouchEvent(event));

    // Make sure the reported gesture event has all the expected data.
    GestureRecordingMotionEventDelegate.GestureEvent gestureEvent =
        delegate.getMostRecentGestureEvent();
    assertNotNull(gestureEvent);
    assertEquals(ContentViewGestureHandler.GESTURE_SCROLL_BY, gestureEvent.getType());
    assertEquals(downTime + 10, gestureEvent.getTimeMs());
    assertEquals(FAKE_COORD_X - deltaX, gestureEvent.getX());
    assertEquals(FAKE_COORD_Y - deltaY, gestureEvent.getY());

    Bundle extraParams = gestureEvent.getExtraParams();
    assertNotNull(extraParams);
    // No horizontal delta because of snapping.
    assertEquals(0, extraParams.getInt(ContentViewGestureHandler.DISTANCE_X));
    assertEquals(deltaY / 2, extraParams.getInt(ContentViewGestureHandler.DISTANCE_Y));
  }
  /**
   * Verify that the first event sent while the page is scrolling will be converted to a
   * touchcancel. The touchcancel event should stay in the pending queue. Acking the touchcancel
   * event will consume all the touch events of the current session.
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testTouchEventsCanceledWhileScrolling() {
    final int deltaY = 84;
    final long downTime = SystemClock.uptimeMillis();

    MockMotionEventDelegate delegate = new MockMotionEventDelegate();
    ContentViewGestureHandler gestureHandler =
        new ContentViewGestureHandler(
            getInstrumentation().getTargetContext(),
            delegate,
            new MockZoomManager(getInstrumentation().getTargetContext(), null));
    gestureHandler.hasTouchEventHandlers(true);
    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
    assertTrue(gestureHandler.onTouchEvent(event));
    gestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);

    event =
        MotionEvent.obtain(
            downTime,
            downTime + 5,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X,
            FAKE_COORD_Y - deltaY / 2,
            0);
    assertTrue(gestureHandler.onTouchEvent(event));
    gestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);

    // This event will be converted to touchcancel and put into the pending
    // queue.
    event =
        MotionEvent.obtain(
            downTime,
            downTime + 10,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X,
            FAKE_COORD_Y - deltaY,
            0);
    assertTrue(gestureHandler.onTouchEvent(event));
    assertEquals(1, gestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertTrue(
        gestureHandler.isEventCancelledForTesting(
            gestureHandler.peekFirstInPendingMotionEventsForTesting()));

    event = motionEvent(MotionEvent.ACTION_POINTER_DOWN, downTime + 15, downTime + 15);
    assertTrue(gestureHandler.onTouchEvent(event));
    assertEquals(2, gestureHandler.getNumberOfPendingMotionEventsForTesting());

    // Acking the touchcancel will drain all the events.
    gestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
    assertEquals(0, gestureHandler.getNumberOfPendingMotionEventsForTesting());
  }
  /**
   * Verify that the timer of LONG_PRESS will be cancelled when scrolling begins so LONG_PRESS and
   * LONG_TAP won't be triggered.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testLongPressAndTapCancelWhenScrollBegins() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    GestureRecordingMotionEventDelegate mockDelegate = new GestureRecordingMotionEventDelegate();
    mGestureHandler =
        new ContentViewGestureHandler(
            getInstrumentation().getTargetContext(),
            mockDelegate,
            new MockZoomManager(getInstrumentation().getTargetContext(), null));
    mLongPressDetector = mGestureHandler.getLongPressDetector();

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertNotNull(mockDelegate.getMostRecentGestureEvent());
    assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 5,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 5,
            FAKE_COORD_Y * 5,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 10,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertTrue("Should not have a pending LONG_PRESS", !mLongPressDetector.hasPendingMessage());

    // No LONG_TAP because LONG_PRESS timer is cancelled.
    assertFalse(
        "No LONG_PRESS should be sent",
        mockDelegate.mGestureTypeList.contains(ContentViewGestureHandler.GESTURE_LONG_PRESS));
    assertFalse(
        "No LONG_TAP should be sent",
        mockDelegate.mGestureTypeList.contains(ContentViewGestureHandler.GESTURE_LONG_TAP));
  }
  /**
   * Verify that a DOWN followed shortly by an UP will trigger a single tap.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testGestureSingleClick() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    assertFalse(mGestureHandler.onTouchEvent(event));
    assertTrue("Should have a pending gesture", mMockGestureDetector.mLastEvent != null);
    assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
    mLongPressDetector.cancelLongPressIfNeeded(event);
    assertTrue("Should not have a pending LONG_PRESS", !mLongPressDetector.hasPendingMessage());
    assertTrue(mGestureHandler.onTouchEvent(event));
    // Synchronous, no need to wait.
    assertTrue("Should have a single tap", mMockListener.mLastSingleTap != null);
  }
  /**
   * Verifies that a single tap doesn't cause a long press event to be sent.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testNoLongPressIsSentForSingleTapOutOfTouchHandler() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    mGestureHandler.hasTouchEventHandlers(true);

    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertTrue("Should not have a pending gesture", mMockGestureDetector.mLastEvent == null);
    assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 5);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);

    assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertEquals(
        "The down touch event should have been sent to the Gesture Detector",
        event.getDownTime(),
        mMockGestureDetector.mLastEvent.getEventTime());
    assertEquals(
        "The next event should be ACTION_UP",
        MotionEvent.ACTION_UP,
        mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());

    mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);

    assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertEquals(
        "The up touch event should have been sent to the Gesture Detector",
        event.getEventTime(),
        mMockGestureDetector.mLastEvent.getEventTime());

    assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());
  }
  /**
   * Verify that a DOWN followed by a MOVE will trigger fling (but not LONG).
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testGestureFlingAndCancelLongClick() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    assertFalse(mGestureHandler.onTouchEvent(event));
    assertTrue("Should have a pending gesture", mMockGestureDetector.mLastEvent != null);
    assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 5,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    mLongPressDetector.cancelLongPressIfNeeded(event);
    assertTrue("Should not have a pending LONG_PRESS", !mLongPressDetector.hasPendingMessage());
    assertTrue(mGestureHandler.onTouchEvent(event));

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 10,
            MotionEvent.ACTION_UP,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));

    // Synchronous, no need to wait.
    assertTrue("Should have a fling", mMockListener.mLastFling1 != null);
    assertTrue("Should not have a long press", mMockListener.mLastLongPress == null);
  }
  /**
   * Verify that the touch slop region is removed from the first scroll delta to avoid a jump when
   * starting to scroll.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testTouchSlopRemovedFromScroll() throws Exception {
    Context context = getInstrumentation().getTargetContext();
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();
    final int scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    final int scrollDelta = 5;

    GestureRecordingMotionEventDelegate mockDelegate = new GestureRecordingMotionEventDelegate();
    mGestureHandler =
        new ContentViewGestureHandler(context, mockDelegate, new MockZoomManager(context, null));

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
    assertTrue(mGestureHandler.onTouchEvent(event));

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 10,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X,
            FAKE_COORD_Y + scaledTouchSlop + scrollDelta,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));

    assertEquals(
        "We should have started scrolling",
        ContentViewGestureHandler.GESTURE_SCROLL_BY,
        mockDelegate.mMostRecentGestureEvent.mType);

    GestureRecordingMotionEventDelegate.GestureEvent gestureEvent =
        mockDelegate.getMostRecentGestureEvent();
    assertNotNull(gestureEvent);
    Bundle extraParams = gestureEvent.getExtraParams();
    assertEquals(0, extraParams.getInt(ContentViewGestureHandler.DISTANCE_X));
    assertEquals(-scrollDelta, extraParams.getInt(ContentViewGestureHandler.DISTANCE_Y));
  }
  /**
   * Verify that a recent show pressed state gesture is canceled when scrolling begins.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testShowPressCancelWhenScrollBegins() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    GestureRecordingMotionEventDelegate mockDelegate = new GestureRecordingMotionEventDelegate();
    mGestureHandler =
        new ContentViewGestureHandler(
            getInstrumentation().getTargetContext(),
            mockDelegate,
            new MockZoomManager(getInstrumentation().getTargetContext(), null));
    mLongPressDetector =
        new LongPressDetector(getInstrumentation().getTargetContext(), mGestureHandler);

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    assertTrue(mGestureHandler.onTouchEvent(event));
    assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    mGestureHandler.sendShowPressedStateGestureForTesting();

    assertEquals(
        "A show pressed state event should have been sent",
        ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE,
        mockDelegate.mMostRecentGestureEvent.mType);
    assertEquals(
        "Only flingCancel and showPressedState should have been sent",
        2,
        mockDelegate.mGestureTypeList.size());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 10,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 5,
            FAKE_COORD_Y * 5,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));

    assertEquals(
        "We should have started scrolling",
        ContentViewGestureHandler.GESTURE_SCROLL_BY,
        mockDelegate.mMostRecentGestureEvent.mType);
    assertTrue(
        "A show press cancel event should have been sent",
        mockDelegate.mGestureTypeList.contains(
            ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL));
    assertEquals(
        "Only flingCancel, showPressedState,"
            + "showPressCancel, scrollBegin and scrollBy should have been sent",
        5,
        mockDelegate.mGestureTypeList.size());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 15,
            MotionEvent.ACTION_UP,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(
        "We should have started flinging",
        ContentViewGestureHandler.GESTURE_FLING_START,
        mockDelegate.mMostRecentGestureEvent.mType);
    assertTrue(
        "A scroll end event should not have been sent",
        !mockDelegate.mGestureTypeList.contains(ContentViewGestureHandler.GESTURE_SCROLL_END));
    assertEquals(
        "The last up should have caused flingCancel and flingStart to be sent",
        7,
        mockDelegate.mGestureTypeList.size());
  }
  /**
   * Verify that for a normal fling (fling after scroll) the following events are sent: -
   * GESTURE_SCROLL_BEGIN - GESTURE_FLING_START
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testFlingEventSequence() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    GestureRecordingMotionEventDelegate mockDelegate = new GestureRecordingMotionEventDelegate();
    mGestureHandler =
        new ContentViewGestureHandler(
            getInstrumentation().getTargetContext(),
            mockDelegate,
            new MockZoomManager(getInstrumentation().getTargetContext(), null));

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    assertTrue(mGestureHandler.onTouchEvent(event));

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 10,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 5,
            FAKE_COORD_Y * 5,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));

    assertTrue(
        "A flingCancel event should have been sent",
        mockDelegate.mGestureTypeList.contains(ContentViewGestureHandler.GESTURE_FLING_CANCEL));
    assertTrue(
        "A scrollStart event should have been sent",
        mockDelegate.mGestureTypeList.contains(ContentViewGestureHandler.GESTURE_SCROLL_START));
    assertEquals(
        "We should have started scrolling",
        ContentViewGestureHandler.GESTURE_SCROLL_BY,
        mockDelegate.mMostRecentGestureEvent.mType);
    assertEquals(
        "Only flingCancel, scrollBegin and scrollBy should have been sent",
        3,
        mockDelegate.mGestureTypeList.size());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 15,
            MotionEvent.ACTION_UP,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(
        "We should have started flinging",
        ContentViewGestureHandler.GESTURE_FLING_START,
        mockDelegate.mMostRecentGestureEvent.mType);
    assertTrue(
        "A scroll end event should not have been sent",
        !mockDelegate.mGestureTypeList.contains(ContentViewGestureHandler.GESTURE_SCROLL_END));
    assertEquals(
        "The last up should have caused flingCancel and flingStart to be sent",
        5,
        mockDelegate.mGestureTypeList.size());
  }
  /**
   * Verify that when a touch event handler is registered the touch events stop getting queued after
   * we received INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testFlingOutOfTouchHandler() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    mGestureHandler.hasTouchEventHandlers(true);

    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertTrue("Should not have a pending gesture", mMockGestureDetector.mLastEvent == null);
    assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    mGestureHandler.confirmTouchEvent(
        ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
    assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertEquals(
        "The down touch event should have been sent to the Gesture Detector",
        event.getEventTime(),
        mMockGestureDetector.mLastEvent.getEventTime());
    assertEquals(
        "The down touch event should have been sent to the Gesture Detector",
        MotionEvent.ACTION_DOWN,
        mMockGestureDetector.mLastEvent.getActionMasked());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 5,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 5,
            FAKE_COORD_Y * 5,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertEquals(
        "Motion events should be going to the Gesture Detector directly",
        event.getEventTime(),
        mMockGestureDetector.mLastEvent.getEventTime());
    assertEquals(
        "Motion events should be going to the Gesture Detector directly",
        MotionEvent.ACTION_MOVE,
        mMockGestureDetector.mLastEvent.getActionMasked());

    event =
        MotionEvent.obtain(
            downTime, eventTime + 10, MotionEvent.ACTION_UP, FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertEquals(
        "Motion events should be going to the Gesture Detector directly",
        event.getEventTime(),
        mMockGestureDetector.mLastEvent.getEventTime());
    assertEquals(
        "Motion events should be going to the Gesture Detector directly",
        MotionEvent.ACTION_UP,
        mMockGestureDetector.mLastEvent.getActionMasked());

    // Synchronous, no need to wait.
    assertTrue("Should have a fling", mMockListener.mLastFling1 != null);
    assertTrue("Should not have a long press", mMockListener.mLastLongPress == null);
  }
  /**
   * Verify that when a registered touch event handler return NO_CONSUMER_EXISTS for down event all
   * queue is drained until next down.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testDrainWithFlingAndClickOutofTouchHandler() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    mGestureHandler =
        new ContentViewGestureHandler(
            getInstrumentation().getTargetContext(),
            new MockMotionEventDelegate(),
            new MockZoomManager(getInstrumentation().getTargetContext(), null));
    mLongPressDetector =
        new LongPressDetector(getInstrumentation().getTargetContext(), mGestureHandler);

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    mGestureHandler.hasTouchEventHandlers(true);

    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 5,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 5,
            FAKE_COORD_Y * 5,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 10,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 15,
            MotionEvent.ACTION_UP,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    event = motionEvent(MotionEvent.ACTION_DOWN, eventTime + 20, eventTime + 20);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(4, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    event =
        MotionEvent.obtain(
            downTime, eventTime + 20, MotionEvent.ACTION_UP, FAKE_COORD_X, FAKE_COORD_Y, 0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(5, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    mGestureHandler.confirmTouchEvent(
        ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
    assertEquals(
        "The queue should have been drained until first down since no consumer exists",
        2,
        mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertEquals(
        MotionEvent.ACTION_DOWN,
        mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());

    mGestureHandler.confirmTouchEvent(
        ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
    assertEquals(
        "The queue should have been drained",
        0,
        mGestureHandler.getNumberOfPendingMotionEventsForTesting());
  }
  /**
   * Verify that after a touch event handlers starts handling a gesture, even though some event in
   * the middle of the gesture returns with NOT_CONSUMED, we don't send that to the gesture detector
   * to avoid falling to a faulty state.
   *
   * @throws Exception
   */
  @SmallTest
  @Feature({"Gestures"})
  public void testFlingOnTouchHandlerWithOneEventNotConsumed() throws Exception {
    final long downTime = SystemClock.uptimeMillis();
    final long eventTime = SystemClock.uptimeMillis();

    MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);

    mGestureHandler.hasTouchEventHandlers(true);

    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertTrue("Should not have a pending gesture", mMockGestureDetector.mLastEvent == null);
    assertFalse("Should not have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 5,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 5,
            FAKE_COORD_Y * 5,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 10,
            MotionEvent.ACTION_MOVE,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(
        "We should have coalesced move events into one",
        2,
        mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    event =
        MotionEvent.obtain(
            downTime,
            eventTime + 15,
            MotionEvent.ACTION_UP,
            FAKE_COORD_X * 10,
            FAKE_COORD_Y * 10,
            0);
    assertTrue(mGestureHandler.onTouchEvent(event));
    assertEquals(3, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
    assertEquals(2, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertEquals(
        MotionEvent.ACTION_MOVE,
        mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());

    mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
    assertEquals(1, mGestureHandler.getNumberOfPendingMotionEventsForTesting());
    assertEquals(
        MotionEvent.ACTION_UP,
        mGestureHandler.peekFirstInPendingMotionEventsForTesting().getActionMasked());
    assertTrue(
        "Even though the last event was not consumed by JavaScript,"
            + "it shouldn't have been sent to the Gesture Detector",
        mMockGestureDetector.mLastEvent == null);

    mGestureHandler.confirmTouchEvent(ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED);
    assertEquals(0, mGestureHandler.getNumberOfPendingMotionEventsForTesting());

    // Synchronous, no need to wait.
    assertTrue("Should not have a fling", mMockListener.mLastFling1 == null);
    assertTrue("Should not have a long press", mMockListener.mLastLongPress == null);
  }