summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorRhed Jao <rhedjao@google.com>2019-01-30 08:01:13 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2019-01-30 08:01:13 +0000
commit098876f547fe9d9f2c7cd6143115b357717b55d1 (patch)
tree6f6414bbc531d4b4f8ed614eb5e24c3a6d987555 /core/java
parent20f1a5d3ab5744fe8bbd75259e8a8e410d385659 (diff)
parent23813d90a51710a8c5e45f0ca36b47057a4b855b (diff)
Merge "Improve clear a11y forcus for A11yManagerService"
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java82
-rw-r--r--core/java/android/view/ViewRootImpl.java9
-rw-r--r--core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl2
3 files changed, 89 insertions, 4 deletions
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index eb41e078e59f..59e562fe8071 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -41,12 +41,14 @@ import android.view.View.AttachInfo;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityRequestPreparer;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
@@ -64,8 +66,11 @@ import java.util.function.Predicate;
* called from the interaction connection ViewAncestor gives the system to
* talk to it and a corresponding *UiThread method that is executed on the
* UI thread.
+ *
+ * @hide
*/
-final class AccessibilityInteractionController {
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class AccessibilityInteractionController {
private static final String LOG_TAG = "AccessibilityInteractionController";
@@ -85,7 +90,7 @@ final class AccessibilityInteractionController {
private final Object mLock = new Object();
- private final Handler mHandler;
+ private final PrivateHandler mHandler;
private final ViewRootImpl mViewRootImpl;
@@ -131,11 +136,19 @@ final class AccessibilityInteractionController {
// thread in this process, set the message as a static reference so
// after this call completes the same thread but in the interrogating
// client can handle the message to generate the result.
- if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
+ if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId
+ && mHandler.hasAccessibilityCallback(message)) {
AccessibilityInteractionClient.getInstanceForThread(
interrogatingTid).setSameThreadMessage(message);
} else {
- mHandler.sendMessage(message);
+ // For messages without callback of interrogating client, just handle the
+ // message immediately if this is UI thread.
+ if (!mHandler.hasAccessibilityCallback(message)
+ && Thread.currentThread().getId() == mMyLooperThreadId) {
+ mHandler.handleMessage(message);
+ } else {
+ mHandler.sendMessage(message);
+ }
}
}
}
@@ -731,6 +744,52 @@ final class AccessibilityInteractionController {
}
}
+ /**
+ * Finds the accessibility focused node in the root, and clears the accessibility focus.
+ */
+ public void clearAccessibilityFocusClientThread() {
+ final Message message = mHandler.obtainMessage();
+ message.what = PrivateHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS;
+
+ // Don't care about pid and tid because there's no interrogating client for this message.
+ scheduleMessage(message, 0, 0, CONSIDER_REQUEST_PREPARERS);
+ }
+
+ private void clearAccessibilityFocusUiThread() {
+ if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+ return;
+ }
+ try {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags =
+ AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+ final View root = mViewRootImpl.mView;
+ if (root != null && isShown(root)) {
+ final View host = mViewRootImpl.mAccessibilityFocusedHost;
+ // If there is no accessibility focus host or it is not a descendant
+ // of the root from which to start the search, then the search failed.
+ if (host == null || !ViewRootImpl.isViewDescendantOf(host, root)) {
+ return;
+ }
+ final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
+ final AccessibilityNodeInfo focusNode =
+ mViewRootImpl.mAccessibilityFocusedVirtualView;
+ if (provider != null && focusNode != null) {
+ final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
+ focusNode.getSourceNodeId());
+ provider.performAction(virtualNodeId,
+ AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(),
+ null);
+ } else {
+ host.performAccessibilityAction(
+ AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(),
+ null);
+ }
+ }
+ } finally {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+ }
+ }
+
private View findViewByAccessibilityId(int accessibilityId) {
View root = mViewRootImpl.mView;
if (root == null) {
@@ -1294,6 +1353,12 @@ final class AccessibilityInteractionController {
private static final int MSG_APP_PREPARATION_FINISHED = 8;
private static final int MSG_APP_PREPARATION_TIMEOUT = 9;
+ // Uses FIRST_NO_ACCESSIBILITY_CALLBACK_MSG for messages that don't need to call back
+ // results to interrogating client.
+ private static final int FIRST_NO_ACCESSIBILITY_CALLBACK_MSG = 100;
+ private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS =
+ FIRST_NO_ACCESSIBILITY_CALLBACK_MSG + 1;
+
public PrivateHandler(Looper looper) {
super(looper);
}
@@ -1320,6 +1385,8 @@ final class AccessibilityInteractionController {
return "MSG_APP_PREPARATION_FINISHED";
case MSG_APP_PREPARATION_TIMEOUT:
return "MSG_APP_PREPARATION_TIMEOUT";
+ case MSG_CLEAR_ACCESSIBILITY_FOCUS:
+ return "MSG_CLEAR_ACCESSIBILITY_FOCUS";
default:
throw new IllegalArgumentException("Unknown message type: " + type);
}
@@ -1356,10 +1423,17 @@ final class AccessibilityInteractionController {
case MSG_APP_PREPARATION_TIMEOUT: {
requestPreparerTimeoutUiThread();
} break;
+ case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
+ clearAccessibilityFocusUiThread();
+ } break;
default:
throw new IllegalArgumentException("Unknown message type: " + type);
}
}
+
+ boolean hasAccessibilityCallback(Message message) {
+ return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false;
+ }
}
private final class AddNodeInfosForViewId implements Predicate<View> {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f47eb10efd29..9213f32326b4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8718,6 +8718,15 @@ public final class ViewRootImpl implements ViewParent,
}
}
}
+
+ @Override
+ public void clearAccessibilityFocus() {
+ ViewRootImpl viewRootImpl = mViewRootImpl.get();
+ if (viewRootImpl != null && viewRootImpl.mView != null) {
+ viewRootImpl.getAccessibilityInteractionController()
+ .clearAccessibilityFocusClientThread();
+ }
+ }
}
private class SendWindowContentChangedAccessibilityEvent implements Runnable {
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index 4c0fdfd5afdf..947ff056627e 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -55,4 +55,6 @@ oneway interface IAccessibilityInteractionConnection {
void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments,
int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid);
+
+ void clearAccessibilityFocus();
}