From 7cb26674cc6b37e11c4683a82b4674761e90aa94 Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Thu, 7 Apr 2022 12:39:22 -0700 Subject: [PATCH] TouchExplorer: allow service to initiate touch exploration and there are no pointers on the screen We need to be able to initiate touch exploration even if there are no pointers on the screen in order to reliably cover the case where a user just taps the screen. The user expects to hear if they have tapped on anything. Bug: 223673301 Test: manual. Tap on the screen and confirm that talkback reads the item in that position. Change-Id: Id96fa8bd7f000ea153f45024e06915a43ca80826 --- .../TouchInteractionController.java | 12 ++++++------ .../accessibility/gestures/TouchExplorer.java | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 7 deletions(-) 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); + } } }