diff options
7 files changed, 425 insertions, 155 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 135615708037..5a1a8cd91d0d 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -362,8 +362,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ if (!permissionGranted) { return null; } + // TODO [Multi-Display] (b/134891479) : + // using correct display Id to replace DEFAULT_DISPLAY. List<AccessibilityWindowInfo> internalWindowList = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); if (internalWindowList == null) { return null; } @@ -1309,23 +1311,25 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ */ private void ensureWindowsAvailableTimed() { synchronized (mLock) { - if (mA11yWindowManager.getWindowListLocked() != null) { + // TODO [Multi-Display] (b/134891479) : + // using correct display Id to replace DEFAULT_DISPLAY. + if (mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY) != null) { return; } // If we have no registered callback, update the state we // we may have to register one but it didn't happen yet. - if (!mA11yWindowManager.isTrackingWindowsLocked()) { + if (!mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)) { // Invokes client change to make sure tracking window enabled. mSystemSupport.onClientChangeLocked(false); } // We have no windows but do not care about them, done. - if (!mA11yWindowManager.isTrackingWindowsLocked()) { + if (!mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)) { return; } // Wait for the windows with a timeout. final long startMillis = SystemClock.uptimeMillis(); - while (mA11yWindowManager.getWindowListLocked() == null) { + while (mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY) == null) { final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; final long remainMillis = WAIT_WINDOWS_TIMEOUT_MILLIS - elapsedMillis; if (remainMillis <= 0) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 893e4e49020b..ddf5bbec7eb1 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -272,9 +272,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this); mMainHandler = new MainHandler(mContext.getMainLooper()); mGlobalActionPerformer = new GlobalActionPerformer(mContext, mWindowManagerService); - mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler); mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler, mWindowManagerService, this, mSecurityPolicy, this); + mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler); mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager); registerBroadcastReceivers(); @@ -580,9 +580,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub // Make sure clients receiving this event will be able to get the // current state of the windows as the window manager may be delaying // the computation for performance reasons. - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY - if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED - && mA11yWindowManager.isTrackingWindowsLocked()) { + // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY. + boolean shouldComputeWindows = false; + synchronized (mLock) { + if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED + && mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)) { + shouldComputeWindows = true; + } + } + if (shouldComputeWindows) { WindowManagerInternal wm = LocalServices.getService(WindowManagerInternal.class); wm.computeWindowsForAccessibility(Display.DEFAULT_DISPLAY); } @@ -1656,10 +1662,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } - if (observingWindows) { - mA11yWindowManager.startTrackingWindows(); - } else { - mA11yWindowManager.stopTrackingWindows(); + // Gets all valid displays and start tracking windows of each display if there is at least + // one bound service that can retrieve window content. + final ArrayList<Display> displays = getValidDisplayList(); + for (int i = 0; i < displays.size(); i++) { + final Display display = displays.get(i); + if (display != null) { + if (observingWindows) { + mA11yWindowManager.startTrackingWindows(display.getDisplayId()); + } else { + mA11yWindowManager.stopTrackingWindows(display.getDisplayId()); + } + } } } @@ -2559,6 +2573,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } updateMagnificationLocked(userState); + updateWindowsForAccessibilityCallbackLocked(userState); } } @@ -2586,6 +2601,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (mMagnificationController != null) { mMagnificationController.onDisplayRemoved(displayId); } + mA11yWindowManager.stopTrackingWindows(displayId); } @Override diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java index c9efe36b2014..82a593cdfd7f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java @@ -79,16 +79,25 @@ public class AccessibilityWindowManager { private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>(); private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection; - + // There is only one active window in the system. It is updated when the top focused window + // of the top focused display changes and when we receive a TYPE_WINDOW_STATE_CHANGED event. private int mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; - private int mFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + // There is only one top focused window in the system. It is updated when the window manager + // updates the window lists. + private int mTopFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; private int mAccessibilityFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; private long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; + // The top focused display and window token updated with the callback of window lists change. + private int mTopFocusedDisplayId; + private IBinder mTopFocusedWindowToken; + // The display has the accessibility focused window currently. + private int mAccessibilityFocusedDisplayId = Display.INVALID_DISPLAY; private boolean mTouchInteractionInProgress; - // TO-DO [Multi-Display] : make DisplayWindowObserver to plural - private DisplayWindowsObserver mDisplayWindowsObserver; + /** List of Display Windows Observer, mapping from displayId -> DisplayWindowsObserver. */ + private final SparseArray<DisplayWindowsObserver> mDisplayWindowsObservers = + new SparseArray<>(); /** * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to @@ -243,6 +252,7 @@ public class AccessibilityWindowManager { for (int i = 0; i < windowCount; i++) { AccessibilityWindowInfo window = mWindows.get(i); if (window.getId() == windowId) { + mAccessibilityFocusedDisplayId = mDisplayId; window.setAccessibilityFocused(true); mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( AccessibilityEvent.obtainWindowsChangedEvent( @@ -318,17 +328,21 @@ public class AccessibilityWindowManager { * 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 topFocusedDisplayId The display Id which has the top focused window. + * @param topFocusedWindowToken The window token of top focused window. * @param windows The windows for accessibility. */ @Override - public void onWindowsForAccessibilityChanged(boolean forceSend, - @NonNull List<WindowInfo> windows) { + public void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId, + IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows) { synchronized (mLock) { if (DEBUG) { Slog.i(LOG_TAG, "Display Id = " + mDisplayId); Slog.i(LOG_TAG, "Windows changed: " + windows); } if (shouldUpdateWindowsLocked(forceSend, windows)) { + mTopFocusedDisplayId = topFocusedDisplayId; + mTopFocusedWindowToken = topFocusedWindowToken; cacheWindows(windows); // Lets the policy update the focused and active windows. updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), @@ -471,6 +485,7 @@ public class AccessibilityWindowManager { final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows); final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone(); + boolean shouldClearAccessibilityFocus = false; mWindows.clear(); mA11yWindowInfoById.clear(); @@ -480,9 +495,25 @@ public class AccessibilityWindowManager { } mWindowInfoById.clear(); mHasWatchOutsideTouchWindow = false; - mFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; - if (!mTouchInteractionInProgress) { - mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + + final int windowCount = windows.size(); + final boolean isTopFocusedDisplay = mDisplayId == mTopFocusedDisplayId; + final boolean isAccessibilityFocusedDisplay = + mDisplayId == mAccessibilityFocusedDisplayId; + // Modifies the value of top focused window, active window and a11y focused window + // only if this display is top focused display which has the top focused window. + if (isTopFocusedDisplay) { + if (windowCount > 0) { + // Sets the top focus window by top focused window token. + mTopFocusedWindowId = findWindowIdLocked(userId, mTopFocusedWindowToken); + } else { + // Resets the top focus window when stopping tracking window of this display. + mTopFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + } + // The active window doesn't need to be reset if the touch operation is progressing. + if (!mTouchInteractionInProgress) { + mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + } } // If the active window goes away while the user is touch exploring we @@ -492,17 +523,17 @@ public class AccessibilityWindowManager { // filters out such events. boolean activeWindowGone = true; - final int windowCount = windows.size(); - // We'll clear accessibility focus if the window with focus is no longer visible to - // accessibility services - boolean shouldClearAccessibilityFocus = - mAccessibilityFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + // accessibility services. + if (isAccessibilityFocusedDisplay) { + shouldClearAccessibilityFocus = mAccessibilityFocusedWindowId + != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + } if (windowCount > 0) { for (int i = 0; i < windowCount; i++) { final WindowInfo windowInfo = windows.get(i); final AccessibilityWindowInfo window; - if (isTrackingWindowsLocked()) { + if (mTrackingWindows) { window = populateReportedWindowLocked(userId, windowInfo); } else { window = null; @@ -513,9 +544,10 @@ public class AccessibilityWindowManager { window.setLayer(windowCount - 1 - window.getLayer()); final int windowId = window.getId(); - if (window.isFocused()) { - mFocusedWindowId = windowId; + if (window.isFocused() && isTopFocusedDisplay) { if (!mTouchInteractionInProgress) { + // This display is top one, and sets the focus window + // as active window. mActiveWindowId = windowId; window.setActive(true); } else if (windowId == mActiveWindowId) { @@ -530,22 +562,28 @@ public class AccessibilityWindowManager { mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo)); } } - - if (mTouchInteractionInProgress && activeWindowGone) { - mActiveWindowId = mFocusedWindowId; - } - - // Focused window may change the active one, so set the - // active window once we decided which it is. final int accessibilityWindowCount = mWindows.size(); - for (int i = 0; i < accessibilityWindowCount; i++) { - final AccessibilityWindowInfo window = mWindows.get(i); - if (window.getId() == mActiveWindowId) { - window.setActive(true); + if (isTopFocusedDisplay) { + if (mTouchInteractionInProgress && activeWindowGone) { + mActiveWindowId = mTopFocusedWindowId; } - if (window.getId() == mAccessibilityFocusedWindowId) { - window.setAccessibilityFocused(true); - shouldClearAccessibilityFocus = false; + // Focused window may change the active one, so set the + // active window once we decided which it is. + for (int i = 0; i < accessibilityWindowCount; i++) { + final AccessibilityWindowInfo window = mWindows.get(i); + if (window.getId() == mActiveWindowId) { + window.setActive(true); + } + } + } + if (isAccessibilityFocusedDisplay) { + for (int i = 0; i < accessibilityWindowCount; i++) { + final AccessibilityWindowInfo window = mWindows.get(i); + if (window.getId() == mAccessibilityFocusedWindowId) { + window.setAccessibilityFocused(true); + shouldClearAccessibilityFocus = false; + break; + } } } } @@ -788,42 +826,86 @@ public class AccessibilityWindowManager { mAccessibilityEventSender = accessibilityEventSender; mSecurityPolicy = securityPolicy; mAccessibilityUserManager = accessibilityUserManager; - mDisplayWindowsObserver = new DisplayWindowsObserver(Display.DEFAULT_DISPLAY); } /** - * Starts tracking windows changes from window manager. + * Starts tracking windows changes from window manager for specified display. + * + * @param displayId The logical display id. */ - public void startTrackingWindows() { + public void startTrackingWindows(int displayId) { synchronized (mLock) { - mDisplayWindowsObserver.startTrackingWindowsLocked(); + DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); + if (observer == null) { + observer = new DisplayWindowsObserver(displayId); + } + if (observer.isTrackingWindowsLocked()) { + return; + } + if (observer.startTrackingWindowsLocked()) { + mDisplayWindowsObservers.put(displayId, observer); + } } } /** - * Stops tracking windows changes from window manager, and clear all windows info. + * Stops tracking windows changes from window manager, and clear all windows info for specified + * display. + * + * @param displayId The logical display id. */ - public void stopTrackingWindows() { + public void stopTrackingWindows(int displayId) { synchronized (mLock) { - mDisplayWindowsObserver.stopTrackingWindowsLocked(); + final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); + if (observer != null) { + observer.stopTrackingWindowsLocked(); + mDisplayWindowsObservers.remove(displayId); + } } } /** - * Returns true if windows changes tracking. + * Checks if we are tracking windows on any display. * - * @return true if windows changes tracking + * @return {@code true} if the observer is tracking windows on any display, + * {@code false} otherwise. */ public boolean isTrackingWindowsLocked() { - return mDisplayWindowsObserver.isTrackingWindowsLocked(); + final int count = mDisplayWindowsObservers.size(); + if (count > 0) { + return true; + } + return false; } /** - * Returns accessibility windows. + * Checks if we are tracking windows on specified display. + * + * @param displayId The logical display id. + * @return {@code true} if the observer is tracking windows on specified display, + * {@code false} otherwise. + */ + public boolean isTrackingWindowsLocked(int displayId) { + final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); + if (observer != null) { + return observer.isTrackingWindowsLocked(); + } + return false; + } + + /** + * Returns accessibility windows for specified display. + * + * @param displayId The logical display id. + * @return accessibility windows for specified display. */ @Nullable - public List<AccessibilityWindowInfo> getWindowListLocked() { - return mDisplayWindowsObserver.getWindowListLocked(); + public List<AccessibilityWindowInfo> getWindowListLocked(int displayId) { + final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); + if (observer != null) { + return observer.getWindowListLocked(); + } + return null; } /** @@ -841,6 +923,8 @@ public class AccessibilityWindowManager { @NonNull IAccessibilityInteractionConnection connection, @NonNull String packageName, int userId) throws RemoteException { final int windowId; + boolean shouldComputeWindows = false; + final int displayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken.asBinder()); synchronized (mLock) { // We treat calls from a profile as if made by its parent as profiles // share the accessibility state of the parent. The call below @@ -880,9 +964,14 @@ public class AccessibilityWindowManager { + " and token: " + windowToken.asBinder()); } } + + if (isTrackingWindowsLocked(displayId)) { + shouldComputeWindows = true; + } + } + if (shouldComputeWindows) { + mWindowManagerInternal.computeWindowsForAccessibility(displayId); } - // TODO [Multi-Display] : using correct display Id to replace DEFAULT_DISPLAY - mWindowManagerInternal.computeWindowsForAccessibility(Display.DEFAULT_DISPLAY); return windowId; } @@ -1067,8 +1156,12 @@ public class AccessibilityWindowManager { */ public boolean computePartialInteractiveRegionForWindowLocked(int windowId, @NonNull Region outRegion) { - return mDisplayWindowsObserver.computePartialInteractiveRegionForWindowLocked(windowId, - outRegion); + final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId); + if (observer != null) { + return observer.computePartialInteractiveRegionForWindowLocked(windowId, outRegion); + } + + return false; } /** @@ -1101,8 +1194,8 @@ public class AccessibilityWindowManager { // windows are delivered. synchronized (mLock) { if (!isTrackingWindowsLocked()) { - mFocusedWindowId = findFocusedWindowId(userId); - if (windowId == mFocusedWindowId) { + mTopFocusedWindowId = findFocusedWindowId(userId); + if (windowId == mTopFocusedWindowId) { mActiveWindowId = windowId; } } @@ -1140,6 +1233,7 @@ public class AccessibilityWindowManager { && (mAccessibilityFocusedWindowId == windowId) && (eventAction != AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)) { mAccessibilityFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + mAccessibilityFocusedDisplayId = Display.INVALID_DISPLAY; } } } break; @@ -1172,7 +1266,7 @@ public class AccessibilityWindowManager { // the active window before all hover accessibility events from // the touched window are delivered is fine. final int oldActiveWindow = mActiveWindowId; - setActiveWindowLocked(mFocusedWindowId); + setActiveWindowLocked(mTopFocusedWindowId); // If there is no service that can operate with interactive windows // then we keep the old behavior where a window loses accessibility @@ -1212,7 +1306,14 @@ public class AccessibilityWindowManager { mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); mActiveWindowId = windowId; - mDisplayWindowsObserver.setActiveWindowLocked(windowId); + // Goes through all windows for each display. + final int count = mDisplayWindowsObservers.size(); + for (int i = 0; i < count; i++) { + final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); + if (observer != null) { + observer.setActiveWindowLocked(windowId); + } + } } } @@ -1224,7 +1325,14 @@ public class AccessibilityWindowManager { WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); mAccessibilityFocusedWindowId = windowId; - mDisplayWindowsObserver.setAccessibilityFocusedWindowLocked(windowId); + // Goes through all windows for each display. + final int count = mDisplayWindowsObservers.size(); + for (int i = 0; i < count; i++) { + final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); + if (observer != null) { + observer.setAccessibilityFocusedWindowLocked(windowId); + } + } } } @@ -1236,7 +1344,11 @@ public class AccessibilityWindowManager { */ @Nullable public AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) { - return mDisplayWindowsObserver.findA11yWindowInfoByIdLocked(windowId); + final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId); + if (observer != null) { + return observer.findA11yWindowInfoByIdLocked(windowId); + } + return null; } /** @@ -1247,7 +1359,11 @@ public class AccessibilityWindowManager { */ @Nullable public WindowInfo findWindowInfoByIdLocked(int windowId) { - return mDisplayWindowsObserver.findWindowInfoByIdLocked(windowId); + final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId); + if (observer != null) { + return observer.findWindowInfoByIdLocked(windowId); + } + return null; } /** @@ -1259,7 +1375,7 @@ public class AccessibilityWindowManager { */ public int getFocusedWindowId(int focusType) { if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { - return mFocusedWindowId; + return mTopFocusedWindowId; } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { return mAccessibilityFocusedWindowId; } @@ -1273,7 +1389,17 @@ public class AccessibilityWindowManager { */ @Nullable public AccessibilityWindowInfo getPictureInPictureWindowLocked() { - return mDisplayWindowsObserver.getPictureInPictureWindowLocked(); + AccessibilityWindowInfo windowInfo = null; + final int count = mDisplayWindowsObservers.size(); + for (int i = 0; i < count; i++) { + final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); + if (observer != null) { + if ((windowInfo = observer.getPictureInPictureWindowLocked()) != null) { + break; + } + } + } + return windowInfo; } /** @@ -1313,10 +1439,13 @@ public class AccessibilityWindowManager { final List<Integer> outsideWindowsIds; final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>(); synchronized (mLock) { - outsideWindowsIds = - mDisplayWindowsObserver.getWatchOutsideTouchWindowIdLocked(targetWindowId); - for (int i = 0; i < outsideWindowsIds.size(); i++) { - connectionList.add(getConnectionLocked(userId, outsideWindowsIds.get(i))); + final DisplayWindowsObserver observer = + getDisplayWindowObserverByWindowIdLocked(targetWindowId); + if (observer != null) { + outsideWindowsIds = observer.getWatchOutsideTouchWindowIdLocked(targetWindowId); + for (int i = 0; i < outsideWindowsIds.size(); i++) { + connectionList.add(getConnectionLocked(userId, outsideWindowsIds.get(i))); + } } } for (int i = 0; i < connectionList.size(); i++) { @@ -1398,10 +1527,29 @@ public class AccessibilityWindowManager { } } + private DisplayWindowsObserver getDisplayWindowObserverByWindowIdLocked(int windowId) { + final int count = mDisplayWindowsObservers.size(); + for (int i = 0; i < count; i++) { + final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); + if (observer != null) { + if (observer.findWindowInfoByIdLocked(windowId) != null) { + return mDisplayWindowsObservers.get(observer.mDisplayId); + } + } + } + return null; + } + /** * Dumps all {@link AccessibilityWindowInfo}s here. */ public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { - mDisplayWindowsObserver.dumpLocked(fd, pw, args); + final int count = mDisplayWindowsObservers.size(); + for (int i = 0; i < count; i++) { + final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); + if (observer != null) { + observer.dumpLocked(fd, pw, args); + } + } } } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 26ca975bfc8f..30a3aef01fdb 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -124,11 +124,11 @@ final class AccessibilityController { return false; } - final Display display = dc.getDisplay(); if (mWindowsForAccessibilityObserver.get(displayId) != null) { + final Display display = dc.getDisplay(); if (display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null) { // The window observer of this embedded display had been set from - // window manager after setting its parent window + // window manager after setting its parent window. return true; } else { throw new IllegalStateException( @@ -136,9 +136,6 @@ final class AccessibilityController { + displayId + " already set!"); } } - if (display.getType() == Display.TYPE_OVERLAY) { - return false; - } mWindowsForAccessibilityObserver.put(displayId, new WindowsForAccessibilityObserver(mService, displayId, callback)); } else { @@ -287,9 +284,8 @@ final class AccessibilityController { } public boolean hasCallbacksLocked() { - // TODO: support multi-display for windows observer return (mDisplayMagnifiers.size() > 0 - || mWindowsForAccessibilityObserver != null); + || mWindowsForAccessibilityObserver.size() > 0); } public void setForceShowMagnifiableBoundsLocked(int displayId, boolean show) { @@ -1158,15 +1154,15 @@ final class AccessibilityController { } List<WindowInfo> windows = new ArrayList<>(); + final int topFocusedDisplayId; + IBinder topFocusedWindowToken = null; synchronized (mService.mGlobalLock) { - // Do not send the windows if there is no current focus as + // Do not send the windows if there is no top focus as // the window manager is still looking for where to put it. // We will do the work when we get a focus change callback. - // TODO [Multi-Display] : only checks top focused window - if (!isCurrentFocusWindowOnDefaultDisplay()) { - return; - } + final WindowState topFocusedWindowState = getTopFocusWindow(); + if (topFocusedWindowState == null) return; final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId); if (dc == null) { @@ -1229,9 +1225,13 @@ final class AccessibilityController { visibleWindows.clear(); addedWindows.clear(); - } - mCallback.onWindowsForAccessibilityChanged(forceSend, windows); + // Gets the top focused display Id and window token for supporting multi-display. + topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId(); + topFocusedWindowToken = topFocusedWindowState.mClient.asBinder(); + } + mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId, + topFocusedWindowToken, windows); // Recycle the windows as we do not need them. clearAndRecycleWindows(windows); @@ -1410,22 +1410,9 @@ final class AccessibilityController { } return displayParentWindow; } - // TODO [Multi-Display] : only checks top focused window - private boolean isCurrentFocusWindowOnDefaultDisplay() { - final WindowState focusedWindow = - mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus; - if (focusedWindow == null) { - return false; - } - - final WindowState rootDisplayParentWindow = findRootDisplayParentWindow(focusedWindow); - if (!focusedWindow.isDefaultDisplay() - && (rootDisplayParentWindow == null - || !rootDisplayParentWindow.isDefaultDisplay())) { - return false; - } - return true; + private WindowState getTopFocusWindow() { + return mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus; } private class MyHandler extends Handler { diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 05cfbd4e39d9..750926f11180 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -52,9 +52,12 @@ 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 topFocusedDisplayId The display Id which has the top focused window. + * @param topFocusedWindowToken The window token of top focused window. * @param windows The windows for accessibility. */ - void onWindowsForAccessibilityChanged(boolean forceSend, List<WindowInfo> windows); + void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId, + IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows); } /** diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java index 1084d625f8a3..f767598e7791 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -76,6 +76,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.testing.DexmakerShareClassLoaderRule; +import android.view.Display; import android.view.KeyEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; @@ -178,7 +179,8 @@ public class AbstractAccessibilityServiceConnectionTest { // Fake a11yWindowInfo and remote a11y connection for tests. addA11yWindowInfo(mA11yWindowInfos, WINDOWID, false); addA11yWindowInfo(mA11yWindowInfos, PIP_WINDOWID, true); - when(mMockA11yWindowManager.getWindowListLocked()).thenReturn(mA11yWindowInfos); + when(mMockA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)) + .thenReturn(mA11yWindowInfos); when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(WINDOWID)) .thenReturn(mA11yWindowInfos.get(0)); when(mMockA11yWindowManager.findA11yWindowInfoByIdLocked(PIP_WINDOWID)) @@ -289,8 +291,9 @@ public class AbstractAccessibilityServiceConnectionTest { @Test public void getWindows_notTrackingWindows_invokeOnClientChange() { - when(mMockA11yWindowManager.getWindowListLocked()).thenReturn(null); - when(mMockA11yWindowManager.isTrackingWindowsLocked()).thenReturn(false); + when(mMockA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)).thenReturn(null); + when(mMockA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)) + .thenReturn(false); mServiceConnection.getWindows(); verify(mMockSystemSupport).onClientChangeLocked(false); @@ -315,8 +318,9 @@ public class AbstractAccessibilityServiceConnectionTest { @Test public void getWindow_notTrackingWindows_invokeOnClientChange() { - when(mMockA11yWindowManager.getWindowListLocked()).thenReturn(null); - when(mMockA11yWindowManager.isTrackingWindowsLocked()).thenReturn(false); + when(mMockA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)).thenReturn(null); + when(mMockA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)) + .thenReturn(false); mServiceConnection.getWindow(WINDOWID); verify(mMockSystemSupport).onClientChangeLocked(false); 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 93c16fedcc1b..b7b5a4eaacfa 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java @@ -79,17 +79,22 @@ public class AccessibilityWindowManagerTest { private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM; private static final int USER_PROFILE = 11; private static final int USER_PROFILE_PARENT = 1; - // TO-DO [Multi-Display] : change the display count to 2 - private static final int DISPLAY_COUNT = 1; + private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1; private static final int NUM_GLOBAL_WINDOWS = 4; private static final int NUM_APP_WINDOWS = 4; - private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS) - * DISPLAY_COUNT; + private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS); private static final int DEFAULT_FOCUSED_INDEX = 1; private static final int SCREEN_WIDTH = 1080; private static final int SCREEN_HEIGHT = 1920; private AccessibilityWindowManager mA11yWindowManager; + // Window manager will support multiple focused window if config_perDisplayFocusEnabled is true, + // i.e., each display would have its current focused window, and one of all focused windows + // would be top focused window. Otherwise, window manager only supports one focused window + // at all displays, and that focused window would be top focused window. + private boolean mSupportPerDisplayFocus = false; + private int mTopFocusedDisplayId = Display.INVALID_DISPLAY; + private IBinder mTopFocusedWindowToken = null; // List of window token, mapping from windowId -> window token. private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>(); @@ -123,12 +128,9 @@ public class AccessibilityWindowManagerTest { mMockA11yEventSender, mMockA11ySecurityPolicy, mMockA11yUserManager); - - for (int i = 0; i < DISPLAY_COUNT; i++) { - when(mMockWindowManagerInternal.setWindowsForAccessibilityCallback(eq(i), any())) - .thenReturn(true); - startTrackingPerDisplay(i); - } + // Starts tracking window of default display and sets the default display + // as top focused display before each testing starts. + startTrackingPerDisplay(Display.DEFAULT_DISPLAY); // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged. // Resets it for mockito verify of further test case. @@ -143,7 +145,7 @@ public class AccessibilityWindowManagerTest { @Test public void startTrackingWindows_shouldEnableWindowManagerCallback() { // AccessibilityWindowManager#startTrackingWindows already invoked in setup. - assertTrue(mA11yWindowManager.isTrackingWindowsLocked()); + assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)); final WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(Display.DEFAULT_DISPLAY); verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback( @@ -152,11 +154,11 @@ public class AccessibilityWindowManagerTest { @Test public void stopTrackingWindows_shouldDisableWindowManagerCallback() { - assertTrue(mA11yWindowManager.isTrackingWindowsLocked()); + assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)); Mockito.reset(mMockWindowManagerInternal); - mA11yWindowManager.stopTrackingWindows(); - assertFalse(mA11yWindowManager.isTrackingWindowsLocked()); + mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY); + assertFalse(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)); verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback( eq(Display.DEFAULT_DISPLAY), isNull()); @@ -164,11 +166,11 @@ public class AccessibilityWindowManagerTest { @Test public void stopTrackingWindows_shouldClearWindows() { - assertTrue(mA11yWindowManager.isTrackingWindowsLocked()); + assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)); final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); - mA11yWindowManager.stopTrackingWindows(); - assertNull(mA11yWindowManager.getWindowListLocked()); + mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY); + assertNull(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)); assertEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT), AccessibilityWindowInfo.UNDEFINED_WINDOW_ID); assertEquals(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), @@ -176,6 +178,20 @@ public class AccessibilityWindowManagerTest { } @Test + public void stopTrackingWindows_onNonTopFocusedDisplay_shouldNotResetTopFocusWindow() + throws RemoteException { + // At setup, the default display sets be the top focused display and + // its current focused window sets be the top focused window. + // Starts tracking window of second display. + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID)); + // Stops tracking windows of second display. + mA11yWindowManager.stopTrackingWindows(SECONDARY_DISPLAY_ID); + assertNotEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT), + AccessibilityWindowInfo.UNDEFINED_WINDOW_ID); + } + + @Test public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() { final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); WindowInfo focusedWindowInfo = @@ -196,10 +212,66 @@ public class AccessibilityWindowManagerTest { } @Test + public void + onWindowsChanged_focusChangeOnNonTopFocusedDisplay_perDisplayFocusOn_notChangeWindow() + throws RemoteException { + // At setup, the default display sets be the top focused display and + // its current focused window sets be the top focused window. + // Sets supporting multiple focused window, i.e., config_perDisplayFocusEnabled is true. + mSupportPerDisplayFocus = true; + // Starts tracking window of second display. + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + // Gets the active window. + final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); + // Gets the top focused window. + final int topFocusedWindowId = + mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT); + // Changes the current focused window at second display. + changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID, + DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX); + + onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES); + // The active window should not be changed. + assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID)); + // The top focused window should not be changed. + assertEquals(topFocusedWindowId, + mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT)); + } + + @Test + public void + onWindowChange_focusChangeToNonTopFocusedDisplay_perDisplayFocusOff_shouldChangeWindow() + throws RemoteException { + // At setup, the default display sets be the top focused display and + // its current focused window sets be the top focused window. + // Sets not supporting multiple focused window, i.e., config_perDisplayFocusEnabled is + // false. + mSupportPerDisplayFocus = false; + // Starts tracking window of second display. + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + // Gets the active window. + final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); + // Gets the top focused window. + final int topFocusedWindowId = + mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT); + // Changes the current focused window from default display to second display. + changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID, + DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX); + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES); + // The active window should be changed. + assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID)); + // The top focused window should be changed. + assertNotEquals(topFocusedWindowId, + mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT)); + } + + @Test public void onWindowsChanged_shouldReportCorrectLayer() { // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup. List<AccessibilityWindowInfo> a11yWindows = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); for (int i = 0; i < a11yWindows.size(); i++) { final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i); final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i); @@ -212,7 +284,7 @@ public class AccessibilityWindowManagerTest { public void onWindowsChanged_shouldReportCorrectOrder() { // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup. List<AccessibilityWindowInfo> a11yWindows = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); for (int i = 0; i < a11yWindows.size(); i++) { final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i); final IBinder windowToken = mA11yWindowManager @@ -226,31 +298,31 @@ public class AccessibilityWindowManagerTest { public void onWindowsChangedAndForceSend_shouldUpdateWindows() { final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); final int correctLayer = - mA11yWindowManager.getWindowListLocked().get(0).getLayer(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer(); windowInfo.layer += 1; onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND); assertNotEquals(correctLayer, - mA11yWindowManager.getWindowListLocked().get(0).getLayer()); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer()); } @Test public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() { final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); final int correctLayer = - mA11yWindowManager.getWindowListLocked().get(0).getLayer(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer(); windowInfo.layer += 1; onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); assertEquals(correctLayer, - mA11yWindowManager.getWindowListLocked().get(0).getLayer()); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer()); } @Test public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows() throws RemoteException { final AccessibilityWindowInfo oldWindow = - mA11yWindowManager.getWindowListLocked().get(0); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0); final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, true, USER_SYSTEM_ID); final WindowInfo windowInfo = WindowInfo.obtain(); @@ -262,7 +334,7 @@ public class AccessibilityWindowManagerTest { onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); assertNotEquals(oldWindow, - mA11yWindowManager.getWindowListLocked().get(0)); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)); } @Test @@ -274,7 +346,8 @@ public class AccessibilityWindowManagerTest { windowInfo.focused = true; onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); - assertTrue(mA11yWindowManager.getWindowListLocked().get(0).isFocused()); + assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0) + .isFocused()); } @Test @@ -305,7 +378,7 @@ public class AccessibilityWindowManagerTest { @Test public void getWindowTokenForUserAndWindowId_shouldNotNull() { final List<AccessibilityWindowInfo> windows = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); for (int i = 0; i < windows.size(); i++) { final int windowId = windows.get(i).getId(); @@ -317,7 +390,7 @@ public class AccessibilityWindowManagerTest { @Test public void findWindowId() { final List<AccessibilityWindowInfo> windows = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); for (int i = 0; i < windows.size(); i++) { final int windowId = windows.get(i).getId(); final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked( @@ -339,7 +412,7 @@ public class AccessibilityWindowManagerTest { onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); final List<AccessibilityWindowInfo> a11yWindows = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); final Region outBounds = new Region(); int windowId = a11yWindows.get(0).getId(); @@ -362,7 +435,7 @@ public class AccessibilityWindowManagerTest { onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); final List<AccessibilityWindowInfo> a11yWindows = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -375,7 +448,7 @@ public class AccessibilityWindowManagerTest { public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() { // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible. final List<AccessibilityWindowInfo> a11yWindows = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -393,7 +466,7 @@ public class AccessibilityWindowManagerTest { onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); final List<AccessibilityWindowInfo> a11yWindows = - mA11yWindowManager.getWindowListLocked(); + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); final Region outBounds = new Region(); int windowId = a11yWindows.get(1).getId(); @@ -413,7 +486,7 @@ public class AccessibilityWindowManagerTest { .thenReturn(eventWindowToken); final int noUse = 0; - mA11yWindowManager.stopTrackingWindows(); + mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY); mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, eventWindowId, noUse, @@ -553,7 +626,7 @@ public class AccessibilityWindowManagerTest { mA11yWindowManager.getConnectionLocked( USER_SYSTEM_ID, newFocusWindowId).getRemote(); - mA11yWindowManager.stopTrackingWindows(); + mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY); final int noUse = 0; mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, defaultFocusWindowId, @@ -636,20 +709,27 @@ public class AccessibilityWindowManagerTest { false, USER_SYSTEM_ID); addWindowInfo(windowInfosForDisplay, token, layer++); } - // Setups default focus. - windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true; + // Sets up current focused window of display. + // Each display has its own current focused window if config_perDisplayFocusEnabled is true. + // Otherwise only default display needs to current focused window. + if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) { + windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true; + } // Turns on windows tracking, and update window info. - mA11yWindowManager.startTrackingWindows(); + when(mMockWindowManagerInternal.setWindowsForAccessibilityCallback(eq(displayId), any())) + .thenReturn(true); + mA11yWindowManager.startTrackingWindows(displayId); // Puts window lists into array. mWindowInfos.put(displayId, windowInfosForDisplay); - // Sets the default display as the top focused display. + // Sets the default display is the top focused display and + // its current focused window is the top focused window. if (displayId == Display.DEFAULT_DISPLAY) { setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX); } // Invokes callback for sending window lists to A11y framework. onWindowsForAccessibilityChanged(displayId, FORCE_SEND); - assertEquals(mA11yWindowManager.getWindowListLocked().size(), + assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(), windowInfosForDisplay.size()); } @@ -700,12 +780,9 @@ public class AccessibilityWindowManagerTest { private void setTopFocusedWindowAndDisplay(int displayId, int index) { // Sets the top focus window. - final IBinder eventWindowToken = mWindowInfos.get(displayId).get(index).token; - when(mMockWindowManagerInternal.getFocusedWindowToken()) - .thenReturn(eventWindowToken); + mTopFocusedWindowToken = mWindowInfos.get(displayId).get(index).token; // Sets the top focused display. - when(mMockWindowManagerInternal.getDisplayIdForWindow(eventWindowToken)) - .thenReturn(displayId); + mTopFocusedDisplayId = displayId; } private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) { @@ -714,7 +791,38 @@ public class AccessibilityWindowManagerTest { callbacks = getWindowsForAccessibilityCallbacks(displayId); mCallbackOfWindows.put(displayId, callbacks); } - callbacks.onWindowsForAccessibilityChanged(forceSend, mWindowInfos.get(displayId)); + callbacks.onWindowsForAccessibilityChanged(forceSend, mTopFocusedDisplayId, + mTopFocusedWindowToken, mWindowInfos.get(displayId)); + } + + private void changeFocusedWindowOnDisplayPerDisplayFocusConfig( + int changeFocusedDisplayId, int newFocusedWindowIndex, int oldTopFocusedDisplayId, + int oldFocusedWindowIndex) { + if (mSupportPerDisplayFocus) { + // Gets the old focused window of display which wants to change focused window. + WindowInfo focusedWindowInfo = + mWindowInfos.get(changeFocusedDisplayId).get(oldFocusedWindowIndex); + // Resets the focus of old focused window. + focusedWindowInfo.focused = false; + // Gets the new window of display which wants to change focused window. + focusedWindowInfo = + mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex); + // Sets the focus of new focused window. + focusedWindowInfo.focused = true; + } else { + // Gets the window of display which wants to change focused window. + WindowInfo focusedWindowInfo = + mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex); + // Sets the focus of new focused window. + focusedWindowInfo.focused = true; + // Gets the old focused window of old top focused display. + focusedWindowInfo = + mWindowInfos.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex); + // Resets the focus of old focused window. + focusedWindowInfo.focused = false; + // Changes the top focused display and window. + setTopFocusedWindowAndDisplay(changeFocusedDisplayId, newFocusedWindowIndex); + } } static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> { |