1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.accessibility; 18 19 import static android.view.KeyCharacterMap.VIRTUAL_KEYBOARD; 20 import static android.view.MotionEvent.ACTION_DOWN; 21 import static android.view.MotionEvent.ACTION_HOVER_MOVE; 22 import static android.view.MotionEvent.ACTION_UP; 23 import static android.view.WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; 24 import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER; 25 26 import static org.hamcrest.CoreMatchers.allOf; 27 import static org.hamcrest.CoreMatchers.anyOf; 28 import static org.hamcrest.CoreMatchers.everyItem; 29 import static org.hamcrest.MatcherAssert.assertThat; 30 import static org.junit.Assert.assertEquals; 31 import static org.junit.Assert.assertFalse; 32 import static org.junit.Assert.assertTrue; 33 import static org.mockito.Matchers.anyBoolean; 34 import static org.mockito.Matchers.anyInt; 35 import static org.mockito.Matchers.eq; 36 import static org.mockito.Mockito.mock; 37 import static org.mockito.Mockito.reset; 38 import static org.mockito.Mockito.times; 39 import static org.mockito.Mockito.verify; 40 import static org.mockito.Mockito.verifyNoMoreInteractions; 41 import static org.mockito.Mockito.verifyZeroInteractions; 42 import static org.mockito.hamcrest.MockitoHamcrest.argThat; 43 44 import android.accessibilityservice.GestureDescription.GestureStep; 45 import android.accessibilityservice.GestureDescription.TouchPoint; 46 import android.accessibilityservice.IAccessibilityServiceClient; 47 import android.graphics.Point; 48 import android.os.Handler; 49 import android.os.Message; 50 import android.os.RemoteException; 51 import android.view.Display; 52 import android.view.InputDevice; 53 import android.view.KeyEvent; 54 import android.view.MotionEvent; 55 import android.view.accessibility.AccessibilityEvent; 56 57 import androidx.test.runner.AndroidJUnit4; 58 59 import com.android.server.accessibility.test.MessageCapturingHandler; 60 import com.android.server.accessibility.utils.MotionEventMatcher; 61 62 import org.hamcrest.Description; 63 import org.hamcrest.Matcher; 64 import org.hamcrest.TypeSafeMatcher; 65 import org.junit.After; 66 import org.junit.Before; 67 import org.junit.Test; 68 import org.junit.runner.RunWith; 69 import org.mockito.ArgumentCaptor; 70 71 import java.util.ArrayList; 72 import java.util.Arrays; 73 import java.util.List; 74 75 /** 76 * Tests for MotionEventInjector 77 */ 78 @RunWith(AndroidJUnit4.class) 79 public class MotionEventInjectorTest { 80 private static final String LOG_TAG = "MotionEventInjectorTest"; 81 private static final Matcher<MotionEvent> IS_ACTION_DOWN = 82 new MotionEventActionMatcher(ACTION_DOWN); 83 private static final Matcher<MotionEvent> IS_ACTION_POINTER_DOWN = 84 new MotionEventActionMatcher(MotionEvent.ACTION_POINTER_DOWN); 85 private static final Matcher<MotionEvent> IS_ACTION_UP = 86 new MotionEventActionMatcher(ACTION_UP); 87 private static final Matcher<MotionEvent> IS_ACTION_POINTER_UP = 88 new MotionEventActionMatcher(MotionEvent.ACTION_POINTER_UP); 89 private static final Matcher<MotionEvent> IS_ACTION_CANCEL = 90 new MotionEventActionMatcher(MotionEvent.ACTION_CANCEL); 91 private static final Matcher<MotionEvent> IS_ACTION_MOVE = 92 new MotionEventActionMatcher(MotionEvent.ACTION_MOVE); 93 94 private static final Point LINE_START = new Point(100, 200); 95 private static final Point LINE_END = new Point(100, 300); 96 private static final int LINE_DURATION = 100; 97 private static final int LINE_SEQUENCE = 50; 98 99 private static final Point CLICK_POINT = new Point(1000, 2000); 100 private static final int CLICK_DURATION = 10; 101 private static final int CLICK_SEQUENCE = 51; 102 103 private static final int MOTION_EVENT_SOURCE = InputDevice.SOURCE_TOUCHSCREEN; 104 private static final int OTHER_EVENT_SOURCE = InputDevice.SOURCE_MOUSE; 105 106 private static final Point CONTINUED_LINE_START = new Point(500, 300); 107 private static final Point CONTINUED_LINE_MID1 = new Point(500, 400); 108 private static final Point CONTINUED_LINE_MID2 = new Point(600, 300); 109 private static final Point CONTINUED_LINE_END = new Point(600, 400); 110 private static final int CONTINUED_LINE_STROKE_ID_1 = 100; 111 private static final int CONTINUED_LINE_STROKE_ID_2 = 101; 112 private static final int CONTINUED_LINE_INTERVAL = 100; 113 private static final int CONTINUED_LINE_SEQUENCE_1 = 52; 114 private static final int CONTINUED_LINE_SEQUENCE_2 = 53; 115 116 private static final float PRESSURE = 1; 117 private static final float X_PRECISION = 1; 118 private static final float Y_PRECISION = 1; 119 private static final int EDGEFLAGS = 0; 120 private static final float POINTER_SIZE = 1; 121 private static final int METASTATE = 0; 122 123 MotionEventInjector mMotionEventInjector; 124 IAccessibilityServiceClient mServiceInterface; 125 List<GestureStep> mLineList = new ArrayList<>(); 126 List<GestureStep> mClickList = new ArrayList<>(); 127 List<GestureStep> mContinuedLineList1 = new ArrayList<>(); 128 List<GestureStep> mContinuedLineList2 = new ArrayList<>(); 129 130 MotionEvent mClickDownEvent; 131 MotionEvent mClickUpEvent; 132 MotionEvent mHoverMoveEvent; 133 134 ArgumentCaptor<MotionEvent> mCaptor1 = ArgumentCaptor.forClass(MotionEvent.class); 135 ArgumentCaptor<MotionEvent> mCaptor2 = ArgumentCaptor.forClass(MotionEvent.class); 136 MessageCapturingHandler mMessageCapturingHandler; 137 Matcher<MotionEvent> mIsLineStart; 138 Matcher<MotionEvent> mIsLineMiddle; 139 Matcher<MotionEvent> mIsLineEnd; 140 Matcher<MotionEvent> mIsClickDown; 141 Matcher<MotionEvent> mIsClickUp; 142 143 @Before setUp()144 public void setUp() { 145 mMessageCapturingHandler = new MessageCapturingHandler(new Handler.Callback() { 146 @Override 147 public boolean handleMessage(Message msg) { 148 return mMotionEventInjector.handleMessage(msg); 149 } 150 }); 151 mMotionEventInjector = new MotionEventInjector(mMessageCapturingHandler); 152 mServiceInterface = mock(IAccessibilityServiceClient.class); 153 154 mLineList = createSimpleGestureFromPoints(0, 0, false, LINE_DURATION, LINE_START, LINE_END); 155 mClickList = createSimpleGestureFromPoints( 156 0, 0, false, CLICK_DURATION, CLICK_POINT, CLICK_POINT); 157 mContinuedLineList1 = createSimpleGestureFromPoints(CONTINUED_LINE_STROKE_ID_1, 0, true, 158 CONTINUED_LINE_INTERVAL, CONTINUED_LINE_START, CONTINUED_LINE_MID1); 159 mContinuedLineList2 = createSimpleGestureFromPoints(CONTINUED_LINE_STROKE_ID_2, 160 CONTINUED_LINE_STROKE_ID_1, false, CONTINUED_LINE_INTERVAL, CONTINUED_LINE_MID1, 161 CONTINUED_LINE_MID2, CONTINUED_LINE_END); 162 163 mClickDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, CLICK_POINT.x, CLICK_POINT.y, 164 PRESSURE, POINTER_SIZE, METASTATE, X_PRECISION, Y_PRECISION, VIRTUAL_KEYBOARD, 165 EDGEFLAGS); 166 mClickDownEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); 167 mClickUpEvent = MotionEvent.obtain(0, CLICK_DURATION, ACTION_UP, CLICK_POINT.x, 168 CLICK_POINT.y, PRESSURE, POINTER_SIZE, METASTATE, X_PRECISION, Y_PRECISION, 169 VIRTUAL_KEYBOARD, EDGEFLAGS); 170 mClickUpEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); 171 172 mHoverMoveEvent = MotionEvent.obtain(0, 0, ACTION_HOVER_MOVE, CLICK_POINT.x, CLICK_POINT.y, 173 PRESSURE, POINTER_SIZE, METASTATE, X_PRECISION, Y_PRECISION, VIRTUAL_KEYBOARD, 174 EDGEFLAGS); 175 mHoverMoveEvent.setSource(InputDevice.SOURCE_MOUSE); 176 177 mIsLineStart = allOf(IS_ACTION_DOWN, isAtPoint(LINE_START), hasStandardInitialization(), 178 hasTimeFromDown(0)); 179 mIsLineMiddle = allOf(IS_ACTION_MOVE, isAtPoint(LINE_END), hasStandardInitialization(), 180 hasTimeFromDown(LINE_DURATION)); 181 mIsLineEnd = allOf(IS_ACTION_UP, isAtPoint(LINE_END), hasStandardInitialization(), 182 hasTimeFromDown(LINE_DURATION)); 183 mIsClickDown = allOf(IS_ACTION_DOWN, isAtPoint(CLICK_POINT), hasStandardInitialization(), 184 hasTimeFromDown(0)); 185 mIsClickUp = allOf(IS_ACTION_UP, isAtPoint(CLICK_POINT), hasStandardInitialization(), 186 hasTimeFromDown(CLICK_DURATION)); 187 } 188 189 @After tearDown()190 public void tearDown() { 191 mMessageCapturingHandler.removeAllMessages(); 192 } 193 194 195 @Test testInjectEvents_shouldEmergeInOrderWithCorrectTiming()196 public void testInjectEvents_shouldEmergeInOrderWithCorrectTiming() throws RemoteException { 197 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 198 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 199 verifyNoMoreInteractions(next); 200 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 201 202 final int expectedFlags = FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY; 203 verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), eq(expectedFlags)); 204 verify(next).onMotionEvent(argThat(mIsLineStart), argThat(mIsLineStart), eq(expectedFlags)); 205 verifyNoMoreInteractions(next); 206 reset(next); 207 208 Matcher<MotionEvent> hasRightDownTime = hasDownTime(mCaptor1.getValue().getDownTime()); 209 210 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 211 verify(next).onMotionEvent(argThat(allOf(mIsLineMiddle, hasRightDownTime)), 212 argThat(allOf(mIsLineMiddle, hasRightDownTime)), eq(expectedFlags)); 213 verifyNoMoreInteractions(next); 214 reset(next); 215 216 verifyZeroInteractions(mServiceInterface); 217 218 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 219 verify(next).onMotionEvent(argThat(allOf(mIsLineEnd, hasRightDownTime)), 220 argThat(allOf(mIsLineEnd, hasRightDownTime)), eq(expectedFlags)); 221 verifyNoMoreInteractions(next); 222 223 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); 224 verifyNoMoreInteractions(mServiceInterface); 225 } 226 227 @Test testInjectEvents_gestureWithTooManyPoints_shouldNotCrash()228 public void testInjectEvents_gestureWithTooManyPoints_shouldNotCrash() throws Exception { 229 int tooManyPointsCount = 20; 230 TouchPoint[] startTouchPoints = new TouchPoint[tooManyPointsCount]; 231 TouchPoint[] endTouchPoints = new TouchPoint[tooManyPointsCount]; 232 for (int i = 0; i < tooManyPointsCount; i++) { 233 startTouchPoints[i] = new TouchPoint(); 234 startTouchPoints[i].mIsStartOfPath = true; 235 startTouchPoints[i].mX = i; 236 startTouchPoints[i].mY = i; 237 endTouchPoints[i] = new TouchPoint(); 238 endTouchPoints[i].mIsEndOfPath = true; 239 endTouchPoints[i].mX = i; 240 endTouchPoints[i].mY = i; 241 } 242 List<GestureStep> events = Arrays.asList( 243 new GestureStep(0, tooManyPointsCount, startTouchPoints), 244 new GestureStep(CLICK_DURATION, tooManyPointsCount, endTouchPoints)); 245 attachMockNext(mMotionEventInjector); 246 injectEventsSync(events, mServiceInterface, CLICK_SEQUENCE); 247 mMessageCapturingHandler.sendAllMessages(); 248 verify(mServiceInterface).onPerformGestureResult(eq(CLICK_SEQUENCE), anyBoolean()); 249 } 250 251 @Test testRegularEvent_afterGestureComplete_shouldPassToNext()252 public void testRegularEvent_afterGestureComplete_shouldPassToNext() { 253 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 254 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 255 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 256 reset(next); 257 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 258 verify(next).onMotionEvent(argThat(mIsClickDown), argThat(mIsClickDown), 259 eq(FLAG_INJECTED_FROM_ACCESSIBILITY)); 260 } 261 262 @Test testInjectEvents_withRealGestureUnderway_shouldCancelRealAndPassInjected()263 public void testInjectEvents_withRealGestureUnderway_shouldCancelRealAndPassInjected() { 264 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 265 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 266 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 267 268 verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 269 assertThat(mCaptor1.getAllValues().get(0), mIsClickDown); 270 assertThat(mCaptor1.getAllValues().get(1), IS_ACTION_CANCEL); 271 reset(next); 272 273 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 274 verify(next).onMotionEvent( 275 argThat(mIsLineStart), argThat(mIsLineStart), 276 eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY)); 277 } 278 279 @Test testInjectEvents_withRealMouseGestureUnderway_shouldContinueRealAndPassInjected()280 public void testInjectEvents_withRealMouseGestureUnderway_shouldContinueRealAndPassInjected() { 281 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 282 MotionEvent mouseEvent = MotionEvent.obtain(mClickDownEvent); 283 mouseEvent.setSource(InputDevice.SOURCE_MOUSE); 284 MotionEventMatcher isMouseEvent = new MotionEventMatcher(mouseEvent); 285 mMotionEventInjector.onMotionEvent(mouseEvent, mouseEvent, 0); 286 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 287 288 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 289 verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 290 assertThat(mCaptor1.getAllValues().get(0), isMouseEvent); 291 assertThat(mCaptor1.getAllValues().get(1), mIsLineStart); 292 } 293 294 @Test testInjectEvents_withRealGestureFinished_shouldJustPassInjected()295 public void testInjectEvents_withRealGestureFinished_shouldJustPassInjected() { 296 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 297 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 298 mMotionEventInjector.onMotionEvent(mClickUpEvent, mClickUpEvent, 0); 299 300 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 301 verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 302 assertThat(mCaptor1.getAllValues().get(0), mIsClickDown); 303 assertThat(mCaptor1.getAllValues().get(1), mIsClickUp); 304 reset(next); 305 306 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 307 verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), 308 eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY)); 309 verify(next).onMotionEvent( 310 argThat(mIsLineStart), argThat(mIsLineStart), 311 eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY)); 312 } 313 314 @Test testOnMotionEvents_openInjectedGestureInProgress_shouldCancelAndNotifyAndPassReal()315 public void testOnMotionEvents_openInjectedGestureInProgress_shouldCancelAndNotifyAndPassReal() 316 throws RemoteException { 317 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 318 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 319 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 320 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 321 322 verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 323 assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); 324 assertThat(mCaptor1.getAllValues().get(1), IS_ACTION_CANCEL); 325 assertThat(mCaptor1.getAllValues().get(2), mIsClickDown); 326 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false); 327 } 328 329 @Test 330 public void testOnMotionEvents_fromMouseWithInjectedGestureInProgress_shouldNotCancelAndPassReal()331 testOnMotionEvents_fromMouseWithInjectedGestureInProgress_shouldNotCancelAndPassReal() 332 throws RemoteException { 333 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 334 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 335 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 336 mMotionEventInjector.onMotionEvent(mHoverMoveEvent, mHoverMoveEvent, 0); 337 mMessageCapturingHandler.sendAllMessages(); 338 339 verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 340 assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); 341 assertThat(mCaptor1.getAllValues().get(1), mIsLineMiddle); 342 assertThat(mCaptor1.getAllValues().get(2), mIsLineEnd); 343 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); 344 } 345 346 @Test testOnMotionEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassReal()347 public void testOnMotionEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassReal() 348 throws RemoteException { 349 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 350 // Tack a click down to the end of the line 351 TouchPoint clickTouchPoint = new TouchPoint(); 352 clickTouchPoint.mIsStartOfPath = true; 353 clickTouchPoint.mX = CLICK_POINT.x; 354 clickTouchPoint.mY = CLICK_POINT.y; 355 mLineList.add(new GestureStep(0, 1, new TouchPoint[] {clickTouchPoint})); 356 357 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 358 359 // Send 3 motion events, leaving the extra down in the queue 360 mMessageCapturingHandler.sendOneMessage(); 361 mMessageCapturingHandler.sendOneMessage(); 362 mMessageCapturingHandler.sendOneMessage(); 363 364 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 365 366 verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 367 assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); 368 assertThat(mCaptor1.getAllValues().get(1), mIsLineMiddle); 369 assertThat(mCaptor1.getAllValues().get(2), mIsLineEnd); 370 assertThat(mCaptor1.getAllValues().get(3), mIsClickDown); 371 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false); 372 assertFalse(mMessageCapturingHandler.hasMessages()); 373 } 374 375 @Test testInjectEvents_openInjectedGestureInProgress_shouldCancelAndNotifyAndPassNew()376 public void testInjectEvents_openInjectedGestureInProgress_shouldCancelAndNotifyAndPassNew() 377 throws RemoteException { 378 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 379 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 380 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 381 382 injectEventsSync(mClickList, mServiceInterface, CLICK_SEQUENCE); 383 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 384 385 verify(mServiceInterface, times(1)).onPerformGestureResult(LINE_SEQUENCE, false); 386 verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 387 assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); 388 assertThat(mCaptor1.getAllValues().get(1), IS_ACTION_CANCEL); 389 assertThat(mCaptor1.getAllValues().get(2), mIsClickDown); 390 } 391 392 @Test testInjectEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassNew()393 public void testInjectEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassNew() 394 throws RemoteException { 395 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 396 // Tack a click down to the end of the line 397 TouchPoint clickTouchPoint = new TouchPoint(); 398 clickTouchPoint.mIsStartOfPath = true; 399 clickTouchPoint.mX = CLICK_POINT.x; 400 clickTouchPoint.mY = CLICK_POINT.y; 401 mLineList.add(new GestureStep(0, 1, new TouchPoint[] {clickTouchPoint})); 402 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 403 404 // Send 3 motion events, leaving newEvent in the queue 405 mMessageCapturingHandler.sendOneMessage(); 406 mMessageCapturingHandler.sendOneMessage(); 407 mMessageCapturingHandler.sendOneMessage(); 408 409 injectEventsSync(mClickList, mServiceInterface, CLICK_SEQUENCE); 410 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 411 412 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false); 413 verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 414 assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); 415 assertThat(mCaptor1.getAllValues().get(1), mIsLineMiddle); 416 assertThat(mCaptor1.getAllValues().get(2), mIsLineEnd); 417 assertThat(mCaptor1.getAllValues().get(3), mIsClickDown); 418 } 419 420 @Test testContinuedGesture_continuationArrivesAfterDispatched_gestureCompletes()421 public void testContinuedGesture_continuationArrivesAfterDispatched_gestureCompletes() 422 throws Exception { 423 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 424 injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 425 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 426 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true); 427 injectEventsSync(mContinuedLineList2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2); 428 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 429 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, true); 430 verify(next, times(5)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 431 List<MotionEvent> events = mCaptor1.getAllValues(); 432 long downTime = events.get(0).getDownTime(); 433 assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN, 434 hasEventTime(downTime))); 435 assertThat(events, everyItem(hasDownTime(downTime))); 436 assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE, 437 hasEventTime(downTime + CONTINUED_LINE_INTERVAL))); 438 // Timing will restart when the gesture continues 439 long secondSequenceStart = events.get(2).getEventTime(); 440 assertTrue(secondSequenceStart >= events.get(1).getEventTime()); 441 assertThat(events.get(2), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_MOVE)); 442 assertThat(events.get(3), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_MOVE, 443 hasEventTime(secondSequenceStart + CONTINUED_LINE_INTERVAL))); 444 assertThat(events.get(4), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_UP, 445 hasEventTime(secondSequenceStart + CONTINUED_LINE_INTERVAL))); 446 } 447 448 @Test testContinuedGesture_withTwoTouchPoints_gestureCompletes()449 public void testContinuedGesture_withTwoTouchPoints_gestureCompletes() 450 throws Exception { 451 // Run one point through the continued line backwards 452 int backLineId1 = 30; 453 int backLineId2 = 30; 454 List<GestureStep> continuedBackLineList1 = createSimpleGestureFromPoints(backLineId1, 0, 455 true, CONTINUED_LINE_INTERVAL, CONTINUED_LINE_END, CONTINUED_LINE_MID2); 456 List<GestureStep> continuedBackLineList2 = createSimpleGestureFromPoints(backLineId2, 457 backLineId1, false, CONTINUED_LINE_INTERVAL, CONTINUED_LINE_MID2, 458 CONTINUED_LINE_MID1, CONTINUED_LINE_START); 459 List<GestureStep> combinedLines1 = combineGestureSteps( 460 mContinuedLineList1, continuedBackLineList1); 461 List<GestureStep> combinedLines2 = combineGestureSteps( 462 mContinuedLineList2, continuedBackLineList2); 463 464 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 465 injectEventsSync(combinedLines1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 466 injectEventsSync(combinedLines2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2); 467 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 468 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true); 469 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, true); 470 verify(next, times(7)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 471 List<MotionEvent> events = mCaptor1.getAllValues(); 472 long downTime = events.get(0).getDownTime(); 473 assertThat(events.get(0), allOf( 474 anyOf(isAtPoint(CONTINUED_LINE_END), isAtPoint(CONTINUED_LINE_START)), 475 IS_ACTION_DOWN, hasEventTime(downTime))); 476 assertThat(events, everyItem(hasDownTime(downTime))); 477 assertThat(events.get(1), allOf(containsPoints(CONTINUED_LINE_START, CONTINUED_LINE_END), 478 IS_ACTION_POINTER_DOWN, hasEventTime(downTime))); 479 assertThat(events.get(2), allOf(containsPoints(CONTINUED_LINE_MID1, CONTINUED_LINE_MID2), 480 IS_ACTION_MOVE, hasEventTime(downTime + CONTINUED_LINE_INTERVAL))); 481 assertThat(events.get(3), allOf(containsPoints(CONTINUED_LINE_MID1, CONTINUED_LINE_MID2), 482 IS_ACTION_MOVE, hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 2))); 483 assertThat(events.get(4), allOf(containsPoints(CONTINUED_LINE_START, CONTINUED_LINE_END), 484 IS_ACTION_MOVE, hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3))); 485 assertThat(events.get(5), allOf(containsPoints(CONTINUED_LINE_START, CONTINUED_LINE_END), 486 IS_ACTION_POINTER_UP, hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3))); 487 assertThat(events.get(6), allOf( 488 anyOf(isAtPoint(CONTINUED_LINE_END), isAtPoint(CONTINUED_LINE_START)), 489 IS_ACTION_UP, hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3))); 490 } 491 492 493 @Test testContinuedGesture_continuationArrivesWhileDispatching_gestureCompletes()494 public void testContinuedGesture_continuationArrivesWhileDispatching_gestureCompletes() 495 throws Exception { 496 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 497 injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 498 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 499 injectEventsSync(mContinuedLineList2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2); 500 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 501 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true); 502 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, true); 503 verify(next, times(5)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 504 List<MotionEvent> events = mCaptor1.getAllValues(); 505 long downTime = events.get(0).getDownTime(); 506 assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN, 507 hasEventTime(downTime))); 508 assertThat(events, everyItem(hasDownTime(downTime))); 509 assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE, 510 hasEventTime(downTime + CONTINUED_LINE_INTERVAL))); 511 assertThat(events.get(2), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_MOVE, 512 hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 2))); 513 assertThat(events.get(3), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_MOVE, 514 hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3))); 515 assertThat(events.get(4), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_UP, 516 hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3))); 517 } 518 519 @Test testContinuedGesture_twoContinuationsArriveWhileDispatching_gestureCompletes()520 public void testContinuedGesture_twoContinuationsArriveWhileDispatching_gestureCompletes() 521 throws Exception { 522 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 523 injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 524 // Continue line again 525 List<GestureStep> continuedLineList2 = createSimpleGestureFromPoints( 526 CONTINUED_LINE_STROKE_ID_2, CONTINUED_LINE_STROKE_ID_1, true, 527 CONTINUED_LINE_INTERVAL, CONTINUED_LINE_MID1, 528 CONTINUED_LINE_MID2, CONTINUED_LINE_END); 529 // Finish line by backtracking 530 int strokeId3 = CONTINUED_LINE_STROKE_ID_2 + 1; 531 int sequence3 = CONTINUED_LINE_SEQUENCE_2 + 1; 532 List<GestureStep> continuedLineList3 = createSimpleGestureFromPoints(strokeId3, 533 CONTINUED_LINE_STROKE_ID_2, false, CONTINUED_LINE_INTERVAL, CONTINUED_LINE_END, 534 CONTINUED_LINE_MID2); 535 536 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 537 injectEventsSync(continuedLineList2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2); 538 injectEventsSync(continuedLineList3, mServiceInterface, sequence3); 539 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 540 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true); 541 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, true); 542 verify(mServiceInterface).onPerformGestureResult(sequence3, true); 543 verify(next, times(6)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 544 List<MotionEvent> events = mCaptor1.getAllValues(); 545 long downTime = events.get(0).getDownTime(); 546 assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN, 547 hasEventTime(downTime))); 548 assertThat(events, everyItem(hasDownTime(downTime))); 549 assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE, 550 hasEventTime(downTime + CONTINUED_LINE_INTERVAL))); 551 assertThat(events.get(2), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_MOVE, 552 hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 2))); 553 assertThat(events.get(3), allOf(isAtPoint(CONTINUED_LINE_END), IS_ACTION_MOVE, 554 hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 3))); 555 assertThat(events.get(4), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_MOVE, 556 hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 4))); 557 assertThat(events.get(5), allOf(isAtPoint(CONTINUED_LINE_MID2), IS_ACTION_UP, 558 hasEventTime(downTime + CONTINUED_LINE_INTERVAL * 4))); 559 } 560 561 @Test testContinuedGesture_nonContinuingGestureArrivesDuringDispatch_gestureCanceled()562 public void testContinuedGesture_nonContinuingGestureArrivesDuringDispatch_gestureCanceled() 563 throws Exception { 564 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 565 injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 566 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 567 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 568 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 569 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, false); 570 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); 571 verify(next, times(5)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 572 List<MotionEvent> events = mCaptor1.getAllValues(); 573 assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN)); 574 assertThat(events.get(1), IS_ACTION_CANCEL); 575 assertThat(events.get(2), allOf(isAtPoint(LINE_START), IS_ACTION_DOWN)); 576 assertThat(events.get(3), allOf(isAtPoint(LINE_END), IS_ACTION_MOVE)); 577 assertThat(events.get(4), allOf(isAtPoint(LINE_END), IS_ACTION_UP)); 578 } 579 580 @Test testContinuedGesture_nonContinuingGestureArrivesAfterDispatch_gestureCanceled()581 public void testContinuedGesture_nonContinuingGestureArrivesAfterDispatch_gestureCanceled() 582 throws Exception { 583 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 584 injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 585 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 586 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 587 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 588 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true); 589 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); 590 verify(next, times(6)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 591 List<MotionEvent> events = mCaptor1.getAllValues(); 592 assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN)); 593 assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE)); 594 assertThat(events.get(2), IS_ACTION_CANCEL); 595 assertThat(events.get(3), allOf(isAtPoint(LINE_START), IS_ACTION_DOWN)); 596 assertThat(events.get(4), allOf(isAtPoint(LINE_END), IS_ACTION_MOVE)); 597 assertThat(events.get(5), allOf(isAtPoint(LINE_END), IS_ACTION_UP)); 598 } 599 600 @Test testContinuedGesture_misMatchedContinuationArrives_bothGesturesCanceled()601 public void testContinuedGesture_misMatchedContinuationArrives_bothGesturesCanceled() 602 throws Exception { 603 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 604 injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 605 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 606 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true); 607 List<GestureStep> discontinuousGesture = mContinuedLineList2 608 .subList(1, mContinuedLineList2.size()); 609 injectEventsSync(discontinuousGesture, mServiceInterface, CONTINUED_LINE_SEQUENCE_2); 610 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 611 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, false); 612 verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 613 List<MotionEvent> events = mCaptor1.getAllValues(); 614 assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN)); 615 assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE)); 616 assertThat(events.get(2), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_CANCEL)); 617 } 618 619 @Test testContinuedGesture_continuationArrivesFromOtherService_bothGesturesCanceled()620 public void testContinuedGesture_continuationArrivesFromOtherService_bothGesturesCanceled() 621 throws Exception { 622 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 623 IAccessibilityServiceClient otherService = mock(IAccessibilityServiceClient.class); 624 injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 625 mMessageCapturingHandler.sendOneMessage(); // Send a motion events 626 injectEventsSync(mContinuedLineList2, otherService, CONTINUED_LINE_SEQUENCE_2); 627 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 628 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, false); 629 verify(otherService).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, false); 630 verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 631 List<MotionEvent> events = mCaptor1.getAllValues(); 632 assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN)); 633 assertThat(events.get(1), IS_ACTION_CANCEL); 634 } 635 636 @Test testContinuedGesture_realGestureArrivesInBetween_getsCanceled()637 public void testContinuedGesture_realGestureArrivesInBetween_getsCanceled() 638 throws Exception { 639 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 640 injectEventsSync(mContinuedLineList1, mServiceInterface, CONTINUED_LINE_SEQUENCE_1); 641 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 642 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_1, true); 643 644 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 645 646 injectEventsSync(mContinuedLineList2, mServiceInterface, CONTINUED_LINE_SEQUENCE_2); 647 mMessageCapturingHandler.sendAllMessages(); // Send all motion events 648 verify(mServiceInterface).onPerformGestureResult(CONTINUED_LINE_SEQUENCE_2, false); 649 verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 650 List<MotionEvent> events = mCaptor1.getAllValues(); 651 assertThat(events.get(0), allOf(isAtPoint(CONTINUED_LINE_START), IS_ACTION_DOWN)); 652 assertThat(events.get(1), allOf(isAtPoint(CONTINUED_LINE_MID1), IS_ACTION_MOVE)); 653 assertThat(events.get(2), IS_ACTION_CANCEL); 654 assertThat(events.get(3), allOf(isAtPoint(CLICK_POINT), IS_ACTION_DOWN)); 655 } 656 657 @Test testClearEvents_realGestureInProgress_shouldForgetAboutGesture()658 public void testClearEvents_realGestureInProgress_shouldForgetAboutGesture() { 659 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 660 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 661 mMotionEventInjector.clearEvents(MOTION_EVENT_SOURCE); 662 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 663 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 664 665 verify(next, times(2)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 666 assertThat(mCaptor1.getAllValues().get(0), mIsClickDown); 667 assertThat(mCaptor1.getAllValues().get(1), mIsLineStart); 668 } 669 670 @Test testClearEventsOnOtherSource_realGestureInProgress_shouldNotForgetAboutGesture()671 public void testClearEventsOnOtherSource_realGestureInProgress_shouldNotForgetAboutGesture() { 672 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 673 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 674 mMotionEventInjector.clearEvents(OTHER_EVENT_SOURCE); 675 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 676 mMessageCapturingHandler.sendOneMessage(); // Send a motion event 677 678 verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); 679 assertThat(mCaptor1.getAllValues().get(0), mIsClickDown); 680 assertThat(mCaptor1.getAllValues().get(1), IS_ACTION_CANCEL); 681 assertThat(mCaptor1.getAllValues().get(2), mIsLineStart); 682 } 683 684 @Test testOnDestroy_shouldCancelGestures()685 public void testOnDestroy_shouldCancelGestures() throws RemoteException { 686 mMotionEventInjector.onDestroy(); 687 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 688 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false); 689 } 690 691 @Test testInjectEvents_withNoNext_shouldCancel()692 public void testInjectEvents_withNoNext_shouldCancel() throws RemoteException { 693 injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); 694 verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false); 695 } 696 697 @Test testOnMotionEvent_withNoNext_shouldNotCrash()698 public void testOnMotionEvent_withNoNext_shouldNotCrash() { 699 mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); 700 } 701 702 @Test testOnKeyEvent_shouldPassToNext()703 public void testOnKeyEvent_shouldPassToNext() { 704 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 705 KeyEvent event = new KeyEvent(0, 0); 706 mMotionEventInjector.onKeyEvent(event, 0); 707 verify(next).onKeyEvent(event, 0); 708 } 709 710 @Test testOnKeyEvent_withNoNext_shouldNotCrash()711 public void testOnKeyEvent_withNoNext_shouldNotCrash() { 712 KeyEvent event = new KeyEvent(0, 0); 713 mMotionEventInjector.onKeyEvent(event, 0); 714 } 715 716 @Test testOnAccessibilityEvent_shouldPassToNext()717 public void testOnAccessibilityEvent_shouldPassToNext() { 718 EventStreamTransformation next = attachMockNext(mMotionEventInjector); 719 AccessibilityEvent event = AccessibilityEvent.obtain(); 720 mMotionEventInjector.onAccessibilityEvent(event); 721 verify(next).onAccessibilityEvent(event); 722 } 723 724 @Test testOnAccessibilityEvent_withNoNext_shouldNotCrash()725 public void testOnAccessibilityEvent_withNoNext_shouldNotCrash() { 726 AccessibilityEvent event = AccessibilityEvent.obtain(); 727 mMotionEventInjector.onAccessibilityEvent(event); 728 } 729 injectEventsSync(List<GestureStep> gestureSteps, IAccessibilityServiceClient serviceInterface, int sequence)730 private void injectEventsSync(List<GestureStep> gestureSteps, 731 IAccessibilityServiceClient serviceInterface, int sequence) { 732 mMotionEventInjector.injectEvents(gestureSteps, serviceInterface, sequence, 733 Display.DEFAULT_DISPLAY); 734 // Dispatch the message sent by the injector. Our simple handler doesn't guarantee stuff 735 // happens in order. 736 mMessageCapturingHandler.sendLastMessage(); 737 } 738 createSimpleGestureFromPoints(int strokeId, int continuedStrokeId, boolean continued, long interval, Point... points)739 private List<GestureStep> createSimpleGestureFromPoints(int strokeId, int continuedStrokeId, 740 boolean continued, long interval, Point... points) { 741 List<GestureStep> gesture = new ArrayList<>(points.length); 742 TouchPoint[] touchPoints = new TouchPoint[1]; 743 touchPoints[0] = new TouchPoint(); 744 for (int i = 0; i < points.length; i++) { 745 touchPoints[0].mX = points[i].x; 746 touchPoints[0].mY = points[i].y; 747 touchPoints[0].mIsStartOfPath = ((i == 0) && (continuedStrokeId <= 0)); 748 touchPoints[0].mContinuedStrokeId = continuedStrokeId; 749 touchPoints[0].mStrokeId = strokeId; 750 touchPoints[0].mIsEndOfPath = ((i == points.length - 1) && !continued); 751 gesture.add(new GestureStep(interval * i, 1, touchPoints)); 752 } 753 return gesture; 754 } 755 combineGestureSteps(List<GestureStep> list1, List<GestureStep> list2)756 List<GestureStep> combineGestureSteps(List<GestureStep> list1, List<GestureStep> list2) { 757 assertEquals(list1.size(), list2.size()); 758 List<GestureStep> gesture = new ArrayList<>(list1.size()); 759 for (int i = 0; i < list1.size(); i++) { 760 int numPoints1 = list1.get(i).numTouchPoints; 761 int numPoints2 = list2.get(i).numTouchPoints; 762 TouchPoint[] touchPoints = new TouchPoint[numPoints1 + numPoints2]; 763 for (int j = 0; j < numPoints1; j++) { 764 touchPoints[j] = new TouchPoint(); 765 touchPoints[j].copyFrom(list1.get(i).touchPoints[j]); 766 } 767 for (int j = 0; j < numPoints2; j++) { 768 touchPoints[numPoints1 + j] = new TouchPoint(); 769 touchPoints[numPoints1 + j].copyFrom(list2.get(i).touchPoints[j]); 770 } 771 gesture.add(new GestureStep(list1.get(i).timeSinceGestureStart, 772 numPoints1 + numPoints2, touchPoints)); 773 } 774 return gesture; 775 } 776 attachMockNext(MotionEventInjector motionEventInjector)777 private EventStreamTransformation attachMockNext(MotionEventInjector motionEventInjector) { 778 EventStreamTransformation next = mock(EventStreamTransformation.class); 779 motionEventInjector.setNext(next); 780 return next; 781 } 782 783 private static class MotionEventActionMatcher extends TypeSafeMatcher<MotionEvent> { 784 int mAction; 785 MotionEventActionMatcher(int action)786 MotionEventActionMatcher(int action) { 787 super(); 788 mAction = action; 789 } 790 791 @Override matchesSafely(MotionEvent motionEvent)792 protected boolean matchesSafely(MotionEvent motionEvent) { 793 return motionEvent.getActionMasked() == mAction; 794 } 795 796 @Override describeTo(Description description)797 public void describeTo(Description description) { 798 description.appendText("Matching to action " + mAction); 799 } 800 } 801 isAtPoint(final Point point)802 private static TypeSafeMatcher<MotionEvent> isAtPoint(final Point point) { 803 return new TypeSafeMatcher<MotionEvent>() { 804 @Override 805 protected boolean matchesSafely(MotionEvent event) { 806 return ((event.getX() == point.x) && (event.getY() == point.y)); 807 } 808 809 @Override 810 public void describeTo(Description description) { 811 description.appendText("Is at point " + point); 812 } 813 }; 814 } 815 816 private static TypeSafeMatcher<MotionEvent> containsPoints(final Point... points) { 817 return new TypeSafeMatcher<MotionEvent>() { 818 @Override 819 protected boolean matchesSafely(MotionEvent event) { 820 MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords(); 821 for (int i = 0; i < points.length; i++) { 822 boolean havePoint = false; 823 for (int j = 0; j < points.length; j++) { 824 event.getPointerCoords(j, coords); 825 if ((points[i].x == coords.x) && (points[i].y == coords.y)) { 826 havePoint = true; 827 } 828 } 829 if (!havePoint) { 830 return false; 831 } 832 } 833 return true; 834 } 835 836 @Override 837 public void describeTo(Description description) { 838 description.appendText("Contains points " + points); 839 } 840 }; 841 } 842 843 private static TypeSafeMatcher<MotionEvent> hasDownTime(final long downTime) { 844 return new TypeSafeMatcher<MotionEvent>() { 845 @Override 846 protected boolean matchesSafely(MotionEvent event) { 847 return event.getDownTime() == downTime; 848 } 849 850 @Override 851 public void describeTo(Description description) { 852 description.appendText("Down time = " + downTime); 853 } 854 }; 855 } 856 857 private static TypeSafeMatcher<MotionEvent> hasEventTime(final long eventTime) { 858 return new TypeSafeMatcher<MotionEvent>() { 859 @Override 860 protected boolean matchesSafely(MotionEvent event) { 861 return event.getEventTime() == eventTime; 862 } 863 864 @Override 865 public void describeTo(Description description) { 866 description.appendText("Event time = " + eventTime); 867 } 868 }; 869 } 870 871 private static TypeSafeMatcher<MotionEvent> hasTimeFromDown(final long timeFromDown) { 872 return new TypeSafeMatcher<MotionEvent>() { 873 @Override 874 protected boolean matchesSafely(MotionEvent event) { 875 return (event.getEventTime() - event.getDownTime()) == timeFromDown; 876 } 877 878 @Override 879 public void describeTo(Description description) { 880 description.appendText("Time from down to event times = " + timeFromDown); 881 } 882 }; 883 } 884 885 private static TypeSafeMatcher<MotionEvent> hasStandardInitialization() { 886 return new TypeSafeMatcher<MotionEvent>() { 887 @Override 888 protected boolean matchesSafely(MotionEvent event) { 889 return (0 == event.getActionIndex()) && (VIRTUAL_KEYBOARD == event.getDeviceId()) 890 && (EDGEFLAGS == event.getEdgeFlags()) && (0 == event.getFlags()) 891 && (METASTATE == event.getMetaState()) && (0F == event.getOrientation()) 892 && (0F == event.getTouchMajor()) && (0F == event.getTouchMinor()) 893 && (X_PRECISION == event.getXPrecision()) 894 && (Y_PRECISION == event.getYPrecision()) 895 && (POINTER_SIZE == event.getSize()) 896 && (1 == event.getPointerCount()) && (PRESSURE == event.getPressure()) 897 && (InputDevice.SOURCE_TOUCHSCREEN == event.getSource()); 898 } 899 900 @Override 901 public void describeTo(Description description) { 902 description.appendText("Has standard values for all parameters"); 903 } 904 }; 905 } 906 } 907