Loading core/java/android/view/accessibility/AccessibilityCache.java +150 −54 Original line number Diff line number Diff line Loading @@ -71,7 +71,9 @@ public class AccessibilityCache { private boolean mIsAllWindowsCached; private final SparseArray<AccessibilityWindowInfo> mWindowCache = // The SparseArray of all {@link AccessibilityWindowInfo}s on all displays. // The key of outer SparseArray is display ID and the key of inner SparseArray is window ID. private final SparseArray<SparseArray<AccessibilityWindowInfo>> mWindowCacheByDisplay = new SparseArray<>(); private final SparseArray<LongSparseArray<AccessibilityNodeInfo>> mNodeCache = Loading @@ -84,34 +86,66 @@ public class AccessibilityCache { mAccessibilityNodeRefresher = nodeRefresher; } public void setWindows(List<AccessibilityWindowInfo> windows) { /** * Sets all {@link AccessibilityWindowInfo}s of all displays into the cache. * The key of SparseArray is display ID. * * @param windowsOnAllDisplays The accessibility windows of all displays. */ public void setWindowsOnAllDisplays( SparseArray<List<AccessibilityWindowInfo>> windowsOnAllDisplays) { synchronized (mLock) { if (DEBUG) { Log.i(LOG_TAG, "Set windows"); } clearWindowCache(); if (windows == null) { clearWindowCacheLocked(); if (windowsOnAllDisplays == null) { return; } final int windowCount = windows.size(); for (int i = 0; i < windowCount; i++) { final AccessibilityWindowInfo window = windows.get(i); addWindow(window); final int displayCounts = windowsOnAllDisplays.size(); for (int i = 0; i < displayCounts; i++) { final List<AccessibilityWindowInfo> windowsOfDisplay = windowsOnAllDisplays.valueAt(i); if (windowsOfDisplay == null) { continue; } final int displayId = windowsOnAllDisplays.keyAt(i); final int windowCount = windowsOfDisplay.size(); for (int j = 0; j < windowCount; j++) { addWindowByDisplayLocked(displayId, windowsOfDisplay.get(j)); } } mIsAllWindowsCached = true; } } /** * Sets an {@link AccessibilityWindowInfo} into the cache. * * @param window The accessibility window. */ public void addWindow(AccessibilityWindowInfo window) { synchronized (mLock) { if (DEBUG) { Log.i(LOG_TAG, "Caching window: " + window.getId()); Log.i(LOG_TAG, "Caching window: " + window.getId() + " at display Id [ " + window.getDisplayId() + " ]"); } final int windowId = window.getId(); mWindowCache.put(windowId, new AccessibilityWindowInfo(window)); addWindowByDisplayLocked(window.getDisplayId(), window); } } private void addWindowByDisplayLocked(int displayId, AccessibilityWindowInfo window) { SparseArray<AccessibilityWindowInfo> windows = mWindowCacheByDisplay.get(displayId); if (windows == null) { windows = new SparseArray<>(); mWindowCacheByDisplay.put(displayId, windows); } final int windowId = window.getId(); windows.put(windowId, new AccessibilityWindowInfo(window)); } /** * Notifies the cache that the something in the UI changed. As a result * the cache will either refresh some nodes or evict some nodes. Loading Loading @@ -236,45 +270,83 @@ public class AccessibilityCache { } } public List<AccessibilityWindowInfo> getWindows() { /** * Gets all {@link AccessibilityWindowInfo}s of all displays from the cache. * * @return All cached {@link AccessibilityWindowInfo}s of all displays * or null if such not found. The key of SparseArray is display ID. */ public SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() { synchronized (mLock) { if (!mIsAllWindowsCached) { return null; } final SparseArray<List<AccessibilityWindowInfo>> returnWindows = new SparseArray<>(); final int displayCounts = mWindowCacheByDisplay.size(); if (displayCounts > 0) { for (int i = 0; i < displayCounts; i++) { final int displayId = mWindowCacheByDisplay.keyAt(i); final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = mWindowCacheByDisplay.valueAt(i); if (windowsOfDisplay == null) { continue; } final int windowCount = mWindowCache.size(); final int windowCount = windowsOfDisplay.size(); if (windowCount > 0) { // Careful to return the windows in a decreasing layer order. SparseArray<AccessibilityWindowInfo> sortedWindows = mTempWindowArray; sortedWindows.clear(); for (int i = 0; i < windowCount; i++) { AccessibilityWindowInfo window = mWindowCache.valueAt(i); for (int j = 0; j < windowCount; j++) { AccessibilityWindowInfo window = windowsOfDisplay.valueAt(j); sortedWindows.put(window.getLayer(), window); } // It's possible in transient conditions for two windows to share the same // layer, which results in sortedWindows being smaller than mWindowCache // layer, which results in sortedWindows being smaller than // mWindowCacheByDisplay final int sortedWindowCount = sortedWindows.size(); List<AccessibilityWindowInfo> windows = new ArrayList<>(sortedWindowCount); for (int i = sortedWindowCount - 1; i >= 0; i--) { AccessibilityWindowInfo window = sortedWindows.valueAt(i); List<AccessibilityWindowInfo> windows = new ArrayList<>(sortedWindowCount); for (int j = sortedWindowCount - 1; j >= 0; j--) { AccessibilityWindowInfo window = sortedWindows.valueAt(j); windows.add(new AccessibilityWindowInfo(window)); sortedWindows.removeAt(i); sortedWindows.removeAt(j); } returnWindows.put(displayId, windows); } return windows; } return returnWindows; } return null; } } /** * Gets an {@link AccessibilityWindowInfo} by windowId. * * @param windowId The id of the window. * * @return The {@link AccessibilityWindowInfo} or null if such not found. */ public AccessibilityWindowInfo getWindow(int windowId) { synchronized (mLock) { AccessibilityWindowInfo window = mWindowCache.get(windowId); final int displayCounts = mWindowCacheByDisplay.size(); for (int i = 0; i < displayCounts; i++) { final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = mWindowCacheByDisplay.valueAt(i); if (windowsOfDisplay == null) { continue; } AccessibilityWindowInfo window = windowsOfDisplay.get(windowId); if (window != null) { return new AccessibilityWindowInfo(window); } } return null; } } Loading Loading @@ -358,7 +430,7 @@ public class AccessibilityCache { if (DEBUG) { Log.i(LOG_TAG, "clear()"); } clearWindowCache(); clearWindowCacheLocked(); final int nodesForWindowCount = mNodeCache.size(); for (int i = nodesForWindowCount - 1; i >= 0; i--) { final int windowId = mNodeCache.keyAt(i); Loading @@ -370,8 +442,23 @@ public class AccessibilityCache { } } private void clearWindowCache() { mWindowCache.clear(); private void clearWindowCacheLocked() { if (DEBUG) { Log.i(LOG_TAG, "clearWindowCacheLocked"); } final int displayCounts = mWindowCacheByDisplay.size(); if (displayCounts > 0) { for (int i = displayCounts - 1; i >= 0; i--) { final int displayId = mWindowCacheByDisplay.keyAt(i); final SparseArray<AccessibilityWindowInfo> windows = mWindowCacheByDisplay.get(displayId); if (windows != null) { windows.clear(); } mWindowCacheByDisplay.remove(displayId); } } mIsAllWindowsCached = false; } Loading Loading @@ -444,16 +531,25 @@ public class AccessibilityCache { public void checkIntegrity() { synchronized (mLock) { // Get the root. if (mWindowCache.size() <= 0 && mNodeCache.size() == 0) { if (mWindowCacheByDisplay.size() <= 0 && mNodeCache.size() == 0) { return; } AccessibilityWindowInfo focusedWindow = null; AccessibilityWindowInfo activeWindow = null; final int windowCount = mWindowCache.size(); for (int i = 0; i < windowCount; i++) { AccessibilityWindowInfo window = mWindowCache.valueAt(i); final int displayCounts = mWindowCacheByDisplay.size(); for (int i = 0; i < displayCounts; i++) { final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = mWindowCacheByDisplay.valueAt(i); if (windowsOfDisplay == null) { continue; } final int windowCount = windowsOfDisplay.size(); for (int j = 0; j < windowCount; j++) { final AccessibilityWindowInfo window = windowsOfDisplay.valueAt(j); // Check for one active window. if (window.isActive()) { Loading @@ -463,7 +559,6 @@ public class AccessibilityCache { activeWindow = window; } } // Check for one focused window. if (window.isFocused()) { if (focusedWindow != null) { Loading @@ -473,6 +568,7 @@ public class AccessibilityCache { } } } } // Traverse the tree and do some checks. AccessibilityNodeInfo accessFocus = null; Loading core/java/android/view/accessibility/AccessibilityInteractionClient.java +9 −4 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.os.SystemClock; import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; Loading Loading @@ -267,12 +268,14 @@ public final class AccessibilityInteractionClient try { IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows(); if (windows != null) { SparseArray<List<AccessibilityWindowInfo>> allWindows = sAccessibilityCache.getWindowsOnAllDisplays(); List<AccessibilityWindowInfo> windows; if (allWindows != null) { if (DEBUG) { Log.i(LOG_TAG, "Windows cache hit"); } return windows; return allWindows.valueAt(Display.DEFAULT_DISPLAY); } if (DEBUG) { Log.i(LOG_TAG, "Windows cache miss"); Loading @@ -284,7 +287,9 @@ public final class AccessibilityInteractionClient Binder.restoreCallingIdentity(identityToken); } if (windows != null) { sAccessibilityCache.setWindows(windows); allWindows = new SparseArray<>(); allWindows.put(Display.DEFAULT_DISPLAY, windows); sAccessibilityCache.setWindowsOnAllDisplays(allWindows); return windows; } } else { Loading core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java +197 −21 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/view/accessibility/AccessibilityCache.java +150 −54 Original line number Diff line number Diff line Loading @@ -71,7 +71,9 @@ public class AccessibilityCache { private boolean mIsAllWindowsCached; private final SparseArray<AccessibilityWindowInfo> mWindowCache = // The SparseArray of all {@link AccessibilityWindowInfo}s on all displays. // The key of outer SparseArray is display ID and the key of inner SparseArray is window ID. private final SparseArray<SparseArray<AccessibilityWindowInfo>> mWindowCacheByDisplay = new SparseArray<>(); private final SparseArray<LongSparseArray<AccessibilityNodeInfo>> mNodeCache = Loading @@ -84,34 +86,66 @@ public class AccessibilityCache { mAccessibilityNodeRefresher = nodeRefresher; } public void setWindows(List<AccessibilityWindowInfo> windows) { /** * Sets all {@link AccessibilityWindowInfo}s of all displays into the cache. * The key of SparseArray is display ID. * * @param windowsOnAllDisplays The accessibility windows of all displays. */ public void setWindowsOnAllDisplays( SparseArray<List<AccessibilityWindowInfo>> windowsOnAllDisplays) { synchronized (mLock) { if (DEBUG) { Log.i(LOG_TAG, "Set windows"); } clearWindowCache(); if (windows == null) { clearWindowCacheLocked(); if (windowsOnAllDisplays == null) { return; } final int windowCount = windows.size(); for (int i = 0; i < windowCount; i++) { final AccessibilityWindowInfo window = windows.get(i); addWindow(window); final int displayCounts = windowsOnAllDisplays.size(); for (int i = 0; i < displayCounts; i++) { final List<AccessibilityWindowInfo> windowsOfDisplay = windowsOnAllDisplays.valueAt(i); if (windowsOfDisplay == null) { continue; } final int displayId = windowsOnAllDisplays.keyAt(i); final int windowCount = windowsOfDisplay.size(); for (int j = 0; j < windowCount; j++) { addWindowByDisplayLocked(displayId, windowsOfDisplay.get(j)); } } mIsAllWindowsCached = true; } } /** * Sets an {@link AccessibilityWindowInfo} into the cache. * * @param window The accessibility window. */ public void addWindow(AccessibilityWindowInfo window) { synchronized (mLock) { if (DEBUG) { Log.i(LOG_TAG, "Caching window: " + window.getId()); Log.i(LOG_TAG, "Caching window: " + window.getId() + " at display Id [ " + window.getDisplayId() + " ]"); } final int windowId = window.getId(); mWindowCache.put(windowId, new AccessibilityWindowInfo(window)); addWindowByDisplayLocked(window.getDisplayId(), window); } } private void addWindowByDisplayLocked(int displayId, AccessibilityWindowInfo window) { SparseArray<AccessibilityWindowInfo> windows = mWindowCacheByDisplay.get(displayId); if (windows == null) { windows = new SparseArray<>(); mWindowCacheByDisplay.put(displayId, windows); } final int windowId = window.getId(); windows.put(windowId, new AccessibilityWindowInfo(window)); } /** * Notifies the cache that the something in the UI changed. As a result * the cache will either refresh some nodes or evict some nodes. Loading Loading @@ -236,45 +270,83 @@ public class AccessibilityCache { } } public List<AccessibilityWindowInfo> getWindows() { /** * Gets all {@link AccessibilityWindowInfo}s of all displays from the cache. * * @return All cached {@link AccessibilityWindowInfo}s of all displays * or null if such not found. The key of SparseArray is display ID. */ public SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() { synchronized (mLock) { if (!mIsAllWindowsCached) { return null; } final SparseArray<List<AccessibilityWindowInfo>> returnWindows = new SparseArray<>(); final int displayCounts = mWindowCacheByDisplay.size(); if (displayCounts > 0) { for (int i = 0; i < displayCounts; i++) { final int displayId = mWindowCacheByDisplay.keyAt(i); final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = mWindowCacheByDisplay.valueAt(i); if (windowsOfDisplay == null) { continue; } final int windowCount = mWindowCache.size(); final int windowCount = windowsOfDisplay.size(); if (windowCount > 0) { // Careful to return the windows in a decreasing layer order. SparseArray<AccessibilityWindowInfo> sortedWindows = mTempWindowArray; sortedWindows.clear(); for (int i = 0; i < windowCount; i++) { AccessibilityWindowInfo window = mWindowCache.valueAt(i); for (int j = 0; j < windowCount; j++) { AccessibilityWindowInfo window = windowsOfDisplay.valueAt(j); sortedWindows.put(window.getLayer(), window); } // It's possible in transient conditions for two windows to share the same // layer, which results in sortedWindows being smaller than mWindowCache // layer, which results in sortedWindows being smaller than // mWindowCacheByDisplay final int sortedWindowCount = sortedWindows.size(); List<AccessibilityWindowInfo> windows = new ArrayList<>(sortedWindowCount); for (int i = sortedWindowCount - 1; i >= 0; i--) { AccessibilityWindowInfo window = sortedWindows.valueAt(i); List<AccessibilityWindowInfo> windows = new ArrayList<>(sortedWindowCount); for (int j = sortedWindowCount - 1; j >= 0; j--) { AccessibilityWindowInfo window = sortedWindows.valueAt(j); windows.add(new AccessibilityWindowInfo(window)); sortedWindows.removeAt(i); sortedWindows.removeAt(j); } returnWindows.put(displayId, windows); } return windows; } return returnWindows; } return null; } } /** * Gets an {@link AccessibilityWindowInfo} by windowId. * * @param windowId The id of the window. * * @return The {@link AccessibilityWindowInfo} or null if such not found. */ public AccessibilityWindowInfo getWindow(int windowId) { synchronized (mLock) { AccessibilityWindowInfo window = mWindowCache.get(windowId); final int displayCounts = mWindowCacheByDisplay.size(); for (int i = 0; i < displayCounts; i++) { final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = mWindowCacheByDisplay.valueAt(i); if (windowsOfDisplay == null) { continue; } AccessibilityWindowInfo window = windowsOfDisplay.get(windowId); if (window != null) { return new AccessibilityWindowInfo(window); } } return null; } } Loading Loading @@ -358,7 +430,7 @@ public class AccessibilityCache { if (DEBUG) { Log.i(LOG_TAG, "clear()"); } clearWindowCache(); clearWindowCacheLocked(); final int nodesForWindowCount = mNodeCache.size(); for (int i = nodesForWindowCount - 1; i >= 0; i--) { final int windowId = mNodeCache.keyAt(i); Loading @@ -370,8 +442,23 @@ public class AccessibilityCache { } } private void clearWindowCache() { mWindowCache.clear(); private void clearWindowCacheLocked() { if (DEBUG) { Log.i(LOG_TAG, "clearWindowCacheLocked"); } final int displayCounts = mWindowCacheByDisplay.size(); if (displayCounts > 0) { for (int i = displayCounts - 1; i >= 0; i--) { final int displayId = mWindowCacheByDisplay.keyAt(i); final SparseArray<AccessibilityWindowInfo> windows = mWindowCacheByDisplay.get(displayId); if (windows != null) { windows.clear(); } mWindowCacheByDisplay.remove(displayId); } } mIsAllWindowsCached = false; } Loading Loading @@ -444,16 +531,25 @@ public class AccessibilityCache { public void checkIntegrity() { synchronized (mLock) { // Get the root. if (mWindowCache.size() <= 0 && mNodeCache.size() == 0) { if (mWindowCacheByDisplay.size() <= 0 && mNodeCache.size() == 0) { return; } AccessibilityWindowInfo focusedWindow = null; AccessibilityWindowInfo activeWindow = null; final int windowCount = mWindowCache.size(); for (int i = 0; i < windowCount; i++) { AccessibilityWindowInfo window = mWindowCache.valueAt(i); final int displayCounts = mWindowCacheByDisplay.size(); for (int i = 0; i < displayCounts; i++) { final SparseArray<AccessibilityWindowInfo> windowsOfDisplay = mWindowCacheByDisplay.valueAt(i); if (windowsOfDisplay == null) { continue; } final int windowCount = windowsOfDisplay.size(); for (int j = 0; j < windowCount; j++) { final AccessibilityWindowInfo window = windowsOfDisplay.valueAt(j); // Check for one active window. if (window.isActive()) { Loading @@ -463,7 +559,6 @@ public class AccessibilityCache { activeWindow = window; } } // Check for one focused window. if (window.isFocused()) { if (focusedWindow != null) { Loading @@ -473,6 +568,7 @@ public class AccessibilityCache { } } } } // Traverse the tree and do some checks. AccessibilityNodeInfo accessFocus = null; Loading
core/java/android/view/accessibility/AccessibilityInteractionClient.java +9 −4 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.os.SystemClock; import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; Loading Loading @@ -267,12 +268,14 @@ public final class AccessibilityInteractionClient try { IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows(); if (windows != null) { SparseArray<List<AccessibilityWindowInfo>> allWindows = sAccessibilityCache.getWindowsOnAllDisplays(); List<AccessibilityWindowInfo> windows; if (allWindows != null) { if (DEBUG) { Log.i(LOG_TAG, "Windows cache hit"); } return windows; return allWindows.valueAt(Display.DEFAULT_DISPLAY); } if (DEBUG) { Log.i(LOG_TAG, "Windows cache miss"); Loading @@ -284,7 +287,9 @@ public final class AccessibilityInteractionClient Binder.restoreCallingIdentity(identityToken); } if (windows != null) { sAccessibilityCache.setWindows(windows); allWindows = new SparseArray<>(); allWindows.put(Display.DEFAULT_DISPLAY, windows); sAccessibilityCache.setWindowsOnAllDisplays(allWindows); return windows; } } else { Loading
core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java +197 −21 File changed.Preview size limit exceeded, changes collapsed. Show changes