| Index: content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorProxyTest.java
|
| diff --git a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorProxyTest.java b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorProxyTest.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..68d3200e8a759b0a84cfca7d075b6a51c28e8ed5
|
| --- /dev/null
|
| +++ b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorProxyTest.java
|
| @@ -0,0 +1,300 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/**
|
| + * Test suite for GestureDetectorProxy.
|
| + */
|
| +
|
| +package org.chromium.content.browser;
|
| +
|
| +import android.content.Context;
|
| +import android.os.SystemClock;
|
| +import android.test.InstrumentationTestCase;
|
| +import android.test.suitebuilder.annotation.LargeTest;
|
| +import android.test.suitebuilder.annotation.SmallTest;
|
| +import android.view.GestureDetector;
|
| +import android.view.MotionEvent;
|
| +import android.view.ViewConfiguration;
|
| +
|
| +import java.util.concurrent.CountDownLatch;
|
| +import java.util.concurrent.TimeUnit;
|
| +
|
| +import org.chromium.base.test.Feature;
|
| +import org.chromium.base.test.ScalableTimeout;
|
| +
|
| +public class GestureDetectorProxyTest extends InstrumentationTestCase {
|
| + final int mTouchSlop = 37;
|
| + MockListener mMockListener;
|
| + MockGestureDetector mMockDetector;
|
| + GestureDetectorProxy mProxy;
|
| +
|
| + class MockListener extends GestureDetector.SimpleOnGestureListener {
|
| + MotionEvent mLastLongPress;
|
| + MotionEvent mLastSingleTap;
|
| + MotionEvent mLastFling1;
|
| + MotionEvent mLastFling2;
|
| + CountDownLatch mLongPressCalled;
|
| + MotionEvent mLastScroll1;
|
| + MotionEvent mLastScroll2;
|
| + float mLastScrollDistanceX;
|
| + float mLastScrollDistanceY;
|
| +
|
| + public MockListener() {
|
| + mLongPressCalled = new CountDownLatch(1);
|
| + }
|
| +
|
| + @Override
|
| + public void onLongPress(MotionEvent e) {
|
| + mLastLongPress = MotionEvent.obtain(e);
|
| + mLongPressCalled.countDown();
|
| + }
|
| +
|
| + @Override
|
| + public boolean onSingleTapConfirmed(MotionEvent e) {
|
| + mLastSingleTap = e;
|
| + return true;
|
| + }
|
| +
|
| + @Override
|
| + public boolean onSingleTapUp(MotionEvent e) {
|
| + mLastSingleTap = e;
|
| + return true;
|
| + }
|
| +
|
| + @Override
|
| + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
| + mLastScroll1 = e1;
|
| + mLastScroll2 = e2;
|
| + mLastScrollDistanceX = distanceX;
|
| + mLastScrollDistanceY = distanceY;
|
| + return true;
|
| + }
|
| +
|
| + @Override
|
| + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
| + mLastFling1 = e1;
|
| + mLastFling2 = e2;
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + class MockGestureDetector extends GestureDetector {
|
| + MotionEvent mLastEvent;
|
| + public MockGestureDetector(Context context, OnGestureListener listener) {
|
| + super(context, listener);
|
| + }
|
| +
|
| + @Override
|
| + public boolean onTouchEvent(MotionEvent ev) {
|
| + mLastEvent = MotionEvent.obtain(ev);
|
| + return super.onTouchEvent(ev);
|
| + }
|
| + }
|
| +
|
| + private MotionEvent motionEvent(int action, long downTime, long eventTime) {
|
| + final int fakeCoordX = 42;
|
| + final int fakeCoordY = 24;
|
| + return MotionEvent.obtain(downTime, eventTime, action, fakeCoordX, fakeCoordY, 0);
|
| + }
|
| +
|
| + @Override
|
| + public void setUp() {
|
| + mMockListener = new MockListener();
|
| + mMockDetector = new MockGestureDetector(getInstrumentation().getTargetContext(),
|
| + mMockListener);
|
| + mProxy = new GestureDetectorProxy(getInstrumentation().getTargetContext(),
|
| + mMockDetector, mMockListener);
|
| + }
|
| +
|
| + /**
|
| + * Verify a DOWN without a corresponding UP will have a pending DOWN.
|
| + *
|
| + * @throws Exception
|
| + */
|
| + @SmallTest
|
| + @Feature({"Android-WebView"})
|
| + public void testProxySimpleLongPress() throws Exception {
|
| + final long downTime = SystemClock.uptimeMillis();
|
| + final long eventTime = SystemClock.uptimeMillis();
|
| +
|
| + MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime);
|
| +
|
| + assertFalse(mProxy.onTouchEvent(event));
|
| + assertTrue("Should have a pending gesture", mMockDetector.mLastEvent != null);
|
| + assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage());
|
| + }
|
| +
|
| + /**
|
| + * Verify a DOWN with a corresponding UP will not have a pending Gesture.
|
| + *
|
| + * @throws Exception
|
| + */
|
| + @SmallTest
|
| + @Feature({"Android-WebView"})
|
| + public void testProxyNoLongPress() throws Exception {
|
| + final long downTime = SystemClock.uptimeMillis();
|
| + final long eventTime = SystemClock.uptimeMillis();
|
| +
|
| + MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime);
|
| +
|
| + assertFalse(mProxy.onTouchEvent(event));
|
| + assertTrue("Should have a pending gesture", mMockDetector.mLastEvent != null);
|
| + assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage());
|
| +
|
| + event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
|
| + mProxy.cancelLongPressIfNeeded(event);
|
| + assertTrue("Should not have a pending LONG_PRESS", !mProxy.hasPendingMessage());
|
| + }
|
| +
|
| + /**
|
| + * Verify that a DOWN followed by an UP after the long press timer would
|
| + * detect a long press (that is, the UP will not trigger a tap or cancel the
|
| + * long press).
|
| + *
|
| + * @throws Exception
|
| + */
|
| + @SmallTest
|
| + @Feature({"Android-WebView"})
|
| + public void testProxyLongWithDelayedUp() throws Exception {
|
| + final long downTime = SystemClock.uptimeMillis();
|
| + final long eventTime = SystemClock.uptimeMillis();
|
| +
|
| + MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime);
|
| +
|
| + assertFalse(mProxy.onTouchEvent(event));
|
| + assertTrue("Should have a pending gesture", mMockDetector.mLastEvent != null);
|
| + assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage());
|
| +
|
| + // Event time must be larger than LONG_PRESS_TIMEOUT.
|
| + event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 1000);
|
| + mProxy.cancelLongPressIfNeeded(event);
|
| + assertTrue("Should still have a pending gesture", mProxy.hasPendingMessage());
|
| + }
|
| +
|
| + /**
|
| + * Verify that a DOWN followed shortly by an UP will trigger a single tap.
|
| + *
|
| + * @throws Exception
|
| + */
|
| + @SmallTest
|
| + @Feature({"Android-WebView"})
|
| + public void testProxySingleClick() throws Exception {
|
| + final long downTime = SystemClock.uptimeMillis();
|
| + final long eventTime = SystemClock.uptimeMillis();
|
| +
|
| + MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime);
|
| +
|
| + assertFalse(mProxy.onTouchEvent(event));
|
| + assertTrue("Should have a pending gesture", mMockDetector.mLastEvent != null);
|
| + assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage());
|
| +
|
| + event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10);
|
| + mProxy.cancelLongPressIfNeeded(event);
|
| + assertTrue("Should not have a pending LONG_PRESS", !mProxy.hasPendingMessage());
|
| + assertTrue(mProxy.onTouchEvent(event));
|
| + // Synchronous, no need to wait.
|
| + assertTrue("Should have a single tap", mMockListener.mLastSingleTap != null);
|
| + }
|
| +
|
| + /**
|
| + * Verify that a DOWN followed by a MOVE will trigger fling (but not LONG).
|
| + * @throws Exception
|
| + */
|
| + @SmallTest
|
| + @Feature({"Android-WebView"})
|
| + public void testProxyFlingAndCancelLongClick() throws Exception {
|
| + final long downTime = SystemClock.uptimeMillis();
|
| + final long eventTime = SystemClock.uptimeMillis();
|
| +
|
| + MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime);
|
| +
|
| + assertFalse(mProxy.onTouchEvent(event));
|
| + assertTrue("Should have a pending gesture", mMockDetector.mLastEvent != null);
|
| + assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage());
|
| +
|
| + event = MotionEvent.obtain(downTime, eventTime + 5, MotionEvent.ACTION_MOVE, 420, 420, 0);
|
| + mProxy.cancelLongPressIfNeeded(event);
|
| + assertTrue("Should not have a pending LONG_PRESS", !mProxy.hasPendingMessage());
|
| + assertTrue(mProxy.onTouchEvent(event));
|
| +
|
| + event = MotionEvent.obtain(downTime, eventTime + 10, MotionEvent.ACTION_UP, 420, 420, 0);
|
| + assertTrue(mProxy.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);
|
| + }
|
| +
|
| +
|
| + class MainThreadTestHelper {
|
| + MockListener mMockListenerUI;
|
| + MockGestureDetector mMockDetectorUI;
|
| + GestureDetectorProxy mProxyUI;
|
| +
|
| + void setUp() {
|
| + mMockListenerUI = new MockListener();
|
| + mMockDetectorUI = new MockGestureDetector(getInstrumentation().getTargetContext(),
|
| + mMockListenerUI);
|
| + mProxyUI = new GestureDetectorProxy(getInstrumentation().getTargetContext(),
|
| + mMockDetectorUI, mMockListenerUI);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * This is an example of a large test running delayed messages.
|
| + * It exercises GestureDetector itself, and expects the onLongPress to be called.
|
| + * Note that GestureDetector creates a Handler and posts message to it for detecting
|
| + * long press. It needs to be created on the Main thread.
|
| + *
|
| + * @throws Exception
|
| + */
|
| + @LargeTest
|
| + @Feature({"Android-WebView"})
|
| + public void testProxyLongPressDetected() throws Exception {
|
| + final MainThreadTestHelper mainThreadTestHelper = new MainThreadTestHelper();
|
| +
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + mainThreadTestHelper.setUp();
|
| + final long downTime = SystemClock.uptimeMillis();
|
| + final long eventTime = SystemClock.uptimeMillis();
|
| + MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime);
|
| + mainThreadTestHelper.mProxyUI.onTouchEvent(event);
|
| + }
|
| + });
|
| + assertTrue(mainThreadTestHelper.mMockListenerUI
|
| + .mLongPressCalled.await(ScalableTimeout.ScaleTimeout(1000), TimeUnit.MILLISECONDS));
|
| + }
|
| +
|
| + /**
|
| + * Verify that the touch move threshold (slop) is working for events offered to native.
|
| + */
|
| + @SmallTest
|
| + @Feature({"Android-WebView"})
|
| + public void testConfirmOfferMoveEventToNative() {
|
| + final int slop = ViewConfiguration.get(getInstrumentation().getTargetContext())
|
| + .getScaledTouchSlop();
|
| +
|
| + final int downX = 100;
|
| + final int downY = 200;
|
| + long eventTime = SystemClock.uptimeMillis();
|
| + final MotionEvent downEvent = MotionEvent.obtain(eventTime, eventTime,
|
| + MotionEvent.ACTION_DOWN, downX, downY, 0);
|
| +
|
| + // Test a small move, where confirmOfferMoveEventToNative should return false.
|
| + mProxy.onOfferTouchEventToNative(downEvent);
|
| + eventTime = SystemClock.uptimeMillis();
|
| + final MotionEvent smallMove = MotionEvent.obtain(eventTime, eventTime,
|
| + MotionEvent.ACTION_MOVE, downX + slop / 2, downY + slop / 2, 0);
|
| + assertFalse(mProxy.confirmOfferMoveEventToNative(smallMove));
|
| +
|
| + // Test a big move, where confirmOfferMoveEventToNative should return true.
|
| + mProxy.onOfferTouchEventToNative(downEvent);
|
| + eventTime = SystemClock.uptimeMillis();
|
| + final MotionEvent largeMove = MotionEvent.obtain(eventTime, eventTime,
|
| + MotionEvent.ACTION_MOVE, downX + slop * 2, downY + slop * 2, 0);
|
| + assertTrue(mProxy.confirmOfferMoveEventToNative(largeMove));
|
| + }
|
| +}
|
|
|