From cff7ebb93dd987505354f318b4fff9ccf18d4232 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Wed, 22 Apr 2020 16:54:49 -0700 Subject: [PATCH] Connect systemwindow root with accessibility This sets the most-recently created view on a shellroot to be used as the "accessibility" window. This allows each shellroot to have 1 window that accessibility sees. Bug: 152368950 Test: atest AccessibilityWindowQueryTest#testWindowDockAndUndock_dividerWindowAppearsAndDisappears Change-Id: Ice2820e11544ccdf7a3e600f918eac0ffb506548 --- core/java/android/view/IWindowManager.aidl | 8 +++++ .../android/view/SurfaceControlViewHost.java | 10 +++++- .../android/systemui/wm/SystemWindows.java | 8 +++++ .../java/com/android/server/wm/ShellRoot.java | 31 ++++++++++++++++++- .../server/wm/WindowManagerService.java | 24 ++++++++++++++ 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index b3b53f0293823..58597cf3fb6d8 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -160,6 +160,14 @@ interface IWindowManager */ SurfaceControl addShellRoot(int displayId, IWindow client, int windowType); + /** + * Sets the window token sent to accessibility for a particular shell root. The + * displayId and windowType identify which shell-root to update. + * + * @param target The IWindow that accessibility service interfaces with. + */ + void setShellRootAccessibilityWindow(int displayId, int windowType, IWindow target); + /** * Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is * used for recents, where generating the thumbnails of the specs takes a non-trivial amount of diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index cfceb031539f3..3d6da6f71b3ff 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -39,7 +39,7 @@ import java.util.Objects; * {@link SurfaceView#setChildSurfacePackage}. */ public class SurfaceControlViewHost { - private ViewRootImpl mViewRoot; + private final ViewRootImpl mViewRoot; private WindowlessWindowManager mWm; private SurfaceControl mSurfaceControl; @@ -225,6 +225,14 @@ public class SurfaceControlViewHost { return mViewRoot.getView(); } + /** + * @return the ViewRootImpl wrapped by this host. + * @hide + */ + public IWindow getWindowToken() { + return mViewRoot.mWindow; + } + /** * @hide */ diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java index 899aabb2e9a74..0b6e4b2ab5980 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java +++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java @@ -201,6 +201,14 @@ public class SystemWindows { attrs.flags |= FLAG_HARDWARE_ACCELERATED; viewRoot.setView(view, attrs); mViewRoots.put(view, viewRoot); + + try { + mWmService.setShellRootAccessibilityWindow(mDisplayId, windowType, + viewRoot.getWindowToken()); + } catch (RemoteException e) { + Slog.e(TAG, "Error setting accessibility window for " + mDisplayId + ":" + + windowType, e); + } } SysUiWindowManager addRoot(int windowType) { diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java index 0b1760dc5a1c0..99f710bd8bd46 100644 --- a/services/core/java/com/android/server/wm/ShellRoot.java +++ b/services/core/java/com/android/server/wm/ShellRoot.java @@ -43,6 +43,8 @@ public class ShellRoot { private WindowToken mToken; private final IBinder.DeathRecipient mDeathRecipient; private SurfaceControl mSurfaceControl = null; + private IWindow mAccessibilityWindow; + private IBinder.DeathRecipient mAccessibilityWindowDeath; ShellRoot(@NonNull IWindow client, @NonNull DisplayContent dc, final int windowType) { mDisplayContent = dc; @@ -112,11 +114,14 @@ public class ShellRoot { if (!mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated()) { return null; } + if (mAccessibilityWindow == null) { + return null; + } WindowInfo windowInfo = WindowInfo.obtain(); windowInfo.displayId = mToken.getDisplayArea().getDisplayContent().mDisplayId; windowInfo.type = mToken.windowType; windowInfo.layer = mToken.getWindowLayerFromType(); - windowInfo.token = mClient.asBinder(); + windowInfo.token = mAccessibilityWindow.asBinder(); windowInfo.title = "Splitscreen Divider"; windowInfo.focused = false; windowInfo.inPictureInPicture = false; @@ -126,5 +131,29 @@ public class ShellRoot { windowInfo.regionInScreen.set(regionRect); return windowInfo; } + + void setAccessibilityWindow(IWindow window) { + if (mAccessibilityWindow != null) { + mAccessibilityWindow.asBinder().unlinkToDeath(mAccessibilityWindowDeath, 0); + } + mAccessibilityWindow = window; + if (mAccessibilityWindow != null) { + try { + mAccessibilityWindowDeath = () -> { + synchronized (mDisplayContent.mWmService.mGlobalLock) { + mAccessibilityWindow = null; + setAccessibilityWindow(null); + } + }; + mAccessibilityWindow.asBinder().linkToDeath(mAccessibilityWindowDeath, 0); + } catch (RemoteException e) { + mAccessibilityWindow = null; + } + } + if (mDisplayContent.mWmService.mAccessibilityController != null) { + mDisplayContent.mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked( + mDisplayContent.getDisplayId()); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index fbdea01deb776..e1b71e2860b51 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3868,6 +3868,30 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void setShellRootAccessibilityWindow(int displayId, int windowType, IWindow target) { + if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS); + } + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + return; + } + ShellRoot root = dc.mShellRoots.get(windowType); + if (root == null) { + return; + } + root.setAccessibilityWindow(target); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + @Override public void setDisplayWindowInsetsController( int displayId, IDisplayWindowInsetsController insetsController) {