From 8065f440201f51ef3d94d22a03a0c1b966109d90 Mon Sep 17 00:00:00 2001 From: chaviw Date: Mon, 18 Nov 2019 13:20:58 -0800 Subject: [PATCH] Allow Windows in Display Overlays Instead of display overlays being a SurfaceControl that can only have child surfaces, it now is a WindowContainer that can have windows. Specifically, windows with the type TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY will be placed in the display overlays layer This is the first step to allow window magnification to use real windows on the display. Test: go/wm-smoke Bug: 136250281 Change-Id: Idad98db7a85f68ba49557c0efb83b9a1be089609 --- core/java/android/view/WindowManager.java | 7 + .../android/server/windowmanagerservice.proto | 1 + .../server/policy/WindowManagerPolicy.java | 9 +- .../com/android/server/wm/DisplayContent.java | 388 ++++++++++-------- .../server/wm/ScreenRotationAnimation.java | 2 +- .../server/wm/WindowManagerService.java | 7 +- .../server/wm/DisplayContentTests.java | 2 - 7 files changed, 226 insertions(+), 190 deletions(-) diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index d40f8325c3204..62a824d759f7c 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1105,6 +1105,13 @@ public interface WindowManager extends ViewManager { */ public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38; + /** + * Window type: Window for adding accessibility window magnification above other windows. + * This will place the window in the overlay windows. + * @hide + */ + public static final int TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39; + /** * End of types of system windows. */ diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 24456d80625d4..0c74842163671 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -163,6 +163,7 @@ message DisplayContentProto { repeated IdentifierProto opening_apps = 17; repeated IdentifierProto closing_apps = 18; repeated IdentifierProto changing_apps = 19; + repeated WindowTokenProto overlay_windows = 20; } /* represents DisplayFrames */ diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 95a5f52e5efb7..b28a112f84d8d 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -18,6 +18,7 @@ package com.android.server.policy; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; @@ -876,13 +877,15 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { case TYPE_ACCESSIBILITY_OVERLAY: // overlay put by accessibility services to intercept user interaction return 30; + case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY: + return 31; case TYPE_SECURE_SYSTEM_OVERLAY: - return 31; - case TYPE_BOOT_PROGRESS: return 32; + case TYPE_BOOT_PROGRESS: + return 33; case TYPE_POINTER: // the (mouse) pointer layer - return 33; + return 34; default: Slog.e("WindowManager", "Unknown window type: " + type); return APPLICATION_LAYER; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 8e126b56a7369..70f5fec04e698 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -58,6 +58,7 @@ import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE; import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; @@ -93,6 +94,7 @@ import static com.android.server.wm.DisplayContentProto.FOCUSED_APP; import static com.android.server.wm.DisplayContentProto.ID; import static com.android.server.wm.DisplayContentProto.IME_WINDOWS; import static com.android.server.wm.DisplayContentProto.OPENING_APPS; +import static com.android.server.wm.DisplayContentProto.OVERLAY_WINDOWS; import static com.android.server.wm.DisplayContentProto.PINNED_STACK_CONTROLLER; import static com.android.server.wm.DisplayContentProto.ROTATION; import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; @@ -240,7 +242,21 @@ class DisplayContent extends WindowContainer callback, boolean traverseTopToBottom) { - // Special handling so we can process IME windows with #forAllImeWindows above their IME - // target, or here in order if there isn't an IME target. - if (traverseTopToBottom) { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final DisplayChildWindowContainer child = mChildren.get(i); - if (skipTraverseChild(child)) { - continue; - } - - if (child.forAllWindows(callback, traverseTopToBottom)) { - return true; - } - } - } else { - final int count = mChildren.size(); - for (int i = 0; i < count; i++) { - final DisplayChildWindowContainer child = mChildren.get(i); - if (skipTraverseChild(child)) { - continue; - } - - if (child.forAllWindows(callback, traverseTopToBottom)) { - return true; - } - } - } - return false; - } - boolean forAllImeWindows(ToBooleanFunction callback, boolean traverseTopToBottom) { return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom); } @@ -2000,7 +1956,7 @@ class DisplayContent extends WindowContainer= 0; --i) { + final WindowToken windowToken = mOverlayContainers.getChildAt(i); + windowToken.dumpDebug(proto, OVERLAY_WINDOWS, logLevel); + } proto.write(DPI, mBaseDisplayDensity); mDisplayInfo.dumpDebug(proto, DISPLAY_INFO); proto.write(ROTATION, getRotation()); @@ -2660,31 +2618,31 @@ class DisplayContent extends WindowContainer= mWmService.mPolicy.getWindowLayerFromTypeLw( - TYPE_INPUT_METHOD_DIALOG, true)) { + TYPE_INPUT_METHOD_DIALOG, true)) { imeContainer.assignRelativeLayer(t, wt.getSurfaceControl(), -1); needAssignIme = false; } @@ -4497,6 +4453,126 @@ class DisplayContent extends WindowContainer { + private final String mName; + + WindowContainers(String name, WindowManagerService service) { + super(service); + mName = name; + } + + @Override + void assignChildLayers(SurfaceControl.Transaction t) { + mBelowAppWindowsContainers.assignLayer(t, 0); + mTaskStackContainers.assignLayer(t, 1); + mAboveAppWindowsContainers.assignLayer(t, 2); + + final WindowState imeTarget = mInputMethodTarget; + boolean needAssignIme = true; + + // In the case where we have an IME target that is not in split-screen mode IME + // assignment is easy. We just need the IME to go directly above the target. This way + // children of the target will naturally go above the IME and everyone is happy. + // + // In the case of split-screen windowing mode, we need to elevate the IME above the + // docked divider while keeping the app itself below the docked divider, so instead + // we use relative layering of the IME targets child windows, and place the IME in + // the non-app layer (see {@link AboveAppWindowContainers#assignChildLayers}). + // + // In the case the IME target is animating, the animation Z order may be different + // than the WindowContainer Z order, so it's difficult to be sure we have the correct + // IME target. In this case we just layer the IME over all transitions by placing it + // in the above applications layer. + // + // In the case where we have no IME target we assign it where its base layer would + // place it in the AboveAppWindowContainers. + // + // Keep IME window in mAboveAppWindowsContainers as long as app's starting window + // exists so it get's layered above the starting window. + if (imeTarget != null && !(imeTarget.mActivityRecord != null + && imeTarget.mActivityRecord.hasStartingWindow()) && ( + !(imeTarget.inSplitScreenWindowingMode() + || imeTarget.mToken.isAppTransitioning()) && ( + imeTarget.getSurfaceControl() != null))) { + mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(), + // TODO: We need to use an extra level on the app surface to ensure + // this is always above SurfaceView but always below attached window. + 1); + needAssignIme = false; + } + + // Above we have assigned layers to our children, now we ask them to assign + // layers to their children. + mBelowAppWindowsContainers.assignChildLayers(t); + mTaskStackContainers.assignChildLayers(t); + mAboveAppWindowsContainers.assignChildLayers(t, + needAssignIme ? mImeWindowsContainers : null); + mImeWindowsContainers.assignChildLayers(t); + } + + @Override + String getName() { + return mName; + } + + void addChildren() { + addChild(mBelowAppWindowsContainers, null); + addChild(mTaskStackContainers, null); + addChild(mAboveAppWindowsContainers, null); + addChild(mImeWindowsContainers, null); + } + + /** + * In split-screen mode we process the IME containers above the docked divider + * rather than directly above their target. + */ + private boolean skipTraverseChild(WindowContainer child) { + return child == mImeWindowsContainers && mInputMethodTarget != null + && !hasSplitScreenPrimaryStack(); + } + + @Override + boolean forAllWindows(ToBooleanFunction callback, + boolean traverseTopToBottom) { + // Special handling so we can process IME windows with #forAllImeWindows above their IME + // target, or here in order if there isn't an IME target. + if (traverseTopToBottom) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + final WindowContainer child = mChildren.get(i); + if (skipTraverseChild(child)) { + continue; + } + + if (child.forAllWindows(callback, traverseTopToBottom)) { + return true; + } + } + } else { + final int count = mChildren.size(); + for (int i = 0; i < count; i++) { + Slog.d(TAG, "child " + mChildren.get(i)); + final WindowContainer child = mChildren.get(i); + if (skipTraverseChild(child)) { + Slog.d(TAG, "child skipped"); + continue; + } + + if (child.forAllWindows(callback, traverseTopToBottom)) { + return true; + } + } + } + return false; + } + + @Override + void positionChildAt(int position, WindowContainer child, boolean includingParents) { + // Children of the WindowContainers are statically ordered, so the real intention here + // is to perform the operation on the display and not the static direct children. + getParent().positionChildAt(position, this, includingParents); + } + } + /** * Window container class that contains all containers on this display that are not related to * Apps. E.g. status bar. @@ -4510,7 +4586,7 @@ class DisplayContent extends WindowContainer mGetOrientingWindow = w -> { @@ -4562,7 +4638,7 @@ class DisplayContent extends WindowContainer