summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Phil Weaver <pweaver@google.com> 2017-02-17 14:55:13 -0800
committer Phil Weaver <pweaver@google.com> 2017-02-17 15:07:33 -0800
commit0adfbd33c884ce80ebe161428d7a8ae9e6aced03 (patch)
tree66c0219c0f7ad4786ba1d67bc69db608e9200e79
parentd666953f5767825f0951324a96ea31f7f161f5a8 (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.java51
-rw-r--r--services/accessibility/java/com/android/server/accessibility/TouchExplorer.java8
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);