diff options
| author | 2025-01-13 23:50:35 +0000 | |
|---|---|---|
| committer | 2025-01-14 20:42:16 +0000 | |
| commit | 3192276a439484d1e7da50aef7ca1a180f78dcd6 (patch) | |
| tree | f6421ab233d424565a51657b5de90307422840c6 | |
| parent | 28cef9b76c59eb2e8dd4b2614a70217608b978fb (diff) | |
Cleanup EventDispatcher#sendMotionEvent callers to provide raw event.
A few releases ago this codebase started tracking the raw (unmodified)
and regular (possibly modified) event separately, but some older
sendMotionEvent callers were not updated to provide the correct
raw event.
This should also help prevent a race condition NPE in
TouchExplorer#sendHoverExitAndTouchExplorationGestureEndIfNeeded:
That method was using the last received *regular* event instead of the
raw event, and this regular event was already cleared from a previous
call to clear() so EventDispatcher#sendMotionEvent was unable to
access the event's attributes. (See linked bug)
Bug: 385812366
Test: atest TouchExplorerTest
Test: atest FrameworksServicesTests:com.android.server.accessibility
Test: Use TalkBack touch exploration, observe no behavior changes
Flag: com.android.server.accessibility.event_dispatcher_raw_event
Change-Id: Ie60f8174de3b12da01987f9bad59669f45bbdfdf
4 files changed, 89 insertions, 9 deletions
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig index 7f0bf0375b4a..722255404dd1 100644 --- a/services/accessibility/accessibility.aconfig +++ b/services/accessibility/accessibility.aconfig @@ -145,6 +145,16 @@ flag { } flag { + name: "event_dispatcher_raw_event" + namespace: "accessibility" + description: "Fixes EventDispatcher#sendMotionEvent callers to properly provide raw event" + bug: "385812366" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "fix_drag_pointer_when_ending_drag" namespace: "accessibility" description: "Send the correct pointer id when transitioning from dragging to delegating states." diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java index bf9202f1b266..5c0bbf4e01eb 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java @@ -31,6 +31,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.EventStreamTransformation; +import com.android.server.accessibility.Flags; import com.android.server.policy.WindowManagerPolicy; /** @@ -297,7 +298,8 @@ class EventDispatcher { sendMotionEvent( prototype, action, - mState.getLastReceivedEvent(), + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } @@ -327,7 +329,8 @@ class EventDispatcher { sendMotionEvent( event, action, - mState.getLastReceivedEvent(), + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } @@ -394,8 +397,10 @@ class EventDispatcher { continue; } final int action = computeInjectionAction(MotionEvent.ACTION_POINTER_UP, i); - sendMotionEvent( - prototype, action, mState.getLastReceivedEvent(), pointerIdBits, policyFlags); + sendMotionEvent(prototype, action, + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), + pointerIdBits, policyFlags); pointerIdBits &= ~(1 << pointerId); } } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 0cbbf6da022b..59e55e5f4b1e 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -506,13 +506,14 @@ public class TouchExplorer extends BaseEventStreamTransformation // We have just decided that the user is touch, // exploring so start sending events. - mSendHoverEnterAndMoveDelayed.addEvent(event, mState.getLastReceivedEvent()); + mSendHoverEnterAndMoveDelayed.addEvent(event, + Flags.eventDispatcherRawEvent() ? rawEvent : mState.getLastReceivedEvent()); mSendHoverEnterAndMoveDelayed.forceSendAndRemove(); mSendHoverExitDelayed.cancel(); mDispatcher.sendMotionEvent( event, ACTION_HOVER_MOVE, - event, + Flags.eventDispatcherRawEvent() ? rawEvent : event, pointerIdBits, policyFlags); return true; @@ -1108,7 +1109,8 @@ public class TouchExplorer extends BaseEventStreamTransformation * * @param policyFlags The policy flags associated with the event. */ - private void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) { + @VisibleForTesting + void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) { MotionEvent event = mState.getLastInjectedHoverEvent(); if (event != null && event.getActionMasked() != ACTION_HOVER_EXIT) { final int pointerIdBits = event.getPointerIdBits(); @@ -1118,7 +1120,8 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher.sendMotionEvent( event, ACTION_HOVER_EXIT, - mState.getLastReceivedEvent(), + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } @@ -1140,7 +1143,8 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher.sendMotionEvent( event, ACTION_HOVER_ENTER, - mState.getLastReceivedEvent(), + Flags.eventDispatcherRawEvent() ? mState.getLastReceivedRawEvent() : + mState.getLastReceivedEvent(), pointerIdBits, policyFlags); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index e5005d1beed4..1af59daa9c78 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -33,6 +33,8 @@ import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGIN import static com.android.server.accessibility.gestures.TouchState.STATE_GESTURE_DETECTING; import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.verify; @@ -132,10 +134,12 @@ public class TouchExplorerTest { */ private class EventCaptor implements EventStreamTransformation { List<MotionEvent> mEvents = new ArrayList<>(); + List<MotionEvent> mRawEvents = new ArrayList<>(); @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { mEvents.add(0, event.copy()); + mRawEvents.add(0, rawEvent.copy()); } @Override @@ -461,6 +465,45 @@ public class TouchExplorerTest { AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN); } + @Test + public void testSendHoverExitIfNeeded_lastSentHoverExit_noActionNeeded() { + // Prep TouchState so that the last injected hover event was a HOVER_EXIT + mTouchExplorer.getState().onInjectedMotionEvent(hoverExitEvent()); + + mTouchExplorer.sendHoverExitAndTouchExplorationGestureEndIfNeeded(/*policyFlags=*/0); + + assertNoCapturedEvents(); + } + + @Test + @EnableFlags(Flags.FLAG_EVENT_DISPATCHER_RAW_EVENT) + public void testSendHoverExitIfNeeded_lastSentHoverEnter_sendsHoverExit_withCorrectRawEvent() { + final MotionEvent rawEvent = downEvent(); + final MotionEvent modifiedEvent = hoverEnterEvent(); + // Use different display IDs just so that we can differentiate between the raw event and + // the modified event later during test assertions. + final int rawDisplayId = 123; + final int modifiedDisplayId = 456; + rawEvent.setDisplayId(rawDisplayId); + modifiedEvent.setDisplayId(modifiedDisplayId); + // Prep TouchState to track the last received modified and raw events + mTouchExplorer.getState().onReceivedMotionEvent(modifiedEvent, rawEvent, /*policyFlags=*/0); + // Prep TouchState so that the last injected hover event was not a HOVER_EXIT + mTouchExplorer.getState().onInjectedMotionEvent(modifiedEvent); + + mTouchExplorer.sendHoverExitAndTouchExplorationGestureEndIfNeeded(/*policyFlags=*/0); + + assertThat(getCapturedEvents().size()).isEqualTo(1); + assertThat(getCapturedRawEvents().size()).isEqualTo(1); + MotionEvent sentEvent = getCapturedEvents().get(0); + MotionEvent sentRawEvent = getCapturedRawEvents().get(0); + // TouchExplorer should send ACTION_HOVER_EXIT built from the last injected hover event + assertThat(sentEvent.getAction()).isEqualTo(ACTION_HOVER_EXIT); + assertThat(sentEvent.getDisplayId()).isEqualTo(modifiedDisplayId); + // ... while passing along the original raw (unmodified) event + assertThat(sentRawEvent.getDisplayId()).isEqualTo(rawDisplayId); + } + /** * Used to play back event data of a gesture by parsing the log into MotionEvents and sending * them to TouchExplorer. @@ -630,6 +673,10 @@ public class TouchExplorerTest { return ((EventCaptor) mCaptor).mEvents; } + private List<MotionEvent> getCapturedRawEvents() { + return ((EventCaptor) mCaptor).mRawEvents; + } + private MotionEvent cancelEvent() { mLastDownTime = SystemClock.uptimeMillis(); return fromTouchscreen( @@ -688,6 +735,20 @@ public class TouchExplorerTest { return event; } + private MotionEvent hoverEnterEvent() { + mLastDownTime = SystemClock.uptimeMillis(); + return fromTouchscreen( + MotionEvent.obtain( + mLastDownTime, mLastDownTime, ACTION_HOVER_ENTER, DEFAULT_X, DEFAULT_Y, 0)); + } + + private MotionEvent hoverExitEvent() { + mLastDownTime = SystemClock.uptimeMillis(); + return fromTouchscreen( + MotionEvent.obtain( + mLastDownTime, mLastDownTime, ACTION_HOVER_EXIT, DEFAULT_X, DEFAULT_Y, 0)); + } + private void moveEachPointers(MotionEvent event, PointF... points) { final float[] x = new float[points.length]; final float[] y = new float[points.length]; |