Move pre-check in A11yController to the new A11yWindowManager
Bug: 112046331
Test: a11y CTS & unit tests
Change-Id: If012cb3d9eb1404864a16592d44edbc0893c81b7
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index d6657f1..8415272 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -31,6 +31,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.IWindow;
@@ -83,6 +84,7 @@
mInteractionConnections = new SparseArray<>();
private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>();
+ private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>();
private List<AccessibilityWindowInfo> mWindows;
private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
@@ -173,25 +175,133 @@
}
/**
- * Callbacks from from window manager when there's an accessibility change in windows.
+ * Callbacks from window manager when there's an accessibility change in windows.
*
+ * @param forceSend Send the windows for accessibility even if they haven't changed.
* @param windows The windows of current display for accessibility.
*/
@Override
- public void onWindowsForAccessibilityChanged(@NonNull List<WindowInfo> windows) {
+ public void onWindowsForAccessibilityChanged(boolean forceSend,
+ @NonNull List<WindowInfo> windows) {
synchronized (mLock) {
if (DEBUG) {
Slog.i(LOG_TAG, "Windows changed: " + windows);
}
- // Let the policy update the focused and active windows.
- updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);
-
- // Someone may be waiting for the windows - advertise it.
- mLock.notifyAll();
+ if (shouldUpdateWindowsLocked(forceSend, windows)) {
+ cacheWindows(windows);
+ // Let the policy update the focused and active windows.
+ updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);
+ // Someone may be waiting for the windows - advertise it.
+ mLock.notifyAll();
+ }
}
}
+ private boolean shouldUpdateWindowsLocked(boolean forceSend,
+ @NonNull List<WindowInfo> windows) {
+ if (forceSend) {
+ return true;
+ }
+
+ final int windowCount = windows.size();
+ // We computed the windows and if they changed notify the client.
+ if (mCachedWindowInfos.size() != windowCount) {
+ // Different size means something changed.
+ return true;
+ } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) {
+ // Since we always traverse windows from high to low layer
+ // the old and new windows at the same index should be the
+ // same, otherwise something changed.
+ for (int i = 0; i < windowCount; i++) {
+ WindowInfo oldWindow = mCachedWindowInfos.get(i);
+ WindowInfo newWindow = windows.get(i);
+ // We do not care for layer changes given the window
+ // order does not change. This brings no new information
+ // to the clients.
+ if (windowChangedNoLayer(oldWindow, newWindow)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private void cacheWindows(List<WindowInfo> windows) {
+ final int oldWindowCount = mCachedWindowInfos.size();
+ for (int i = oldWindowCount - 1; i >= 0; i--) {
+ mCachedWindowInfos.remove(i).recycle();
+ }
+ final int newWindowCount = windows.size();
+ for (int i = 0; i < newWindowCount; i++) {
+ WindowInfo newWindow = windows.get(i);
+ mCachedWindowInfos.add(WindowInfo.obtain(newWindow));
+ }
+ }
+
+ private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
+ if (oldWindow == newWindow) {
+ return false;
+ }
+ if (oldWindow == null) {
+ return true;
+ }
+ if (newWindow == null) {
+ return true;
+ }
+ if (oldWindow.type != newWindow.type) {
+ return true;
+ }
+ if (oldWindow.focused != newWindow.focused) {
+ return true;
+ }
+ if (oldWindow.token == null) {
+ if (newWindow.token != null) {
+ return true;
+ }
+ } else if (!oldWindow.token.equals(newWindow.token)) {
+ return true;
+ }
+ if (oldWindow.parentToken == null) {
+ if (newWindow.parentToken != null) {
+ return true;
+ }
+ } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
+ return true;
+ }
+ if (oldWindow.activityToken == null) {
+ if (newWindow.activityToken != null) {
+ return true;
+ }
+ } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) {
+ return true;
+ }
+ if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
+ return true;
+ }
+ if (oldWindow.childTokens != null && newWindow.childTokens != null
+ && !oldWindow.childTokens.equals(newWindow.childTokens)) {
+ return true;
+ }
+ if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
+ return true;
+ }
+ if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
+ return true;
+ }
+ if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) {
+ return true;
+ }
+ if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) {
+ return true;
+ }
+ if (oldWindow.displayId != newWindow.displayId) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Start tracking windows changes from window manager.
*/
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 6b7187e..a2891e9 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -43,9 +43,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.text.TextUtils;
import android.util.ArraySet;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -1036,12 +1034,9 @@
private static final boolean DEBUG = false;
- private final SparseArray<WindowState> mTempWindowStates =
- new SparseArray<WindowState>();
+ private final SparseArray<WindowState> mTempWindowStates = new SparseArray<>();
- private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();
-
- private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
+ private final Set<IBinder> mTempBinderSet = new ArraySet<>();
private final RectF mTempRectF = new RectF();
@@ -1098,8 +1093,7 @@
Slog.i(LOG_TAG, "computeChangedWindows()");
}
- boolean windowsChanged = false;
- List<WindowInfo> windows = new ArrayList<WindowInfo>();
+ List<WindowInfo> windows = new ArrayList<>();
synchronized (mService.mGlobalLock) {
// Do not send the windows if there is no current focus as
@@ -1169,46 +1163,9 @@
visibleWindows.clear();
addedWindows.clear();
-
- if (!forceSend) {
- // We computed the windows and if they changed notify the client.
- if (mOldWindows.size() != windows.size()) {
- // Different size means something changed.
- windowsChanged = true;
- } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
- // Since we always traverse windows from high to low layer
- // the old and new windows at the same index should be the
- // same, otherwise something changed.
- for (int i = 0; i < windowCount; i++) {
- WindowInfo oldWindow = mOldWindows.get(i);
- WindowInfo newWindow = windows.get(i);
- // We do not care for layer changes given the window
- // order does not change. This brings no new information
- // to the clients.
- if (windowChangedNoLayer(oldWindow, newWindow)) {
- windowsChanged = true;
- break;
- }
- }
- }
- }
-
- if (forceSend || windowsChanged) {
- cacheWindows(windows);
- }
}
- // Now we do not hold the lock, so send the windows over.
- if (forceSend || windowsChanged) {
- if (DEBUG) {
- Log.i(LOG_TAG, "Windows changed or force sending:" + windows);
- }
- mCallback.onWindowsForAccessibilityChanged(windows);
- } else {
- if (DEBUG) {
- Log.i(LOG_TAG, "No windows changed.");
- }
- }
+ mCallback.onWindowsForAccessibilityChanged(forceSend, windows);
// Recycle the windows as we do not need them.
clearAndRecycleWindows(windows);
@@ -1313,67 +1270,6 @@
tokenOut.add(window.token);
}
- private void cacheWindows(List<WindowInfo> windows) {
- final int oldWindowCount = mOldWindows.size();
- for (int i = oldWindowCount - 1; i >= 0; i--) {
- mOldWindows.remove(i).recycle();
- }
- final int newWindowCount = windows.size();
- for (int i = 0; i < newWindowCount; i++) {
- WindowInfo newWindow = windows.get(i);
- mOldWindows.add(WindowInfo.obtain(newWindow));
- }
- }
-
- private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
- if (oldWindow == newWindow) {
- return false;
- }
- if (oldWindow == null) {
- return true;
- }
- if (newWindow == null) {
- return true;
- }
- if (oldWindow.type != newWindow.type) {
- return true;
- }
- if (oldWindow.focused != newWindow.focused) {
- return true;
- }
- if (oldWindow.token == null) {
- if (newWindow.token != null) {
- return true;
- }
- } else if (!oldWindow.token.equals(newWindow.token)) {
- return true;
- }
- if (oldWindow.parentToken == null) {
- if (newWindow.parentToken != null) {
- return true;
- }
- } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
- return true;
- }
- if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
- return true;
- }
- if (oldWindow.childTokens != null && newWindow.childTokens != null
- && !oldWindow.childTokens.equals(newWindow.childTokens)) {
- return true;
- }
- if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
- return true;
- }
- if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
- return true;
- }
- if (oldWindow.displayId != newWindow.displayId) {
- return true;
- }
- return false;
- }
-
private static void clearAndRecycleWindows(List<WindowInfo> windows) {
final int windowCount = windows.size();
for (int i = windowCount - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 40bec14..6910ce9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -51,9 +51,10 @@
/**
* Called when the windows for accessibility changed.
*
+ * @param forceSend Send the windows for accessibility even if they haven't changed.
* @param windows The windows for accessibility.
*/
- public void onWindowsForAccessibilityChanged(List<WindowInfo> windows);
+ void onWindowsForAccessibilityChanged(boolean forceSend, List<WindowInfo> windows);
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 04ca40e..22408cc 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -70,6 +70,8 @@
*/
public class AccessibilityWindowManagerTest {
private static final String PACKAGE_NAME = "com.android.server.accessibility";
+ private static final boolean FORCE_SEND = true;
+ private static final boolean SEND_ON_WINDOW_CHANGES = false;
private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
private static final int NUM_GLOBAL_WINDOWS = 4;
private static final int NUM_APP_WINDOWS = 4;
@@ -122,7 +124,7 @@
mWindowInfos.get(DEFAULT_FOCUSED_INDEX).focused = true;
// Turn on windows tracking, and update window info
mA11yWindowManager.startTrackingWindows();
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
assertEquals(mA11yWindowManager.getWindowListLocked().size(),
mWindowInfos.size());
@@ -169,16 +171,16 @@
@Test
public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
- WindowInfo focuedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
+ WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
- USER_SYSTEM_ID, focuedWindowInfo.token));
+ USER_SYSTEM_ID, focusedWindowInfo.token));
- focuedWindowInfo.focused = false;
- focuedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1);
- focuedWindowInfo.focused = true;
+ focusedWindowInfo.focused = false;
+ focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1);
+ focusedWindowInfo.focused = true;
mA11yWindowManager.onTouchInteractionStart();
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
}
@@ -208,6 +210,52 @@
}
@Test
+ public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
+ final WindowInfo windowInfo = mWindowInfos.get(0);
+ final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
+ windowInfo.layer += 1;
+
+ mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
+ assertNotEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
+ }
+
+ @Test
+ public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
+ final WindowInfo windowInfo = mWindowInfos.get(0);
+ final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
+ windowInfo.layer += 1;
+
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+ assertEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
+ }
+
+ @Test
+ public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
+ throws RemoteException {
+ final AccessibilityWindowInfo oldWindow = mA11yWindowManager.getWindowListLocked().get(0);
+ final IWindow token = addAccessibilityInteractionConnection(true);
+ final WindowInfo windowInfo = WindowInfo.obtain();
+ windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
+ windowInfo.token = token.asBinder();
+ windowInfo.layer = 0;
+ windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ mWindowInfos.set(0, windowInfo);
+
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+ assertNotEquals(oldWindow, mA11yWindowManager.getWindowListLocked().get(0));
+ }
+
+ @Test
+ public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
+ final WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
+ final WindowInfo windowInfo = mWindowInfos.get(0);
+ focusedWindowInfo.focused = false;
+ windowInfo.focused = true;
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
+ assertTrue(mA11yWindowManager.getWindowListLocked().get(0).isFocused());
+ }
+
+ @Test
public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
for (int i = 0; i < NUM_OF_WINDOWS; i++) {
final int windowId = mA11yWindowTokens.keyAt(i);
@@ -264,7 +312,7 @@
windowInfo = mWindowInfos.get(1);
windowInfo.boundsInScreen.set(0, SCREEN_HEIGHT / 2,
SCREEN_WIDTH, SCREEN_HEIGHT);
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
@@ -291,7 +339,7 @@
windowInfo = mWindowInfos.get(1);
windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
int windowId = a11yWindows.get(1).getId();
@@ -309,7 +357,7 @@
windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
windowInfo = mWindowInfos.get(1);
windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
final Region outBounds = new Region();
@@ -498,7 +546,7 @@
public void getPictureInPictureWindow_shouldNotNull() {
assertNull(mA11yWindowManager.getPictureInPictureWindow());
mWindowInfos.get(1).inPictureInPicture = true;
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
assertNotNull(mA11yWindowManager.getPictureInPictureWindow());
}
@@ -511,7 +559,7 @@
mA11yWindowManager.getConnectionLocked(
USER_SYSTEM_ID, outsideWindowId).getRemote();
mWindowInfos.get(0).hasFlagWatchOutsideTouch = true;
- mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
+ mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
verify(mockRemoteConnection).notifyOutsideTouch();