Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca9e0612 authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

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
parent ad726872
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -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<DisplayContent.DisplayChildWindowCo
            if (!obscured) {
                final boolean isDisplayed = w.isDisplayedLw();

                if (isDisplayed && w.isObscuringFullscreen(mDisplayInfo)) {
                if (isDisplayed && w.isObscuringDisplay()) {
                    // This window completely covers everything behind it, so we want to leave all
                    // of them as undimmed (for performance reasons).
                    root.mObscuringWindow = w;
@@ -2945,7 +2943,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                    screenshotReady = true;
                }

                if (ws.isObscuringFullscreen(mDisplayInfo)){
                if (ws.isObscuringDisplay()){
                    break;
                }
            }
+24 −0
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ class WindowLayersController {
    private boolean mAnyLayerChanged;
    private int mHighestLayerInImeTargetBaseLayer;
    private WindowState mImeTarget;
    private boolean mAboveImeTarget;
    private ArrayDeque<WindowState> 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);
            }
        }

    }
+4 −9
Original line number Diff line number Diff line
@@ -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<WindowState> 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;
    }
+3 −6
Original line number Diff line number Diff line
@@ -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;

+57 −0
Original line number Diff line number Diff line
@@ -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 =