From ca9e061256861a86d7d1c2770c666451d3fb53de Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Fri, 2 Dec 2016 07:45:59 -0800 Subject: [PATCH] Allow some app windows to display above the IME. - Display child windows of the current IME target above the IME. - Display app windows above the current IME target above the IME. Regression in the functionality was introduce in I6f8bf15ba246fac69c4a496ebb1d9e0b9b6a95a2 when we switch away from using the window list for z-ordering and using the hierarchy which has the IME above all app windows. Change-Id: I399aab7fd5ad7327ef6bc29d48f6d9bf48a6ac6c Fixes: 33128382 Test: bit FrameworksServicesTests:com.android.server.wm.WindowLayersControllerTests --- .../com/android/server/wm/DisplayContent.java | 6 +- .../server/wm/WindowLayersController.java | 24 ++++++++ .../com/android/server/wm/WindowState.java | 13 ++--- .../server/wm/WindowStateAnimator.java | 9 +-- .../wm/WindowLayersControllerTests.java | 57 +++++++++++++++++++ 5 files changed, 90 insertions(+), 19 deletions(-) diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index e73acde65a3d4..18568ba4f1372 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -141,8 +141,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; /** * Utility class for keeping track of the WindowStates and other pertinent contents of a @@ -2546,7 +2544,7 @@ class DisplayContent extends WindowContainer mAboveImeTargetAppWindows = new ArrayDeque(); final void assignWindowLayers(DisplayContent dc) { if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based", @@ -143,6 +145,8 @@ class WindowLayersController { mImeTarget = mService.mInputMethodTarget; mHighestLayerInImeTargetBaseLayer = (mImeTarget != null) ? mImeTarget.mBaseLayer : 0; + mAboveImeTarget = false; + mAboveImeTargetAppWindows.clear(); } private void collectSpecialWindows(WindowState w) { @@ -157,6 +161,20 @@ class WindowLayersController { mInputMethodWindows.add(w); return; } + if (mImeTarget != null) { + if (w.getParentWindow() == mImeTarget && w.mSubLayer > 0) { + // Child windows of the ime target with a positive sub-layer should be placed above + // the IME. + mAboveImeTargetAppWindows.add(w); + } else if (mAboveImeTarget && w.mAppToken != null) { + // windows of apps above the IME target should be placed above the IME. + mAboveImeTargetAppWindows.add(w); + } + if (w == mImeTarget) { + mAboveImeTarget = true; + } + } + final Task task = w.getTask(); if (task == null) { return; @@ -211,6 +229,12 @@ class WindowLayersController { while (!mInputMethodWindows.isEmpty()) { layer = assignAndIncreaseLayerIfNeeded(mInputMethodWindows.remove(), layer); } + + // Adjust app windows the should be displayed above the IME since they are above the IME + // target. + while (!mAboveImeTargetAppWindows.isEmpty()) { + layer = assignAndIncreaseLayerIfNeeded(mAboveImeTargetAppWindows.remove(), layer); + } } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 572581e0c1e03..2ee1e186c0f60 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -60,8 +60,6 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedList; -import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; import static android.app.ActivityManager.StackId; @@ -91,7 +89,6 @@ import static android.view.WindowManager.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; @@ -1654,18 +1651,16 @@ class WindowState extends WindowContainer implements WindowManagerP && (!mIsChildWindow || !getParentWindow().hasMoved()); } - boolean isObscuringFullscreen(final DisplayInfo displayInfo) { + boolean isObscuringDisplay() { Task task = getTask(); if (task != null && task.mStack != null && !task.mStack.fillsParent()) { return false; } - if (!isOpaqueDrawn() || !isFrameFullscreen(displayInfo)) { - return false; - } - return true; + return isOpaqueDrawn() && fillsDisplay(); } - boolean isFrameFullscreen(final DisplayInfo displayInfo) { + boolean fillsDisplay() { + final DisplayInfo displayInfo = getDisplayInfo(); return mFrame.left <= 0 && mFrame.top <= 0 && mFrame.right >= displayInfo.appWidth && mFrame.bottom >= displayInfo.appHeight; } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 04db499052ae5..37bd402902b68 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -57,7 +57,6 @@ import android.os.Trace; import android.util.Slog; import android.view.DisplayInfo; import android.view.MagnificationSpec; -import android.view.Surface; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; import android.view.WindowManager; @@ -1108,10 +1107,9 @@ class WindowStateAnimator { /** * Calculate the window-space crop rect and fill clipRect. - * @return true if clipRect has been filled otherwise, no window space - * crop should be applied. + * @return true if clipRect has been filled otherwise, no window space crop should be applied. */ - boolean calculateCrop(Rect clipRect) { + private boolean calculateCrop(Rect clipRect) { final WindowState w = mWin; final DisplayContent displayContent = w.getDisplayContent(); clipRect.setEmpty(); @@ -1130,7 +1128,6 @@ class WindowStateAnimator { return false; } - final DisplayInfo displayInfo = displayContent.getDisplayInfo(); if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop win=" + w + " mLastCrop=" + mLastClipRect); @@ -1139,7 +1136,7 @@ class WindowStateAnimator { if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame=" + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect); - final boolean fullscreen = w.isFrameFullscreen(displayInfo); + final boolean fullscreen = w.fillsDisplay(); final boolean isFreeformResizing = w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM; diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java index 5a035d636443c..b9fc3ff5f69f0 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowLayersControllerTests.java @@ -25,6 +25,7 @@ import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; @@ -120,6 +121,62 @@ public class WindowLayersControllerTests extends WindowTestsBase { assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow); } + @Test + public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception { + final WindowState imeAppTarget = + createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget"); + final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget, + TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken, + "imeAppTargetChildAboveWindow"); + final WindowState imeAppTargetChildBelowWindow = createWindow(imeAppTarget, + TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken, + "imeAppTargetChildBelowWindow"); + + sWm.mInputMethodTarget = imeAppTarget; + sLayersController.assignWindowLayers(sDisplayContent); + + // Ime should be above all app windows except for child windows that are z-ordered above it + // and below system windows if it is targeting an app window. + assertWindowLayerGreaterThan(sImeWindow, imeAppTarget); + assertWindowLayerGreaterThan(imeAppTargetChildAboveWindow, sImeWindow); + assertWindowLayerGreaterThan(sImeWindow, imeAppTargetChildBelowWindow); + assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow); + assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow); + assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow); + + // And, IME dialogs should always have an higher layer than the IME. + assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow); + } + + @Test + public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception { + final WindowState appBelowImeTarget = + createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "appBelowImeTarget"); + final WindowState imeAppTarget = + createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "imeAppTarget"); + final WindowState appAboveImeTarget = + createWindow(null, TYPE_BASE_APPLICATION, sDisplayContent, "appAboveImeTarget"); + + sWm.mInputMethodTarget = imeAppTarget; + sLayersController.assignWindowLayers(sDisplayContent); + + // Ime should be above all app windows except for non-fullscreen app window above it and + // below system windows if it is targeting an app window. + assertWindowLayerGreaterThan(sImeWindow, imeAppTarget); + assertWindowLayerGreaterThan(sImeWindow, appBelowImeTarget); + assertWindowLayerGreaterThan(appAboveImeTarget, sImeWindow); + assertWindowLayerGreaterThan(sImeWindow, sChildAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sAppWindow); + assertWindowLayerGreaterThan(sImeWindow, sDockedDividerWindow); + assertWindowLayerGreaterThan(sNavBarWindow, sImeWindow); + assertWindowLayerGreaterThan(sStatusBarWindow, sImeWindow); + + // And, IME dialogs should always have an higher layer than the IME. + assertWindowLayerGreaterThan(sImeDialogWindow, sImeWindow); + } + @Test public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception { final WindowState imeSystemOverlayTarget =