Loading services/accessibility/accessibility.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,16 @@ flag { } } flag { name: "motion_event_injector_cancel_fix" namespace: "accessibility" description: "Fix the ACTION_CANCEL logic used in MotionEventInjector to avoid InputDispatcher inconsistency" bug: "384451671" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "package_monitor_dedicated_thread" namespace: "accessibility" Loading services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java +41 −28 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.InputDevice; import android.view.KeyCharacterMap; Loading Loading @@ -67,7 +66,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement private static MotionEvent.PointerProperties[] sPointerProps; private final Handler mHandler; private final SparseArray<Boolean> mOpenGesturesInProgress = new SparseArray<>(); private boolean mOpenTouchGestureInProgress = false; private final AccessibilityTraceManager mTrace; private IAccessibilityServiceClient mServiceInterfaceForCurrentGesture; Loading Loading @@ -116,6 +115,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args)); } // Note: MotionEventInjector is the first transformation in the AccessibilityInputFilter stream // so any event that arrives here is a real event from a real user interaction. @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { if (mTrace.isA11yTracingEnabledForTypes( Loading @@ -124,23 +125,31 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement AccessibilityTrace.FLAGS_INPUT_FILTER | AccessibilityTrace.FLAGS_GESTURE, "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); } // MotionEventInjector would cancel any injected gesture when any MotionEvent arrives. // For user using an external device to control the pointer movement, it's almost // impossible to perform the gestures. Any slightly unintended movement results in the // cancellation of the gesture. // InputDispatcher cancels an injected touch gesture if another MotionEvent arrives on this // display from another device or source, like a real touch or a real mouse pointer. // For user using an external device to control the pointer movement, it becomes difficult // to perform injected gestures because slight unintended movement results in cancellation // of the injected gesture; to fix this we swallow real mouse MotionEvents while an injected // touch gesture is in progress, preventing the mouse events from reaching InputDispatcher. if ((event.isFromSource(InputDevice.SOURCE_MOUSE) && event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) && mOpenGesturesInProgress.get(EVENT_SOURCE, false)) { && mOpenTouchGestureInProgress) { return; } if (Flags.motionEventInjectorCancelFix()) { // Pass this real event down the stream unmodified. super.onMotionEvent(event, rawEvent, policyFlags); } else { cancelAnyPendingInjectedEvents(); if (!android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) { if (!android.view.accessibility.Flags .preventA11yNontoolFromInjectingIntoSensitiveViews()) { // Indicate that the input event is injected from accessibility, to let applications // distinguish it from events injected by other means. policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; } sendMotionEventToNext(event, rawEvent, policyFlags); } } @Override public void clearEvents(int inputSource) { Loading @@ -148,8 +157,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement * Reset state for motion events passing through so we won't send a cancel event for * them. */ if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) { mOpenGesturesInProgress.put(inputSource, false); if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT) && inputSource == EVENT_SOURCE) { mOpenTouchGestureInProgress = false; } } Loading Loading @@ -224,8 +233,10 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement } if (!continuingGesture) { cancelAnyPendingInjectedEvents(); if (!Flags.motionEventInjectorCancelFix()) { // Injected gestures have been canceled, but real gestures still need cancelling cancelAnyGestureInProgress(EVENT_SOURCE); cancelInjectedGestureInProgress(); } } mServiceInterfaceForCurrentGesture = serviceInterface; Loading Loading @@ -323,18 +334,20 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement int policyFlags) { if (getNext() != null) { super.onMotionEvent(event, rawEvent, policyFlags); if (event.getSource() == EVENT_SOURCE) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { mOpenGesturesInProgress.put(event.getSource(), true); mOpenTouchGestureInProgress = true; } if ((event.getActionMasked() == MotionEvent.ACTION_UP) || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) { mOpenGesturesInProgress.put(event.getSource(), false); mOpenTouchGestureInProgress = false; } } } } private void cancelAnyGestureInProgress(int source) { if ((getNext() != null) && mOpenGesturesInProgress.get(source, false)) { private void cancelInjectedGestureInProgress() { if ((getNext() != null) && mOpenTouchGestureInProgress) { long now = SystemClock.uptimeMillis(); MotionEvent cancelEvent = obtainMotionEvent(now, now, MotionEvent.ACTION_CANCEL, getLastTouchPoints(), 1); Loading @@ -348,14 +361,14 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL; } sendMotionEventToNext(cancelEvent, cancelEvent, policyFlags); mOpenGesturesInProgress.put(source, false); mOpenTouchGestureInProgress = false; } } private void cancelAnyPendingInjectedEvents() { if (mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) { mHandler.removeMessages(MESSAGE_SEND_MOTION_EVENT); cancelAnyGestureInProgress(EVENT_SOURCE); cancelInjectedGestureInProgress(); for (int i = mSequencesInProgress.size() - 1; i >= 0; i--) { notifyService(mServiceInterfaceForCurrentGesture, mSequencesInProgress.get(i), false); Loading @@ -363,7 +376,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement } } else if (mNumLastTouchPoints != 0) { // An injected gesture is in progress and waiting for a continuation. Cancel it. cancelAnyGestureInProgress(EVENT_SOURCE); cancelInjectedGestureInProgress(); } mNumLastTouchPoints = 0; mStrokeIdToPointerId.clear(); Loading services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +65 −2 Original line number Diff line number Diff line Loading @@ -274,7 +274,10 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS) @DisableFlags({ FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS, Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX }) public void testRegularEvent_afterGestureComplete_shouldPassToNext_withFlagInjectedFromA11y() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); Loading @@ -286,7 +289,10 @@ public class MotionEventInjectorTest { } @Test @EnableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS) @EnableFlags({ FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS, Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX }) public void testRegularEvent_afterGestureComplete_shouldPassToNext_withNoPolicyFlagChanges() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); Loading @@ -299,6 +305,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testInjectEvents_withRealGestureUnderway_shouldCancelRealAndPassInjected() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); Loading @@ -316,6 +323,24 @@ public class MotionEventInjectorTest { | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY)); } @Test @EnableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testInjectEvents_withRealGestureUnderway_shouldNotCancelReal_ShouldPassInjected() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); verify(next, times(1)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); assertThat(mCaptor1.getAllValues().get(0), mIsClickDown); reset(next); mMessageCapturingHandler.sendOneMessage(); // Send a motion event verify(next).onMotionEvent( argThat(mIsLineStart), argThat(mIsLineStart), eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY)); } @Test public void testInjectEvents_withRealMouseGestureUnderway_shouldContinueRealAndPassInjected() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); Loading Loading @@ -354,6 +379,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testOnMotionEvents_openInjectedGestureInProgress_shouldCancelAndNotifyAndPassReal() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); Loading @@ -368,6 +394,24 @@ public class MotionEventInjectorTest { verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false); } @Test @EnableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testOnMotionEvents_openInjectedGestureInProgress_shouldNotCancel_shouldPassReal() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); mMessageCapturingHandler.sendOneMessage(); // Send a motion event mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); mMessageCapturingHandler.sendAllMessages(); verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); assertThat(mCaptor1.getAllValues().get(1), mIsClickDown); assertThat(mCaptor1.getAllValues().get(2), mIsLineMiddle); assertThat(mCaptor1.getAllValues().get(3), mIsLineEnd); verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); } @Test public void testOnMotionEvents_fromMouseWithInjectedGestureInProgress_shouldNotCancelAndPassReal() Loading @@ -386,6 +430,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testOnMotionEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassReal() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); Loading Loading @@ -676,6 +721,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testContinuedGesture_realGestureArrivesInBetween_getsCanceled() throws Exception { EventStreamTransformation next = attachMockNext(mMotionEventInjector); Loading Loading @@ -710,6 +756,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testClearEventsOnOtherSource_realGestureInProgress_shouldNotForgetAboutGesture() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); Loading @@ -723,6 +770,22 @@ public class MotionEventInjectorTest { assertThat(mCaptor1.getAllValues().get(2), mIsLineStart); } @Test @EnableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testClearEventsOnOtherSource_shouldNotCancelRealOrInjectedGesture() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); mMotionEventInjector.clearEvents(OTHER_EVENT_SOURCE); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); mMessageCapturingHandler.sendAllMessages(); verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); assertThat(mCaptor1.getAllValues().get(0), mIsClickDown); assertThat(mCaptor1.getAllValues().get(1), mIsLineStart); assertThat(mCaptor1.getAllValues().get(2), mIsLineMiddle); assertThat(mCaptor1.getAllValues().get(3), mIsLineEnd); } @Test public void testOnDestroy_shouldCancelGestures() throws RemoteException { mMotionEventInjector.onDestroy(); Loading Loading
services/accessibility/accessibility.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -208,6 +208,16 @@ flag { } } flag { name: "motion_event_injector_cancel_fix" namespace: "accessibility" description: "Fix the ACTION_CANCEL logic used in MotionEventInjector to avoid InputDispatcher inconsistency" bug: "384451671" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "package_monitor_dedicated_thread" namespace: "accessibility" Loading
services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java +41 −28 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.InputDevice; import android.view.KeyCharacterMap; Loading Loading @@ -67,7 +66,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement private static MotionEvent.PointerProperties[] sPointerProps; private final Handler mHandler; private final SparseArray<Boolean> mOpenGesturesInProgress = new SparseArray<>(); private boolean mOpenTouchGestureInProgress = false; private final AccessibilityTraceManager mTrace; private IAccessibilityServiceClient mServiceInterfaceForCurrentGesture; Loading Loading @@ -116,6 +115,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args)); } // Note: MotionEventInjector is the first transformation in the AccessibilityInputFilter stream // so any event that arrives here is a real event from a real user interaction. @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { if (mTrace.isA11yTracingEnabledForTypes( Loading @@ -124,23 +125,31 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement AccessibilityTrace.FLAGS_INPUT_FILTER | AccessibilityTrace.FLAGS_GESTURE, "event=" + event + ";rawEvent=" + rawEvent + ";policyFlags=" + policyFlags); } // MotionEventInjector would cancel any injected gesture when any MotionEvent arrives. // For user using an external device to control the pointer movement, it's almost // impossible to perform the gestures. Any slightly unintended movement results in the // cancellation of the gesture. // InputDispatcher cancels an injected touch gesture if another MotionEvent arrives on this // display from another device or source, like a real touch or a real mouse pointer. // For user using an external device to control the pointer movement, it becomes difficult // to perform injected gestures because slight unintended movement results in cancellation // of the injected gesture; to fix this we swallow real mouse MotionEvents while an injected // touch gesture is in progress, preventing the mouse events from reaching InputDispatcher. if ((event.isFromSource(InputDevice.SOURCE_MOUSE) && event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) && mOpenGesturesInProgress.get(EVENT_SOURCE, false)) { && mOpenTouchGestureInProgress) { return; } if (Flags.motionEventInjectorCancelFix()) { // Pass this real event down the stream unmodified. super.onMotionEvent(event, rawEvent, policyFlags); } else { cancelAnyPendingInjectedEvents(); if (!android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) { if (!android.view.accessibility.Flags .preventA11yNontoolFromInjectingIntoSensitiveViews()) { // Indicate that the input event is injected from accessibility, to let applications // distinguish it from events injected by other means. policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; } sendMotionEventToNext(event, rawEvent, policyFlags); } } @Override public void clearEvents(int inputSource) { Loading @@ -148,8 +157,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement * Reset state for motion events passing through so we won't send a cancel event for * them. */ if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) { mOpenGesturesInProgress.put(inputSource, false); if (!mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT) && inputSource == EVENT_SOURCE) { mOpenTouchGestureInProgress = false; } } Loading Loading @@ -224,8 +233,10 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement } if (!continuingGesture) { cancelAnyPendingInjectedEvents(); if (!Flags.motionEventInjectorCancelFix()) { // Injected gestures have been canceled, but real gestures still need cancelling cancelAnyGestureInProgress(EVENT_SOURCE); cancelInjectedGestureInProgress(); } } mServiceInterfaceForCurrentGesture = serviceInterface; Loading Loading @@ -323,18 +334,20 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement int policyFlags) { if (getNext() != null) { super.onMotionEvent(event, rawEvent, policyFlags); if (event.getSource() == EVENT_SOURCE) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { mOpenGesturesInProgress.put(event.getSource(), true); mOpenTouchGestureInProgress = true; } if ((event.getActionMasked() == MotionEvent.ACTION_UP) || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) { mOpenGesturesInProgress.put(event.getSource(), false); mOpenTouchGestureInProgress = false; } } } } private void cancelAnyGestureInProgress(int source) { if ((getNext() != null) && mOpenGesturesInProgress.get(source, false)) { private void cancelInjectedGestureInProgress() { if ((getNext() != null) && mOpenTouchGestureInProgress) { long now = SystemClock.uptimeMillis(); MotionEvent cancelEvent = obtainMotionEvent(now, now, MotionEvent.ACTION_CANCEL, getLastTouchPoints(), 1); Loading @@ -348,14 +361,14 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL; } sendMotionEventToNext(cancelEvent, cancelEvent, policyFlags); mOpenGesturesInProgress.put(source, false); mOpenTouchGestureInProgress = false; } } private void cancelAnyPendingInjectedEvents() { if (mHandler.hasMessages(MESSAGE_SEND_MOTION_EVENT)) { mHandler.removeMessages(MESSAGE_SEND_MOTION_EVENT); cancelAnyGestureInProgress(EVENT_SOURCE); cancelInjectedGestureInProgress(); for (int i = mSequencesInProgress.size() - 1; i >= 0; i--) { notifyService(mServiceInterfaceForCurrentGesture, mSequencesInProgress.get(i), false); Loading @@ -363,7 +376,7 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement } } else if (mNumLastTouchPoints != 0) { // An injected gesture is in progress and waiting for a continuation. Cancel it. cancelAnyGestureInProgress(EVENT_SOURCE); cancelInjectedGestureInProgress(); } mNumLastTouchPoints = 0; mStrokeIdToPointerId.clear(); Loading
services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +65 −2 Original line number Diff line number Diff line Loading @@ -274,7 +274,10 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS) @DisableFlags({ FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS, Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX }) public void testRegularEvent_afterGestureComplete_shouldPassToNext_withFlagInjectedFromA11y() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); Loading @@ -286,7 +289,10 @@ public class MotionEventInjectorTest { } @Test @EnableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS) @EnableFlags({ FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS, Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX }) public void testRegularEvent_afterGestureComplete_shouldPassToNext_withNoPolicyFlagChanges() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); Loading @@ -299,6 +305,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testInjectEvents_withRealGestureUnderway_shouldCancelRealAndPassInjected() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); Loading @@ -316,6 +323,24 @@ public class MotionEventInjectorTest { | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY)); } @Test @EnableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testInjectEvents_withRealGestureUnderway_shouldNotCancelReal_ShouldPassInjected() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); verify(next, times(1)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); assertThat(mCaptor1.getAllValues().get(0), mIsClickDown); reset(next); mMessageCapturingHandler.sendOneMessage(); // Send a motion event verify(next).onMotionEvent( argThat(mIsLineStart), argThat(mIsLineStart), eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY)); } @Test public void testInjectEvents_withRealMouseGestureUnderway_shouldContinueRealAndPassInjected() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); Loading Loading @@ -354,6 +379,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testOnMotionEvents_openInjectedGestureInProgress_shouldCancelAndNotifyAndPassReal() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); Loading @@ -368,6 +394,24 @@ public class MotionEventInjectorTest { verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false); } @Test @EnableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testOnMotionEvents_openInjectedGestureInProgress_shouldNotCancel_shouldPassReal() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); mMessageCapturingHandler.sendOneMessage(); // Send a motion event mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); mMessageCapturingHandler.sendAllMessages(); verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); assertThat(mCaptor1.getAllValues().get(1), mIsClickDown); assertThat(mCaptor1.getAllValues().get(2), mIsLineMiddle); assertThat(mCaptor1.getAllValues().get(3), mIsLineEnd); verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); } @Test public void testOnMotionEvents_fromMouseWithInjectedGestureInProgress_shouldNotCancelAndPassReal() Loading @@ -386,6 +430,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testOnMotionEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassReal() throws RemoteException { EventStreamTransformation next = attachMockNext(mMotionEventInjector); Loading Loading @@ -676,6 +721,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testContinuedGesture_realGestureArrivesInBetween_getsCanceled() throws Exception { EventStreamTransformation next = attachMockNext(mMotionEventInjector); Loading Loading @@ -710,6 +756,7 @@ public class MotionEventInjectorTest { } @Test @DisableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testClearEventsOnOtherSource_realGestureInProgress_shouldNotForgetAboutGesture() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); Loading @@ -723,6 +770,22 @@ public class MotionEventInjectorTest { assertThat(mCaptor1.getAllValues().get(2), mIsLineStart); } @Test @EnableFlags(Flags.FLAG_MOTION_EVENT_INJECTOR_CANCEL_FIX) public void testClearEventsOnOtherSource_shouldNotCancelRealOrInjectedGesture() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); mMotionEventInjector.clearEvents(OTHER_EVENT_SOURCE); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); mMessageCapturingHandler.sendAllMessages(); verify(next, times(4)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); assertThat(mCaptor1.getAllValues().get(0), mIsClickDown); assertThat(mCaptor1.getAllValues().get(1), mIsLineStart); assertThat(mCaptor1.getAllValues().get(2), mIsLineMiddle); assertThat(mCaptor1.getAllValues().get(3), mIsLineEnd); } @Test public void testOnDestroy_shouldCancelGestures() throws RemoteException { mMotionEventInjector.onDestroy(); Loading