summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java122
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java112
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java72
4 files changed, 182 insertions, 127 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index d6657f1e637b..841527261e29 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.IBinder;
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 @@ public class AccessibilityWindowManager
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,23 +175,131 @@ public class AccessibilityWindowManager
}
/**
- * 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);
+ 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));
+ }
+ }
- // Someone may be waiting for the windows - advertise it.
- mLock.notifyAll();
+ 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;
}
/**
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 6b7187ebcc01..a2891e97f521 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.Handler;
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 @@ final class AccessibilityController {
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 @@ final class AccessibilityController {
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 @@ final class AccessibilityController {
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 @@ final class AccessibilityController {
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 40bec148b33b..6910ce91cce2 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 @@ public abstract class WindowManagerInternal {
/**
* 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 04ca40e74546..22408cc05b93 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 @@ import java.util.List;
*/
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 @@ public class AccessibilityWindowManagerTest {
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 @@ public class AccessibilityWindowManagerTest {
@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 @@ public class AccessibilityWindowManagerTest {
}
@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 @@ public class AccessibilityWindowManagerTest {
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 @@ public class AccessibilityWindowManagerTest {
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 @@ public class AccessibilityWindowManagerTest {
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 class AccessibilityWindowManagerTest {
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 @@ public class AccessibilityWindowManagerTest {
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();