diff --git a/core/java/android/accessibilityservice/TouchInteractionController.java b/core/java/android/accessibilityservice/TouchInteractionController.java index 735df805b8726..af00f316de7b6 100644 --- a/core/java/android/accessibilityservice/TouchInteractionController.java +++ b/core/java/android/accessibilityservice/TouchInteractionController.java @@ -262,7 +262,7 @@ public final class TouchInteractionController { * interaction. */ public void requestTouchExploration() { - checkState(); + validateTransitionRequest(); final IAccessibilityServiceConnection connection = AccessibilityInteractionClient.getInstance() .getConnection(mService.getConnectionId()); @@ -288,7 +288,7 @@ public final class TouchInteractionController { * @throws IllegalArgumentException if the pointer id is outside of the allowed range. */ public void requestDragging(int pointerId) { - checkState(); + validateTransitionRequest(); if (pointerId < 0 || pointerId > MAX_POINTER_COUNT) { throw new IllegalArgumentException("Invalid pointer id: " + pointerId); } @@ -313,7 +313,7 @@ public final class TouchInteractionController { * the duration of this interaction. */ public void requestDelegating() { - checkState(); + validateTransitionRequest(); final IAccessibilityServiceConnection connection = AccessibilityInteractionClient.getInstance() .getConnection(mService.getConnectionId()); @@ -371,14 +371,14 @@ public final class TouchInteractionController { } } - private void checkState() { + private void validateTransitionRequest() { if (!mServiceDetectsGestures || mCallbacks.size() == 0) { throw new IllegalStateException( "State transitions are not allowed without first adding a callback."); } - if (mState != STATE_TOUCH_INTERACTING && mState != STATE_DRAGGING) { + if ((mState == STATE_DELEGATING || mState == STATE_TOUCH_EXPLORING)) { throw new IllegalStateException( - "State transitions are not allowed in " + stateToString(mState)); + "State transition requests are not allowed in " + stateToString(mState)); } } 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 6846b2e3e6f73..2cf0e3e54326a 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -1329,13 +1329,28 @@ public class TouchExplorer extends BaseEventStreamTransformation if (mState.isServiceDetectingGestures() && mState.isTouchInteracting()) { // Cancel without deleting events. mHandler.removeCallbacks(mSendHoverEnterAndMoveDelayed); - final int pointerId = mReceivedPointerTracker.getPrimaryPointerId(); + int pointerId = mReceivedPointerTracker.getPrimaryPointerId(); + if (pointerId == INVALID_POINTER_ID) { + MotionEvent event = mState.getLastReceivedEvent(); + if (event != null) { + // Use the first pointer of the most recent event. + pointerId = event.getPointerId(0); + } + } + if (pointerId == INVALID_POINTER_ID) { + Slog.e(LOG_TAG, "Unable to find a valid pointer for touch exploration."); + return; + } final int pointerIdBits = (1 << pointerId); final int policyFlags = mState.getLastReceivedPolicyFlags(); mSendHoverEnterAndMoveDelayed.setPointerIdBits(pointerIdBits); mSendHoverEnterAndMoveDelayed.setPolicyFlags(policyFlags); mSendHoverEnterAndMoveDelayed.run(); mSendHoverEnterAndMoveDelayed.clear(); + if (mReceivedPointerTracker.getReceivedPointerDownCount() == 0) { + // We need to send hover exit because there will be no future ACTION_UP + sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); + } } }