summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jackal Guo <jackalguo@google.com> 2019-12-13 01:27:08 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-12-13 01:27:08 +0000
commit24ca88cf305068a7133e5b879735a585d977a66d (patch)
treef0b0f065bbbed9e4b92a157892095a14ce858ed8
parent8c56261c297b4bc32be5364ac075bed435188911 (diff)
parent24a1ac51bfd89633798554dc625f1adb181aed34 (diff)
Merge "Don't clear cache when changing accessibility focus"
-rw-r--r--core/java/android/view/accessibility/AccessibilityCache.java58
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java37
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java29
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java16
4 files changed, 126 insertions, 14 deletions
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index dc8bf9b5fbae..9ab2c2b8bcb1 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -69,6 +69,8 @@ public class AccessibilityCache {
private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ private int mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+
private boolean mIsAllWindowsCached;
// The SparseArray of all {@link AccessibilityWindowInfo}s on all displays.
@@ -164,16 +166,19 @@ public class AccessibilityCache {
switch (eventType) {
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
if (mAccessibilityFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
- refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
}
mAccessibilityFocus = event.getSourceNodeId();
- refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ mAccessibilityFocusedWindow = event.getWindowId();
+ refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
} break;
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
- if (mAccessibilityFocus == event.getSourceNodeId()) {
- refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ if (mAccessibilityFocus == event.getSourceNodeId()
+ && mAccessibilityFocusedWindow == event.getWindowId()) {
+ refreshCachedNodeLocked(mAccessibilityFocusedWindow, mAccessibilityFocus);
mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
} break;
@@ -210,6 +215,13 @@ public class AccessibilityCache {
} break;
case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
+ if (event.getWindowChanges()
+ == AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED) {
+ // Don't need to clear all cache. Unless the changes are related to
+ // content, we won't clear all cache here.
+ refreshCachedWindowLocked(event.getWindowId());
+ break;
+ }
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
clear();
} break;
@@ -243,6 +255,34 @@ public class AccessibilityCache {
clearSubTreeLocked(windowId, sourceId);
}
+ private void refreshCachedWindowLocked(int windowId) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Refreshing cached window.");
+ }
+
+ if (windowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
+ return;
+ }
+
+ final int displayCounts = mWindowCacheByDisplay.size();
+ for (int i = 0; i < displayCounts; i++) {
+ final SparseArray<AccessibilityWindowInfo> windowsOfDisplay =
+ mWindowCacheByDisplay.valueAt(i);
+ if (windowsOfDisplay == null) {
+ continue;
+ }
+ final AccessibilityWindowInfo window = windowsOfDisplay.get(windowId);
+ if (window == null) {
+ continue;
+ }
+ if (!mAccessibilityNodeRefresher.refreshWindow(window)) {
+ // If we fail to refresh the window, clear all windows.
+ clearWindowCacheLocked();
+ }
+ return;
+ }
+ }
+
/**
* Gets a cached {@link AccessibilityNodeInfo} given the id of the hosting
* window and the accessibility id of the node.
@@ -413,8 +453,10 @@ public class AccessibilityCache {
refreshCachedNodeLocked(windowId, mAccessibilityFocus);
}
mAccessibilityFocus = sourceId;
+ mAccessibilityFocusedWindow = windowId;
} else if (mAccessibilityFocus == sourceId) {
mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
if (clone.isFocused()) {
mInputFocus = sourceId;
@@ -439,6 +481,8 @@ public class AccessibilityCache {
mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+
+ mAccessibilityFocusedWindow = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
}
}
@@ -653,8 +697,14 @@ public class AccessibilityCache {
// Layer of indirection included to break dependency chain for testing
public static class AccessibilityNodeRefresher {
+ /** Refresh the given AccessibilityNodeInfo object. */
public boolean refreshNode(AccessibilityNodeInfo info, boolean bypassCache) {
return info.refresh(null, bypassCache);
}
+
+ /** Refresh the given AccessibilityWindowInfo object. */
+ public boolean refreshWindow(AccessibilityWindowInfo info) {
+ return info.refresh();
+ }
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index bb10ef10d79e..386651731d45 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -223,19 +223,36 @@ public final class AccessibilityInteractionClient
* @return The {@link AccessibilityWindowInfo}.
*/
public AccessibilityWindowInfo getWindow(int connectionId, int accessibilityWindowId) {
+ return getWindow(connectionId, accessibilityWindowId, /* bypassCache */ false);
+ }
+
+ /**
+ * Gets the info for a window.
+ *
+ * @param connectionId The id of a connection for interacting with the system.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link android.view.accessibility.AccessibilityWindowInfo#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param bypassCache Whether to bypass the cache.
+ * @return The {@link AccessibilityWindowInfo}.
+ */
+ public AccessibilityWindowInfo getWindow(int connectionId, int accessibilityWindowId,
+ boolean bypassCache) {
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
- AccessibilityWindowInfo window = sAccessibilityCache.getWindow(
- accessibilityWindowId);
- if (window != null) {
+ AccessibilityWindowInfo window;
+ if (!bypassCache) {
+ window = sAccessibilityCache.getWindow(accessibilityWindowId);
+ if (window != null) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Window cache hit");
+ }
+ return window;
+ }
if (DEBUG) {
- Log.i(LOG_TAG, "Window cache hit");
+ Log.i(LOG_TAG, "Window cache miss");
}
- return window;
- }
- if (DEBUG) {
- Log.i(LOG_TAG, "Window cache miss");
}
final long identityToken = Binder.clearCallingIdentity();
try {
@@ -244,7 +261,9 @@ public final class AccessibilityInteractionClient
Binder.restoreCallingIdentity(identityToken);
}
if (window != null) {
- sAccessibilityCache.addWindow(window);
+ if (!bypassCache) {
+ sAccessibilityCache.addWindow(window);
+ }
return window;
}
} else {
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 2cc6e9aebd74..ca5c417bdc6d 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -87,6 +87,8 @@ public final class AccessibilityWindowInfo implements Parcelable {
/** @hide */
public static final int ACTIVE_WINDOW_ID = Integer.MAX_VALUE;
/** @hide */
+ public static final int UNDEFINED_CONNECTION_ID = -1;
+ /** @hide */
public static final int UNDEFINED_WINDOW_ID = -1;
/** @hide */
public static final int ANY_WINDOW_ID = -2;
@@ -117,7 +119,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
private CharSequence mTitle;
private long mAnchorId = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
- private int mConnectionId = UNDEFINED_WINDOW_ID;
+ private int mConnectionId = UNDEFINED_CONNECTION_ID;
/**
* Creates a new {@link AccessibilityWindowInfo}.
@@ -539,6 +541,30 @@ public final class AccessibilityWindowInfo implements Parcelable {
}
}
+ /**
+ * Refreshes this window with the latest state of the window it represents.
+ * <p>
+ * <strong>Note:</strong> If this method returns false this info is obsolete
+ * since it represents a window that is no longer exist.
+ * </p>
+ *
+ * @hide
+ */
+ public boolean refresh() {
+ if (mConnectionId == UNDEFINED_CONNECTION_ID || mId == UNDEFINED_WINDOW_ID) {
+ return false;
+ }
+ final AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+ final AccessibilityWindowInfo refreshedInfo = client.getWindow(mConnectionId,
+ mId, /* bypassCache */true);
+ if (refreshedInfo == null) {
+ return false;
+ }
+ init(refreshedInfo);
+ refreshedInfo.recycle();
+ return true;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -586,6 +612,7 @@ public final class AccessibilityWindowInfo implements Parcelable {
mTitle = other.mTitle;
mAnchorId = other.mAnchorId;
+ if (mChildIds != null) mChildIds.clear();
if (other.mChildIds != null && other.mChildIds.size() > 0) {
if (mChildIds == null) {
mChildIds = other.mChildIds.clone();
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index 6bce6517a85d..0d5db6d791f1 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -436,6 +436,22 @@ public class AccessibilityCacheTest {
}
@Test
+ public void windowsChangedWithWindowsChangeA11yFocusedEvent_dontClearCache() {
+ AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1);
+ mAccessibilityCache.add(nodeInfo);
+ AccessibilityEvent event = new AccessibilityEvent(AccessibilityEvent.TYPE_WINDOWS_CHANGED);
+ event.setWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED);
+ mAccessibilityCache.onAccessibilityEvent(event);
+ AccessibilityNodeInfo cachedNode = mAccessibilityCache.getNode(WINDOW_ID_1,
+ nodeInfo.getSourceNodeId());
+ try {
+ assertNotNull(cachedNode);
+ } finally {
+ nodeInfo.recycle();
+ }
+ }
+
+ @Test
public void subTreeChangeEvent_clearsNodeAndChild() {
AccessibilityEvent event = AccessibilityEvent
.obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);