Loading services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +14 −0 Original line number Diff line number Diff line Loading @@ -373,6 +373,20 @@ public class AccessibilityWindowManager { } } /** * Called when the display is reparented and becomes an embedded * display. * * @param embeddedDisplayId The embedded display Id. */ @Override public void onDisplayReparented(int embeddedDisplayId) { // Removes the un-used window observer for the embedded display. synchronized (mLock) { mDisplayWindowsObservers.remove(embeddedDisplayId); } } private boolean shouldUpdateWindowsLocked(boolean forceSend, @NonNull List<WindowInfo> windows) { if (forceSend) { Loading services/core/java/com/android/server/wm/AccessibilityController.java +46 −29 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ import android.view.animation.Interpolator; import com.android.internal.R; import com.android.internal.os.SomeArgs; import com.android.internal.util.TraceBuffer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal; Loading Loading @@ -172,11 +173,15 @@ final class AccessibilityController { /** * Sets a callback for observing which windows are touchable for the purposes * of accessibility on specified display. * of accessibility on specified display. When a display is reparented and becomes * an embedded one, the {@link WindowsForAccessibilityCallback#onDisplayReparented(int)} * will notify the accessibility framework to remove the un-used window observer of * this embedded display. * * @param displayId The logical display id. * @param callback The callback. * @return {@code false} if display id is not valid or an embedded display. * @return {@code false} if display id is not valid or an embedded display when the callback * isn't null. */ boolean setWindowsForAccessibilityCallback(int displayId, WindowsForAccessibilityCallback callback) { Loading @@ -185,12 +190,13 @@ final class AccessibilityController { TAG + ".setWindowsForAccessibilityCallback", "displayId=" + displayId + "; callback={" + callback + "}"); } if (callback != null) { final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId); if (dc == null) { return false; } if (callback != null) { WindowsForAccessibilityObserver observer = mWindowsForAccessibilityObserver.get(displayId); if (isEmbeddedDisplay(dc)) { Loading @@ -209,21 +215,13 @@ final class AccessibilityController { if (Build.IS_DEBUGGABLE) { throw new IllegalStateException(errorMessage); } removeObserverOfEmbeddedDisplay(observer); removeObserversForEmbeddedChildDisplays(observer); mWindowsForAccessibilityObserver.remove(displayId); } observer = new WindowsForAccessibilityObserver(mService, displayId, callback); mWindowsForAccessibilityObserver.put(displayId, observer); mAllObserversInitialized &= observer.mInitialized; } else { if (isEmbeddedDisplay(dc)) { // If this display is an embedded one, its window observer should be removed along // with the window observer of its parent display removed because the window // observer of the embedded display and its parent display is the same, and would // be removed together when stopping the window tracking of its parent display. So // here don't need to do removing window observer of the embedded display again. return true; } final WindowsForAccessibilityObserver windowsForA11yObserver = mWindowsForAccessibilityObserver.get(displayId); if (windowsForA11yObserver == null) { Loading @@ -234,7 +232,7 @@ final class AccessibilityController { throw new IllegalStateException(errorMessage); } } removeObserverOfEmbeddedDisplay(windowsForA11yObserver); removeObserversForEmbeddedChildDisplays(windowsForA11yObserver); mWindowsForAccessibilityObserver.remove(displayId); } return true; Loading Loading @@ -507,24 +505,36 @@ final class AccessibilityController { if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) { return; } mService.mH.sendMessage(PooledLambda.obtainMessage( AccessibilityController::updateWindowObserverOfEmbeddedDisplay, this, embeddedDisplayId, parentWindow)); } private void updateWindowObserverOfEmbeddedDisplay(int embeddedDisplayId, WindowState parentWindow) { final WindowsForAccessibilityObserver windowsForA11yObserver; synchronized (mService.mGlobalLock) { // Finds the parent display of this embedded display final int parentDisplayId; WindowState candidate = parentWindow; while (candidate != null) { parentWindow = candidate; candidate = parentWindow.getDisplayContent().getParentWindow(); } parentDisplayId = parentWindow.getDisplayId(); final int parentDisplayId = parentWindow.getDisplayId(); // Uses the observer of parent display final WindowsForAccessibilityObserver windowsForA11yObserver = mWindowsForAccessibilityObserver.get(parentDisplayId); windowsForA11yObserver = mWindowsForAccessibilityObserver.get(parentDisplayId); } if (windowsForA11yObserver != null) { windowsForA11yObserver.notifyDisplayReparented(embeddedDisplayId); windowsForA11yObserver.addEmbeddedDisplay(embeddedDisplayId); synchronized (mService.mGlobalLock) { // Replaces the observer of embedded display to the one of parent display mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver); } } } void onImeSurfaceShownChanged(WindowState windowState, boolean shown) { if (mAccessibilityTracing.isEnabled()) { Loading Loading @@ -555,7 +565,7 @@ final class AccessibilityController { + "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver); } private void removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver private void removeObserversForEmbeddedChildDisplays(WindowsForAccessibilityObserver observerOfParentDisplay) { final IntArray embeddedDisplayIdList = observerOfParentDisplay.getAndClearEmbeddedDisplayIdList(); Loading Loading @@ -1541,6 +1551,13 @@ final class AccessibilityController { mEmbeddedDisplayIdList.add(displayId); } void notifyDisplayReparented(int embeddedDisplayId) { // Notifies the A11y framework the display is reparented and // becomes an embedded display for removing the un-used // displayWindowObserver of this embedded one. mCallback.onDisplayReparented(embeddedDisplayId); } /** * Check if windows have changed, and send them to the accessibility subsystem if they have. * Loading services/core/java/com/android/server/wm/WindowManagerInternal.java +10 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,16 @@ public abstract class WindowManagerInternal { */ void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId, IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows); /** * Called when the display is reparented and becomes an embedded * display. The {@link WindowsForAccessibilityCallback} with the given embedded * display will be replaced by the {@link WindowsForAccessibilityCallback} * associated with its parent display at the same time. * * @param embeddedDisplayId The embedded display Id. */ void onDisplayReparented(int embeddedDisplayId); } /** Loading services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java +13 −0 Original line number Diff line number Diff line Loading @@ -834,6 +834,19 @@ public class AccessibilityWindowManagerTest { assertNull(token); } @Test public void onDisplayReparented_shouldRemoveObserver() throws RemoteException { // Starts tracking window of second display. startTrackingPerDisplay(SECONDARY_DISPLAY_ID); assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID)); // Notifies the second display is an embedded one of the default display. final WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(Display.DEFAULT_DISPLAY); callbacks.onDisplayReparented(SECONDARY_DISPLAY_ID); // Makes sure the observer of the second display is removed. assertFalse(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID)); } private void registerLeashedTokenAndWindowId() { mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID); mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID); Loading Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +14 −0 Original line number Diff line number Diff line Loading @@ -373,6 +373,20 @@ public class AccessibilityWindowManager { } } /** * Called when the display is reparented and becomes an embedded * display. * * @param embeddedDisplayId The embedded display Id. */ @Override public void onDisplayReparented(int embeddedDisplayId) { // Removes the un-used window observer for the embedded display. synchronized (mLock) { mDisplayWindowsObservers.remove(embeddedDisplayId); } } private boolean shouldUpdateWindowsLocked(boolean forceSend, @NonNull List<WindowInfo> windows) { if (forceSend) { Loading
services/core/java/com/android/server/wm/AccessibilityController.java +46 −29 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ import android.view.animation.Interpolator; import com.android.internal.R; import com.android.internal.os.SomeArgs; import com.android.internal.util.TraceBuffer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal; Loading Loading @@ -172,11 +173,15 @@ final class AccessibilityController { /** * Sets a callback for observing which windows are touchable for the purposes * of accessibility on specified display. * of accessibility on specified display. When a display is reparented and becomes * an embedded one, the {@link WindowsForAccessibilityCallback#onDisplayReparented(int)} * will notify the accessibility framework to remove the un-used window observer of * this embedded display. * * @param displayId The logical display id. * @param callback The callback. * @return {@code false} if display id is not valid or an embedded display. * @return {@code false} if display id is not valid or an embedded display when the callback * isn't null. */ boolean setWindowsForAccessibilityCallback(int displayId, WindowsForAccessibilityCallback callback) { Loading @@ -185,12 +190,13 @@ final class AccessibilityController { TAG + ".setWindowsForAccessibilityCallback", "displayId=" + displayId + "; callback={" + callback + "}"); } if (callback != null) { final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId); if (dc == null) { return false; } if (callback != null) { WindowsForAccessibilityObserver observer = mWindowsForAccessibilityObserver.get(displayId); if (isEmbeddedDisplay(dc)) { Loading @@ -209,21 +215,13 @@ final class AccessibilityController { if (Build.IS_DEBUGGABLE) { throw new IllegalStateException(errorMessage); } removeObserverOfEmbeddedDisplay(observer); removeObserversForEmbeddedChildDisplays(observer); mWindowsForAccessibilityObserver.remove(displayId); } observer = new WindowsForAccessibilityObserver(mService, displayId, callback); mWindowsForAccessibilityObserver.put(displayId, observer); mAllObserversInitialized &= observer.mInitialized; } else { if (isEmbeddedDisplay(dc)) { // If this display is an embedded one, its window observer should be removed along // with the window observer of its parent display removed because the window // observer of the embedded display and its parent display is the same, and would // be removed together when stopping the window tracking of its parent display. So // here don't need to do removing window observer of the embedded display again. return true; } final WindowsForAccessibilityObserver windowsForA11yObserver = mWindowsForAccessibilityObserver.get(displayId); if (windowsForA11yObserver == null) { Loading @@ -234,7 +232,7 @@ final class AccessibilityController { throw new IllegalStateException(errorMessage); } } removeObserverOfEmbeddedDisplay(windowsForA11yObserver); removeObserversForEmbeddedChildDisplays(windowsForA11yObserver); mWindowsForAccessibilityObserver.remove(displayId); } return true; Loading Loading @@ -507,24 +505,36 @@ final class AccessibilityController { if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) { return; } mService.mH.sendMessage(PooledLambda.obtainMessage( AccessibilityController::updateWindowObserverOfEmbeddedDisplay, this, embeddedDisplayId, parentWindow)); } private void updateWindowObserverOfEmbeddedDisplay(int embeddedDisplayId, WindowState parentWindow) { final WindowsForAccessibilityObserver windowsForA11yObserver; synchronized (mService.mGlobalLock) { // Finds the parent display of this embedded display final int parentDisplayId; WindowState candidate = parentWindow; while (candidate != null) { parentWindow = candidate; candidate = parentWindow.getDisplayContent().getParentWindow(); } parentDisplayId = parentWindow.getDisplayId(); final int parentDisplayId = parentWindow.getDisplayId(); // Uses the observer of parent display final WindowsForAccessibilityObserver windowsForA11yObserver = mWindowsForAccessibilityObserver.get(parentDisplayId); windowsForA11yObserver = mWindowsForAccessibilityObserver.get(parentDisplayId); } if (windowsForA11yObserver != null) { windowsForA11yObserver.notifyDisplayReparented(embeddedDisplayId); windowsForA11yObserver.addEmbeddedDisplay(embeddedDisplayId); synchronized (mService.mGlobalLock) { // Replaces the observer of embedded display to the one of parent display mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver); } } } void onImeSurfaceShownChanged(WindowState windowState, boolean shown) { if (mAccessibilityTracing.isEnabled()) { Loading Loading @@ -555,7 +565,7 @@ final class AccessibilityController { + "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver); } private void removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver private void removeObserversForEmbeddedChildDisplays(WindowsForAccessibilityObserver observerOfParentDisplay) { final IntArray embeddedDisplayIdList = observerOfParentDisplay.getAndClearEmbeddedDisplayIdList(); Loading Loading @@ -1541,6 +1551,13 @@ final class AccessibilityController { mEmbeddedDisplayIdList.add(displayId); } void notifyDisplayReparented(int embeddedDisplayId) { // Notifies the A11y framework the display is reparented and // becomes an embedded display for removing the un-used // displayWindowObserver of this embedded one. mCallback.onDisplayReparented(embeddedDisplayId); } /** * Check if windows have changed, and send them to the accessibility subsystem if they have. * Loading
services/core/java/com/android/server/wm/WindowManagerInternal.java +10 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,16 @@ public abstract class WindowManagerInternal { */ void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId, IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows); /** * Called when the display is reparented and becomes an embedded * display. The {@link WindowsForAccessibilityCallback} with the given embedded * display will be replaced by the {@link WindowsForAccessibilityCallback} * associated with its parent display at the same time. * * @param embeddedDisplayId The embedded display Id. */ void onDisplayReparented(int embeddedDisplayId); } /** Loading
services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java +13 −0 Original line number Diff line number Diff line Loading @@ -834,6 +834,19 @@ public class AccessibilityWindowManagerTest { assertNull(token); } @Test public void onDisplayReparented_shouldRemoveObserver() throws RemoteException { // Starts tracking window of second display. startTrackingPerDisplay(SECONDARY_DISPLAY_ID); assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID)); // Notifies the second display is an embedded one of the default display. final WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(Display.DEFAULT_DISPLAY); callbacks.onDisplayReparented(SECONDARY_DISPLAY_ID); // Makes sure the observer of the second display is removed. assertFalse(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID)); } private void registerLeashedTokenAndWindowId() { mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID); mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID); Loading