OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 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 |
| 5 /** |
| 6 * Test suite for GestureDetectorProxy. |
| 7 */ |
| 8 |
| 9 package org.chromium.content.browser; |
| 10 |
| 11 import android.content.Context; |
| 12 import android.os.SystemClock; |
| 13 import android.test.InstrumentationTestCase; |
| 14 import android.test.suitebuilder.annotation.LargeTest; |
| 15 import android.test.suitebuilder.annotation.SmallTest; |
| 16 import android.view.GestureDetector; |
| 17 import android.view.MotionEvent; |
| 18 import android.view.ViewConfiguration; |
| 19 |
| 20 import java.util.concurrent.CountDownLatch; |
| 21 import java.util.concurrent.TimeUnit; |
| 22 |
| 23 import org.chromium.base.test.Feature; |
| 24 import org.chromium.base.test.ScalableTimeout; |
| 25 |
| 26 public class GestureDetectorProxyTest extends InstrumentationTestCase { |
| 27 final int mTouchSlop = 37; |
| 28 MockListener mMockListener; |
| 29 MockGestureDetector mMockDetector; |
| 30 GestureDetectorProxy mProxy; |
| 31 |
| 32 class MockListener extends GestureDetector.SimpleOnGestureListener { |
| 33 MotionEvent mLastLongPress; |
| 34 MotionEvent mLastSingleTap; |
| 35 MotionEvent mLastFling1; |
| 36 MotionEvent mLastFling2; |
| 37 CountDownLatch mLongPressCalled; |
| 38 MotionEvent mLastScroll1; |
| 39 MotionEvent mLastScroll2; |
| 40 float mLastScrollDistanceX; |
| 41 float mLastScrollDistanceY; |
| 42 |
| 43 public MockListener() { |
| 44 mLongPressCalled = new CountDownLatch(1); |
| 45 } |
| 46 |
| 47 @Override |
| 48 public void onLongPress(MotionEvent e) { |
| 49 mLastLongPress = MotionEvent.obtain(e); |
| 50 mLongPressCalled.countDown(); |
| 51 } |
| 52 |
| 53 @Override |
| 54 public boolean onSingleTapConfirmed(MotionEvent e) { |
| 55 mLastSingleTap = e; |
| 56 return true; |
| 57 } |
| 58 |
| 59 @Override |
| 60 public boolean onSingleTapUp(MotionEvent e) { |
| 61 mLastSingleTap = e; |
| 62 return true; |
| 63 } |
| 64 |
| 65 @Override |
| 66 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) { |
| 67 mLastScroll1 = e1; |
| 68 mLastScroll2 = e2; |
| 69 mLastScrollDistanceX = distanceX; |
| 70 mLastScrollDistanceY = distanceY; |
| 71 return true; |
| 72 } |
| 73 |
| 74 @Override |
| 75 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) { |
| 76 mLastFling1 = e1; |
| 77 mLastFling2 = e2; |
| 78 return true; |
| 79 } |
| 80 } |
| 81 |
| 82 class MockGestureDetector extends GestureDetector { |
| 83 MotionEvent mLastEvent; |
| 84 public MockGestureDetector(Context context, OnGestureListener listener)
{ |
| 85 super(context, listener); |
| 86 } |
| 87 |
| 88 @Override |
| 89 public boolean onTouchEvent(MotionEvent ev) { |
| 90 mLastEvent = MotionEvent.obtain(ev); |
| 91 return super.onTouchEvent(ev); |
| 92 } |
| 93 } |
| 94 |
| 95 private MotionEvent motionEvent(int action, long downTime, long eventTime) { |
| 96 final int fakeCoordX = 42; |
| 97 final int fakeCoordY = 24; |
| 98 return MotionEvent.obtain(downTime, eventTime, action, fakeCoordX, fakeC
oordY, 0); |
| 99 } |
| 100 |
| 101 @Override |
| 102 public void setUp() { |
| 103 mMockListener = new MockListener(); |
| 104 mMockDetector = new MockGestureDetector(getInstrumentation().getTargetCo
ntext(), |
| 105 mMockListener); |
| 106 mProxy = new GestureDetectorProxy(getInstrumentation().getTargetContext(
), |
| 107 mMockDetector, mMockListener); |
| 108 } |
| 109 |
| 110 /** |
| 111 * Verify a DOWN without a corresponding UP will have a pending DOWN. |
| 112 * |
| 113 * @throws Exception |
| 114 */ |
| 115 @SmallTest |
| 116 @Feature({"Android-WebView"}) |
| 117 public void testProxySimpleLongPress() throws Exception { |
| 118 final long downTime = SystemClock.uptimeMillis(); |
| 119 final long eventTime = SystemClock.uptimeMillis(); |
| 120 |
| 121 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, event
Time); |
| 122 |
| 123 assertFalse(mProxy.onTouchEvent(event)); |
| 124 assertTrue("Should have a pending gesture", mMockDetector.mLastEvent !=
null); |
| 125 assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage(
)); |
| 126 } |
| 127 |
| 128 /** |
| 129 * Verify a DOWN with a corresponding UP will not have a pending Gesture. |
| 130 * |
| 131 * @throws Exception |
| 132 */ |
| 133 @SmallTest |
| 134 @Feature({"Android-WebView"}) |
| 135 public void testProxyNoLongPress() throws Exception { |
| 136 final long downTime = SystemClock.uptimeMillis(); |
| 137 final long eventTime = SystemClock.uptimeMillis(); |
| 138 |
| 139 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, event
Time); |
| 140 |
| 141 assertFalse(mProxy.onTouchEvent(event)); |
| 142 assertTrue("Should have a pending gesture", mMockDetector.mLastEvent !=
null); |
| 143 assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage(
)); |
| 144 |
| 145 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10); |
| 146 mProxy.cancelLongPressIfNeeded(event); |
| 147 assertTrue("Should not have a pending LONG_PRESS", !mProxy.hasPendingMes
sage()); |
| 148 } |
| 149 |
| 150 /** |
| 151 * Verify that a DOWN followed by an UP after the long press timer would |
| 152 * detect a long press (that is, the UP will not trigger a tap or cancel the |
| 153 * long press). |
| 154 * |
| 155 * @throws Exception |
| 156 */ |
| 157 @SmallTest |
| 158 @Feature({"Android-WebView"}) |
| 159 public void testProxyLongWithDelayedUp() throws Exception { |
| 160 final long downTime = SystemClock.uptimeMillis(); |
| 161 final long eventTime = SystemClock.uptimeMillis(); |
| 162 |
| 163 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, event
Time); |
| 164 |
| 165 assertFalse(mProxy.onTouchEvent(event)); |
| 166 assertTrue("Should have a pending gesture", mMockDetector.mLastEvent !=
null); |
| 167 assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage(
)); |
| 168 |
| 169 // Event time must be larger than LONG_PRESS_TIMEOUT. |
| 170 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 1000); |
| 171 mProxy.cancelLongPressIfNeeded(event); |
| 172 assertTrue("Should still have a pending gesture", mProxy.hasPendingMessa
ge()); |
| 173 } |
| 174 |
| 175 /** |
| 176 * Verify that a DOWN followed shortly by an UP will trigger a single tap. |
| 177 * |
| 178 * @throws Exception |
| 179 */ |
| 180 @SmallTest |
| 181 @Feature({"Android-WebView"}) |
| 182 public void testProxySingleClick() throws Exception { |
| 183 final long downTime = SystemClock.uptimeMillis(); |
| 184 final long eventTime = SystemClock.uptimeMillis(); |
| 185 |
| 186 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, event
Time); |
| 187 |
| 188 assertFalse(mProxy.onTouchEvent(event)); |
| 189 assertTrue("Should have a pending gesture", mMockDetector.mLastEvent !=
null); |
| 190 assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage(
)); |
| 191 |
| 192 event = motionEvent(MotionEvent.ACTION_UP, downTime, eventTime + 10); |
| 193 mProxy.cancelLongPressIfNeeded(event); |
| 194 assertTrue("Should not have a pending LONG_PRESS", !mProxy.hasPendingMes
sage()); |
| 195 assertTrue(mProxy.onTouchEvent(event)); |
| 196 // Synchronous, no need to wait. |
| 197 assertTrue("Should have a single tap", mMockListener.mLastSingleTap != n
ull); |
| 198 } |
| 199 |
| 200 /** |
| 201 * Verify that a DOWN followed by a MOVE will trigger fling (but not LONG). |
| 202 * @throws Exception |
| 203 */ |
| 204 @SmallTest |
| 205 @Feature({"Android-WebView"}) |
| 206 public void testProxyFlingAndCancelLongClick() throws Exception { |
| 207 final long downTime = SystemClock.uptimeMillis(); |
| 208 final long eventTime = SystemClock.uptimeMillis(); |
| 209 |
| 210 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, event
Time); |
| 211 |
| 212 assertFalse(mProxy.onTouchEvent(event)); |
| 213 assertTrue("Should have a pending gesture", mMockDetector.mLastEvent !=
null); |
| 214 assertTrue("Should have a pending LONG_PRESS", mProxy.hasPendingMessage(
)); |
| 215 |
| 216 event = MotionEvent.obtain(downTime, eventTime + 5, MotionEvent.ACTION_M
OVE, 420, 420, 0); |
| 217 mProxy.cancelLongPressIfNeeded(event); |
| 218 assertTrue("Should not have a pending LONG_PRESS", !mProxy.hasPendingMes
sage()); |
| 219 assertTrue(mProxy.onTouchEvent(event)); |
| 220 |
| 221 event = MotionEvent.obtain(downTime, eventTime + 10, MotionEvent.ACTION_
UP, 420, 420, 0); |
| 222 assertTrue(mProxy.onTouchEvent(event)); |
| 223 |
| 224 // Synchronous, no need to wait. |
| 225 assertTrue("Should have a fling", mMockListener.mLastFling1 != null); |
| 226 assertTrue("Should not have a long press", mMockListener.mLastLongPress
== null); |
| 227 } |
| 228 |
| 229 |
| 230 class MainThreadTestHelper { |
| 231 MockListener mMockListenerUI; |
| 232 MockGestureDetector mMockDetectorUI; |
| 233 GestureDetectorProxy mProxyUI; |
| 234 |
| 235 void setUp() { |
| 236 mMockListenerUI = new MockListener(); |
| 237 mMockDetectorUI = new MockGestureDetector(getInstrumentation().getTa
rgetContext(), |
| 238 mMockListenerUI); |
| 239 mProxyUI = new GestureDetectorProxy(getInstrumentation().getTargetCo
ntext(), |
| 240 mMockDetectorUI, mMockListenerUI); |
| 241 } |
| 242 } |
| 243 |
| 244 /** |
| 245 * This is an example of a large test running delayed messages. |
| 246 * It exercises GestureDetector itself, and expects the onLongPress to be ca
lled. |
| 247 * Note that GestureDetector creates a Handler and posts message to it for d
etecting |
| 248 * long press. It needs to be created on the Main thread. |
| 249 * |
| 250 * @throws Exception |
| 251 */ |
| 252 @LargeTest |
| 253 @Feature({"Android-WebView"}) |
| 254 public void testProxyLongPressDetected() throws Exception { |
| 255 final MainThreadTestHelper mainThreadTestHelper = new MainThreadTestHelp
er(); |
| 256 |
| 257 getInstrumentation().runOnMainSync(new Runnable() { |
| 258 @Override |
| 259 public void run() { |
| 260 mainThreadTestHelper.setUp(); |
| 261 final long downTime = SystemClock.uptimeMillis(); |
| 262 final long eventTime = SystemClock.uptimeMillis(); |
| 263 MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTim
e, eventTime); |
| 264 mainThreadTestHelper.mProxyUI.onTouchEvent(event); |
| 265 } |
| 266 }); |
| 267 assertTrue(mainThreadTestHelper.mMockListenerUI |
| 268 .mLongPressCalled.await(ScalableTimeout.ScaleTimeout(1000), Time
Unit.MILLISECONDS)); |
| 269 } |
| 270 |
| 271 /** |
| 272 * Verify that the touch move threshold (slop) is working for events offered
to native. |
| 273 */ |
| 274 @SmallTest |
| 275 @Feature({"Android-WebView"}) |
| 276 public void testConfirmOfferMoveEventToNative() { |
| 277 final int slop = ViewConfiguration.get(getInstrumentation().getTargetCon
text()) |
| 278 .getScaledTouchSlop(); |
| 279 |
| 280 final int downX = 100; |
| 281 final int downY = 200; |
| 282 long eventTime = SystemClock.uptimeMillis(); |
| 283 final MotionEvent downEvent = MotionEvent.obtain(eventTime, eventTime, |
| 284 MotionEvent.ACTION_DOWN, downX, downY, 0); |
| 285 |
| 286 // Test a small move, where confirmOfferMoveEventToNative should return
false. |
| 287 mProxy.onOfferTouchEventToNative(downEvent); |
| 288 eventTime = SystemClock.uptimeMillis(); |
| 289 final MotionEvent smallMove = MotionEvent.obtain(eventTime, eventTime, |
| 290 MotionEvent.ACTION_MOVE, downX + slop / 2, downY + slop / 2, 0); |
| 291 assertFalse(mProxy.confirmOfferMoveEventToNative(smallMove)); |
| 292 |
| 293 // Test a big move, where confirmOfferMoveEventToNative should return tr
ue. |
| 294 mProxy.onOfferTouchEventToNative(downEvent); |
| 295 eventTime = SystemClock.uptimeMillis(); |
| 296 final MotionEvent largeMove = MotionEvent.obtain(eventTime, eventTime, |
| 297 MotionEvent.ACTION_MOVE, downX + slop * 2, downY + slop * 2, 0); |
| 298 assertTrue(mProxy.confirmOfferMoveEventToNative(largeMove)); |
| 299 } |
| 300 } |
OLD | NEW |