summaryrefslogtreecommitdiff
path: root/services/accessibility/java
diff options
context:
space:
mode:
author Daniel Norman <danielnorman@google.com> 2025-02-06 13:20:52 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-06 13:20:52 -0800
commit0c25ba71ed2270681ae337a4aca151f1c3aaa0ad (patch)
tree53638078b40197962e673d2c7afbfb09a94bf9c8 /services/accessibility/java
parentc6c026a76968afdcd3fb5822f8e8384028cd9be9 (diff)
parent614c6be5aea885432f86b9638de15c1f292f6402 (diff)
Merge changes from topic "b384451671" into main
* changes: Removes ACTION_CANCEL which caused InputDispatcher inconsistency. Cleanup mOpenGesturesInProgress to use a simple boolean.
Diffstat (limited to 'services/accessibility/java')
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java69
1 files changed, 41 insertions, 28 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
index b2169535d0de..a7203b0b83f1 100644
--- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -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;
@@ -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;
@@ -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(
@@ -124,22 +125,30 @@ 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;
}
- cancelAnyPendingInjectedEvents();
- 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;
+ if (Flags.motionEventInjectorCancelFix()) {
+ // Pass this real event down the stream unmodified.
+ super.onMotionEvent(event, rawEvent, policyFlags);
+ } else {
+ cancelAnyPendingInjectedEvents();
+ 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);
}
- sendMotionEventToNext(event, rawEvent, policyFlags);
}
@Override
@@ -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;
}
}
@@ -224,8 +233,10 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
}
if (!continuingGesture) {
cancelAnyPendingInjectedEvents();
- // Injected gestures have been canceled, but real gestures still need cancelling
- cancelAnyGestureInProgress(EVENT_SOURCE);
+ if (!Flags.motionEventInjectorCancelFix()) {
+ // Injected gestures have been canceled, but real gestures still need cancelling
+ cancelInjectedGestureInProgress();
+ }
}
mServiceInterfaceForCurrentGesture = serviceInterface;
@@ -323,18 +334,20 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
int policyFlags) {
if (getNext() != null) {
super.onMotionEvent(event, rawEvent, policyFlags);
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mOpenGesturesInProgress.put(event.getSource(), true);
- }
- if ((event.getActionMasked() == MotionEvent.ACTION_UP)
- || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) {
- mOpenGesturesInProgress.put(event.getSource(), false);
+ if (event.getSource() == EVENT_SOURCE) {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mOpenTouchGestureInProgress = true;
+ }
+ if ((event.getActionMasked() == MotionEvent.ACTION_UP)
+ || (event.getActionMasked() == MotionEvent.ACTION_CANCEL)) {
+ 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);
@@ -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);
@@ -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();