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. 4 5package org.chromium.content.browser; 6 7import android.os.SystemClock; 8import android.test.InstrumentationTestCase; 9import android.test.suitebuilder.annotation.LargeTest; 10import android.test.suitebuilder.annotation.SmallTest; 11import android.view.MotionEvent; 12import android.view.ViewConfiguration; 13 14import org.chromium.base.test.util.Feature; 15import org.chromium.base.test.util.ScalableTimeout; 16 17import java.util.concurrent.CountDownLatch; 18import java.util.concurrent.TimeUnit; 19 20/** 21 * Test suite for LongPressDetector. 22 */ 23public class LongPressDetectorTest extends InstrumentationTestCase { 24 private static final int FAKE_COORD_X = 42; 25 private static final int FAKE_COORD_Y = 24; 26 private LongPressDetector mLongPressDetector; 27 28 private MotionEvent motionEvent(int action, long downTime, long eventTime) { 29 return MotionEvent.obtain(downTime, eventTime, action, FAKE_COORD_X, FAKE_COORD_Y, 0); 30 } 31 32 @Override 33 public void setUp() { 34 mLongPressDetector = new LongPressDetector(getInstrumentation().getTargetContext(), null); 35 } 36 37 /** 38 * Verify a DOWN without a corresponding UP will have a pending DOWN. 39 * 40 * @throws Exception 41 */ 42 @SmallTest 43 @Feature({"AndroidWebView"}) 44 public void testGestureSimpleLongPress() throws Exception { 45 final long downTime = SystemClock.uptimeMillis(); 46 final long eventTime = SystemClock.uptimeMillis(); 47 48 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime); 49 mLongPressDetector.startLongPressTimerIfNeeded(event); 50 51 assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage()); 52 } 53 54 private void gestureNoLongPressTestHelper(int cancelActionType) throws Exception { 55 final long downTime = SystemClock.uptimeMillis(); 56 final long eventTime = SystemClock.uptimeMillis(); 57 58 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime); 59 mLongPressDetector.startLongPressTimerIfNeeded(event); 60 61 assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage()); 62 63 event = motionEvent(cancelActionType, downTime, eventTime + 10); 64 mLongPressDetector.cancelLongPressIfNeeded(event); 65 assertTrue("Should not have a pending LONG_PRESS", !mLongPressDetector.hasPendingMessage()); 66 } 67 68 /** 69 * Verify a DOWN with a corresponding UP will not have a pending Gesture. 70 * 71 * @throws Exception 72 */ 73 @SmallTest 74 @Feature({"AndroidWebView"}) 75 public void testGestureNoLongPressOnUp() throws Exception { 76 gestureNoLongPressTestHelper(MotionEvent.ACTION_UP); 77 } 78 79 /** 80 * Verify a DOWN with a corresponding CANCEL will not have a pending Gesture. 81 * 82 * @throws Exception 83 */ 84 @SmallTest 85 @Feature({"AndroidWebView"}) 86 public void testGestureNoLongPressOnCancel() throws Exception { 87 gestureNoLongPressTestHelper(MotionEvent.ACTION_CANCEL); 88 } 89 90 /** 91 * Verify that a DOWN followed by an UP after the long press timer would 92 * detect a long press (that is, the UP will not trigger a tap or cancel the 93 * long press). 94 * 95 * @throws Exception 96 */ 97 @SmallTest 98 @Feature({"AndroidWebView"}) 99 public void testGestureLongWithDelayedUp() throws Exception { 100 final long downTime = SystemClock.uptimeMillis(); 101 final long eventTime = SystemClock.uptimeMillis(); 102 103 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime); 104 mLongPressDetector.startLongPressTimerIfNeeded(event); 105 106 assertTrue("Should have a pending LONG_PRESS", mLongPressDetector.hasPendingMessage()); 107 108 // Event time must be larger than LONG_PRESS_TIMEOUT. 109 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 1000); 110 mLongPressDetector.cancelLongPressIfNeeded(event); 111 assertTrue("Should still have a pending gesture", mLongPressDetector.hasPendingMessage()); 112 } 113 114 /** 115 * Verify that the touch move threshold (slop) is working for events offered to native. 116 */ 117 @SmallTest 118 @Feature({"AndroidWebView"}) 119 public void testConfirmOfferMoveEventToNative() { 120 final int slop = ViewConfiguration.get(getInstrumentation().getTargetContext()) 121 .getScaledTouchSlop(); 122 123 long eventTime = SystemClock.uptimeMillis(); 124 final MotionEvent downEvent = MotionEvent.obtain( 125 eventTime, eventTime, MotionEvent.ACTION_DOWN, FAKE_COORD_X, FAKE_COORD_Y, 0); 126 127 // Test a small move, where confirmOfferMoveEventToNative should return false. 128 mLongPressDetector.onOfferTouchEventToJavaScript(downEvent); 129 eventTime = SystemClock.uptimeMillis(); 130 final MotionEvent smallMove = MotionEvent.obtain( 131 eventTime, eventTime, MotionEvent.ACTION_MOVE, 132 FAKE_COORD_X + slop / 2, FAKE_COORD_Y + slop / 2, 0); 133 assertFalse(mLongPressDetector.confirmOfferMoveEventToJavaScript(smallMove)); 134 135 // Test a big move, where confirmOfferMoveEventToNative should return true. 136 mLongPressDetector.onOfferTouchEventToJavaScript(downEvent); 137 eventTime = SystemClock.uptimeMillis(); 138 final MotionEvent largeMove = MotionEvent.obtain( 139 eventTime, eventTime, MotionEvent.ACTION_MOVE, 140 FAKE_COORD_X + slop * 2, FAKE_COORD_Y + slop * 2, 0); 141 assertTrue(mLongPressDetector.confirmOfferMoveEventToJavaScript(largeMove)); 142 } 143 144 /** 145 * This is an example of a large test running delayed messages. 146 * It exercises GestureDetector itself, and expects the onLongPress to be called. 147 * Note that GestureDetector creates a Handler and posts message to it for detecting 148 * long press. It needs to be created on the Main thread. 149 * 150 * @throws Exception 151 */ 152 @LargeTest 153 @Feature({"AndroidWebView"}) 154 public void testGestureLongPressDetected() throws Exception { 155 final CountDownLatch longPressCalled = new CountDownLatch(1); 156 getInstrumentation().runOnMainSync(new Runnable() { 157 @Override 158 public void run() { 159 LongPressDetector longPressDetector = new LongPressDetector( 160 getInstrumentation().getTargetContext(), 161 new LongPressDetector.LongPressDelegate() { 162 @Override 163 public void onLongPress(MotionEvent event) { 164 longPressCalled.countDown(); 165 } 166 }); 167 168 final long downTime = SystemClock.uptimeMillis(); 169 final long eventTime = SystemClock.uptimeMillis(); 170 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, eventTime); 171 longPressDetector.startLongPressTimerIfNeeded(event); 172 } 173 }); 174 assertTrue(longPressCalled.await( 175 ScalableTimeout.ScaleTimeout(1000), TimeUnit.MILLISECONDS)); 176 } 177} 178