diff options
author | 2017-02-17 14:55:13 -0800 | |
---|---|---|
committer | 2017-02-17 15:07:33 -0800 | |
commit | 0adfbd33c884ce80ebe161428d7a8ae9e6aced03 (patch) | |
tree | 66c0219c0f7ad4786ba1d67bc69db608e9200e79 | |
parent | d666953f5767825f0951324a96ea31f7f161f5a8 (diff) |
Use accessibility action for touch exploration
Explore-By-Touch has been dispatching touch events to the screen
rather than using the accessibility API. This was intended as a
workaround for apps that did not properly handle accessibility,
but the workaround itself has been causing bugs in corner cases
where properly accessible Views are partially covered by windows.
This CL first tries to dispatch a click action, and falls back on
the touch dispatch only if the click action fails.
Bug: 35200501
Bug: 26216304
Bug: 20665958
Bug: 34949365
Bug: 34844480
Bug: 29535082
Test: Poking around with first party apps and TalkBack works fine.
This behavior isn't covered by automated testing.
Change-Id: I9cc18399d8f40f7381dfcbef91b5991b711bb7f1
-rw-r--r-- | services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java | 51 | ||||
-rw-r--r-- | services/accessibility/java/com/android/server/accessibility/TouchExplorer.java | 8 |
2 files changed, 48 insertions, 11 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index aae5dd83723a..d1042b810c5f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -912,8 +912,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { */ // TODO: (multi-display) Make sure this works for multiple displays. boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { - return getInteractionBridgeLocked() - .getAccessibilityFocusClickPointInScreenNotLocked(outPoint); + return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint); + } + + /** + * Perform an accessibility action on the view that currently has accessibility focus. + * Has no effect if no item has accessibility focus, if the item with accessibility + * focus does not expose the specified action, or if the action fails. + * + * @param actionId The id of the action to perform. + * + * @return {@code true} if the action was performed. {@code false} if it was not. + */ + public boolean performActionOnAccessibilityFocusedItem( + AccessibilityNodeInfo.AccessibilityAction action) { + return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action); } /** @@ -1029,11 +1042,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { onUserStateChangedLocked(userState); } - private InteractionBridge getInteractionBridgeLocked() { - if (mInteractionBridge == null) { - mInteractionBridge = new InteractionBridge(); + private InteractionBridge getInteractionBridge() { + synchronized (mLock) { + if (mInteractionBridge == null) { + mInteractionBridge = new InteractionBridge(); + } + return mInteractionBridge; } - return mInteractionBridge; } private boolean notifyGestureLocked(int gestureId, boolean isDefault) { @@ -2274,11 +2289,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case MSG_CLEAR_ACCESSIBILITY_FOCUS: { final int windowId = msg.arg1; - InteractionBridge bridge; - synchronized (mLock) { - bridge = getInteractionBridgeLocked(); - } - bridge.clearAccessibilityFocusNotLocked(windowId); + getInteractionBridge().clearAccessibilityFocusNotLocked(windowId); } break; case MSG_SEND_SERVICES_STATE_CHANGED_TO_CLIENTS: { @@ -4051,6 +4062,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } + /** + * Perform an accessibility action on the view that currently has accessibility focus. + * Has no effect if no item has accessibility focus, if the item with accessibility + * focus does not expose the specified action, or if the action fails. + * + * @param actionId The id of the action to perform. + * + * @return {@code true} if the action was performed. {@code false} if it was not. + */ + public boolean performActionOnAccessibilityFocusedItemNotLocked( + AccessibilityNodeInfo.AccessibilityAction action) { + AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); + if ((focus == null) || !focus.getActionList().contains(action)) { + return false; + } + return focus.performAction(action.getId()); + } + public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) { AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); if (focus == null) { diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index ecba24501a3e..6e87f88602f1 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java @@ -29,6 +29,7 @@ import android.view.ViewConfiguration; import android.view.WindowManagerPolicy; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityNodeInfo; import java.util.ArrayList; import java.util.Arrays; @@ -407,6 +408,13 @@ class TouchExplorer implements EventStreamTransformation, AccessibilityGestureDe mSendTouchInteractionEndDelayed.forceSendAndRemove(); } + // Try to use the standard accessibility API to click + if (mAms.performActionOnAccessibilityFocusedItem( + AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK)) { + return true; + } + Slog.e(LOG_TAG, "ACTION_CLICK failed. Dispatching motion events to simulate click."); + final int pointerIndex = event.getActionIndex(); final int pointerId = event.getPointerId(pointerIndex); |