/**
   * 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());
  }
  /**
   * 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 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 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 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);
  }