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)); |
+ } |
+} |