From e95df8aecba882db24f0442e3f686eee25bdc0d5 Mon Sep 17 00:00:00 2001 From: Jackal Guo Date: Fri, 29 Mar 2019 17:08:39 +0800 Subject: [PATCH] Don't cancel injected event when mouse event arrives Currently, 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. However, if MotionEventInjector keeps sending mouse movement events when gesture is performing, dispatch logic would be confused and it causes the gesture malfunction. Therefore, ignore movement events from mouse when there is an ongoing gesture since click event from mouse should be intended. Bug: 116459737 Test: add a new test case in MotionEventInjectorTest Test: a11y CTS & unit tests Change-Id: I2c2be8cf565ba15d1a9cd6bc8c45b695c1309b56 --- .../accessibility/MotionEventInjector.java | 9 ++++++++ .../MotionEventInjectorTest.java | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java index 46e3226bb751c..7b6a12822faa9 100644 --- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java +++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java @@ -111,6 +111,15 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int 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. + if ((event.isFromSource(InputDevice.SOURCE_MOUSE) + && event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) + && mOpenGesturesInProgress.get(EVENT_SOURCE, false)) { + return; + } cancelAnyPendingInjectedEvents(); sendMotionEventToNext(event, rawEvent, policyFlags); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java index 2cba9d0228664..2977414fb302b 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java @@ -17,6 +17,7 @@ package com.android.server.accessibility; import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_HOVER_MOVE; import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER; @@ -116,6 +117,7 @@ public class MotionEventInjectorTest { MotionEvent mClickDownEvent; MotionEvent mClickUpEvent; + MotionEvent mHoverMoveEvent; ArgumentCaptor mCaptor1 = ArgumentCaptor.forClass(MotionEvent.class); ArgumentCaptor mCaptor2 = ArgumentCaptor.forClass(MotionEvent.class); @@ -152,6 +154,10 @@ public class MotionEventInjectorTest { CLICK_POINT.y, 0); mClickUpEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); + mHoverMoveEvent = MotionEvent.obtain(0, 0, ACTION_HOVER_MOVE, CLICK_POINT.x, CLICK_POINT.y, + 0); + mHoverMoveEvent.setSource(InputDevice.SOURCE_MOUSE); + mIsLineStart = allOf(IS_ACTION_DOWN, isAtPoint(LINE_START), hasStandardInitialization(), hasTimeFromDown(0)); mIsLineMiddle = allOf(IS_ACTION_MOVE, isAtPoint(LINE_END), hasStandardInitialization(), @@ -300,6 +306,23 @@ public class MotionEventInjectorTest { verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, false); } + @Test + public void + testOnMotionEvents_fromMouseWithInjectedGestureInProgress_shouldNotCancelAndPassReal() + throws RemoteException { + EventStreamTransformation next = attachMockNext(mMotionEventInjector); + injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); + mMessageCapturingHandler.sendOneMessage(); // Send a motion event + mMotionEventInjector.onMotionEvent(mHoverMoveEvent, mHoverMoveEvent, 0); + mMessageCapturingHandler.sendAllMessages(); + + verify(next, times(3)).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), anyInt()); + assertThat(mCaptor1.getAllValues().get(0), mIsLineStart); + assertThat(mCaptor1.getAllValues().get(1), mIsLineMiddle); + assertThat(mCaptor1.getAllValues().get(2), mIsLineEnd); + verify(mServiceInterface).onPerformGestureResult(LINE_SEQUENCE, true); + } + @Test public void testOnMotionEvents_closedInjectedGestureInProgress_shouldOnlyNotifyAndPassReal() throws RemoteException {