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

Commit 2df7ff30 authored by Tiger Huang's avatar Tiger Huang Committed by Android (Google) Code Review
Browse files

Merge "Move all the window layout logic to WindowLayout"

parents e2089c77 5210f964
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -57,12 +57,15 @@ import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
@@ -72,6 +75,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_V
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
@@ -90,6 +94,7 @@ import android.annotation.UiContext;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ResourcesManager;
import android.app.WindowConfiguration;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -515,6 +520,8 @@ public final class ViewRootImpl implements ViewParent,

    private final WindowLayout mWindowLayout = new WindowLayout();

    private ViewRootImpl mParentViewRoot;

    // This is used to reduce the race between window focus changes being dispatched from
    // the window manager and input events coming through the input system.
    @GuardedBy("this")
@@ -1053,6 +1060,7 @@ public final class ViewRootImpl implements ViewParent,
                if (panelParentView != null) {
                    mAttachInfo.mPanelParentWindowToken
                            = panelParentView.getApplicationWindowToken();
                    mParentViewRoot = panelParentView.getViewRootImpl();
                }
                mAdded = true;
                int res; /* = WindowManagerImpl.ADD_OKAY; */
@@ -1113,10 +1121,13 @@ public final class ViewRootImpl implements ViewParent,
                final InsetsState state = mInsetsController.getState();
                final Rect displayCutoutSafe = mTempRect;
                state.getDisplayCutoutSafe(displayCutoutSafe);
                final WindowConfiguration winConfig = getConfiguration().windowConfiguration;
                mWindowLayout.computeWindowFrames(mWindowAttributes, state,
                        displayCutoutSafe, getConfiguration().windowConfiguration.getBounds(),
                        displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
                        UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
                        mInsetsController.getRequestedVisibilities(),
                        null /* attachedWindowFrame */, mTmpFrames.frame, mTempRect2);
                        getAttachedWindowFrame(), 1f /* compactScale */,
                        mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
                setFrame(mTmpFrames.frame);
                if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                if (res < WindowManagerGlobal.ADD_OKAY) {
@@ -1227,6 +1238,14 @@ public final class ViewRootImpl implements ViewParent,
        }
    }

    private Rect getAttachedWindowFrame() {
        final int type = mWindowAttributes.type;
        final boolean layoutAttached = (mParentViewRoot != null
                && type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW
                && type != TYPE_APPLICATION_ATTACHED_DIALOG);
        return layoutAttached ? mParentViewRoot.mWinFrame : null;
    }

    /**
     * Register any kind of listeners if setView was success.
     */
+134 −11
Original line number Diff line number Diff line
@@ -19,29 +19,44 @@ package android.view;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;

import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.Log;

/**
 * Computes window frames.
 * @hide
 */
public class WindowLayout {
    private static final String TAG = WindowLayout.class.getSimpleName();
    private static final boolean DEBUG = false;

    public static final int UNSPECIFIED_LENGTH = -1;

    private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
    private final Rect mTempRect = new Rect();

    public boolean computeWindowFrames(WindowManager.LayoutParams attrs, InsetsState state,
            Rect displayCutoutSafe, Rect windowBounds, InsetsVisibilities requestedVisibilities,
            Rect attachedWindowFrame, Rect outDisplayFrame, Rect outParentFrame) {
            Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
            int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities,
            Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame,
            Rect outFrame) {
        final int type = attrs.type;
        final int fl = attrs.flags;
        final int pfl = attrs.privateFlags;
@@ -72,18 +87,14 @@ public class WindowLayout {
        }

        // Compute bounds restricted by display cutout
        final int cutoutMode = attrs.layoutInDisplayCutoutMode;
        final DisplayCutout cutout = state.getDisplayCutout();
        if (cutout.isEmpty()) {
            return false;
        }
        boolean clippedByDisplayCutout = false;
        final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect;
        displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe);

        boolean clippedByDisplayCutout = false;
        if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) {
            // Ensure that windows with a non-ALWAYS display cutout mode are laid out in
            // the cutout safe zone.
        final int cutoutMode = attrs.layoutInDisplayCutoutMode;
        if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
            final Rect displayFrame = state.getDisplayFrame();
            final InsetsSource statusBarSource = state.peekSource(ITYPE_STATUS_BAR);
            if (statusBarSource != null && displayCutoutSafe.top > displayFrame.top) {
@@ -147,6 +158,118 @@ public class WindowLayout {
            }
            outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
        }

        final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
        final boolean inMultiWindowMode = WindowConfiguration.inMultiWindowMode(windowingMode);

        // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
        // Also, we don't allow windows in multi-window mode to extend out of the screen.
        if (noLimits && type != TYPE_SYSTEM_ERROR && !inMultiWindowMode) {
            outDisplayFrame.left = outDisplayFrame.top = -10000;
            outDisplayFrame.right = outDisplayFrame.bottom = 10000;
        }

        final boolean hasCompatScale = compatScale != 1f;
        final int pw = outParentFrame.width();
        final int ph = outParentFrame.height();
        int rw = requestedWidth;
        int rh = requestedHeight;
        float x, y;
        int w, h;

        // If the view hierarchy hasn't been measured, the requested width and height would be
        // UNSPECIFIED_LENGTH. This can happen in the first layout of a window or in the simulated
        // layout.
        if (rw == UNSPECIFIED_LENGTH) {
            rw = attrs.width >= 0 ? attrs.width : pw;
        }
        if (rh == UNSPECIFIED_LENGTH) {
            rh = attrs.height >= 0 ? attrs.height : ph;
        }

        if ((attrs.flags & FLAG_SCALED) != 0) {
            if (attrs.width < 0) {
                w = pw;
            } else if (hasCompatScale) {
                w = (int) (attrs.width * compatScale + .5f);
            } else {
                w = attrs.width;
            }
            if (attrs.height < 0) {
                h = ph;
            } else if (hasCompatScale) {
                h = (int) (attrs.height * compatScale + .5f);
            } else {
                h = attrs.height;
            }
        } else {
            if (attrs.width == MATCH_PARENT) {
                w = pw;
            } else if (hasCompatScale) {
                w = (int) (rw * compatScale + .5f);
            } else {
                w = rw;
            }
            if (attrs.height == MATCH_PARENT) {
                h = ph;
            } else if (hasCompatScale) {
                h = (int) (rh * compatScale + .5f);
            } else {
                h = rh;
            }
        }

        if (hasCompatScale) {
            x = attrs.x * compatScale;
            y = attrs.y * compatScale;
        } else {
            x = attrs.x;
            y = attrs.y;
        }

        if (inMultiWindowMode
                && (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) == 0) {
            // Make sure window fits in parent frame since it is in a non-fullscreen task as
            // required by {@link Gravity#apply} call.
            w = Math.min(w, pw);
            h = Math.min(h, ph);
        }

        // We need to fit it to the display if either
        // a) The window is in a fullscreen container, or we don't have a task (we assume fullscreen
        // for the taskless windows)
        // b) If it's a secondary app window, we also need to fit it to the display unless
        // FLAG_LAYOUT_NO_LIMITS is set. This is so we place Popups, dialogs, and similar windows on
        // screen, but SurfaceViews want to be always at a specific location so we don't fit it to
        // the display.
        final boolean fitToDisplay = !inMultiWindowMode
                || ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits);

        // Set mFrame
        Gravity.apply(attrs.gravity, w, h, outParentFrame,
                (int) (x + attrs.horizontalMargin * pw),
                (int) (y + attrs.verticalMargin * ph), outFrame);
        // Now make sure the window fits in the overall display frame.
        if (fitToDisplay) {
            Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame);
        }

        if (DEBUG) Log.d(TAG, "computeWindowFrames " + attrs.getTitle()
                + " outFrame=" + outFrame.toShortString()
                + " outParentFrame=" + outParentFrame.toShortString()
                + " outDisplayFrame=" + outDisplayFrame.toShortString()
                + " attachedWindowFrame=" + (attachedWindowFrame != null
                        ? attachedWindowFrame.toShortString()
                        : "null")
                + " requestedWidth=" + requestedWidth
                + " requestedHeight=" + requestedHeight
                + " compatScale=" + compatScale
                + " windowingMode=" + WindowConfiguration.windowingModeToString(windowingMode)
                + " displayCutoutSafe=" + displayCutoutSafe
                + " attrs=" + attrs
                + " state=" + state
                + " requestedVisibilities=" + requestedVisibilities);

        return clippedByDisplayCutout;
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -527,7 +527,7 @@ message ConfigurationContainerProto {
message WindowFramesProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    optional .android.graphics.RectProto containing_frame = 1;
    optional .android.graphics.RectProto containing_frame = 1 [deprecated=true];
    optional .android.graphics.RectProto content_frame = 2 [deprecated=true];
    optional .android.graphics.RectProto decor_frame = 3 [deprecated=true];
    optional .android.graphics.RectProto display_frame = 4;
+28 −25
Original line number Diff line number Diff line
@@ -802,13 +802,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    };

    private final Consumer<WindowState> mPerformLayout = w -> {
        if (w.mLayoutAttached || w.skipLayout()) {
            return;
        }

        // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid
        // wasting time and funky changes while a window is animating away.
        final boolean gone = w.isGoneForLayout();

        if (DEBUG_LAYOUT && !w.mLayoutAttached) {
        if (DEBUG_LAYOUT) {
            Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame
                    + " mLayoutAttached=" + w.mLayoutAttached
                    + " config reported=" + w.isLastConfigReportedToClient());
            final ActivityRecord activity = w.mActivityRecord;
            if (gone) Slog.v(TAG, "  GONE: mViewVisibility=" + w.mViewVisibility
@@ -824,7 +827,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        // If this view is GONE, then skip it -- keep the current frame, and let the caller know
        // so they can ignore it if they want.  (We do the normal layout for INVISIBLE windows,
        // since that means "perform layout as normal, just don't display").
        if ((!gone || !w.mHaveFrame || w.mLayoutNeeded) && !w.mLayoutAttached) {
        if (!gone || !w.mHaveFrame || w.mLayoutNeeded) {
            if (mTmpInitial) {
                w.resetContentChanged();
            }
@@ -851,13 +854,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            }

            if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.getFrame()
                    + " mContainingFrame=" + w.getContainingFrame()
                    + " mParentFrame=" + w.getParentFrame()
                    + " mDisplayFrame=" + w.getDisplayFrame());
        }
    };

    private final Consumer<WindowState> mPerformLayoutAttached = w -> {
        if (w.mLayoutAttached) {
        if (!w.mLayoutAttached || w.skipLayout()) {
            return;
        }
        if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame
                + " mViewVisibility=" + w.mViewVisibility
                + " mRelayoutCalled=" + w.mRelayoutCalled);
@@ -867,7 +872,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame
                || w.mLayoutNeeded) {
            if (mTmpInitial) {
                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                w.resetContentChanged();
            }
            w.mSurfacePlacementNeeded = true;
@@ -876,10 +880,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
            w.mLayoutSeq = mLayoutSeq;
            if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame()
                        + " mContainingFrame=" + w.getContainingFrame()
                    + " mParentFrame=" + w.getParentFrame()
                    + " mDisplayFrame=" + w.getDisplayFrame());
        }
        }
    };

    private final Predicate<WindowState> mComputeImeTargetPredicate = w -> {
+30 −22
Original line number Diff line number Diff line
@@ -43,12 +43,12 @@ import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_B
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS;
import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -65,7 +65,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
@@ -1719,10 +1718,6 @@ public class DisplayPolicy {
            layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR));
            return;
        }
        if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) {
            // Skip layout of the window when in transition to pip mode.
            return;
        }
        final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);

        final int type = attrs.type;
@@ -1734,37 +1729,50 @@ public class DisplayPolicy {

        final Rect pf = windowFrames.mParentFrame;
        final Rect df = windowFrames.mDisplayFrame;
        final Rect f = windowFrames.mFrame;
        final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null;
        sTmpLastParentFrame.set(pf);

        final Rect winBounds;
        final int requestedWidth;
        final int requestedHeight;
        if (windowFrames.mIsSimulatingDecorWindow) {
            // Override the bounds in window token has many side effects. Directly use the display
        // frame set for the simulated layout for this case.
        final Rect winBounds = windowFrames.mIsSimulatingDecorWindow ? df : win.getBounds();
            // frame set for the simulated layout.
            winBounds = df;

            // The view hierarchy has not been measured in the simulated layout. Use
            // UNSPECIFIED_LENGTH as the requested width and height so that WindowLayout will choose
            // the proper values in this case.
            requestedWidth = UNSPECIFIED_LENGTH;
            requestedHeight = UNSPECIFIED_LENGTH;
        } else {
            winBounds = win.getBounds();
            requestedWidth = win.mRequestedWidth;
            requestedHeight = win.mRequestedHeight;
        }

        final boolean clippedByDisplayCutout = mWindowLayout.computeWindowFrames(attrs,
                win.getInsetsState(), displayFrames.mDisplayCutoutSafe, winBounds,
                win.getRequestedVisibilities(), attachedWindowFrame, df, pf);
                win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
                winBounds, win.getWindowingMode(), requestedWidth, requestedHeight,
                win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
                df, pf, f);
        windowFrames.setParentFrameWasClippedByDisplayCutout(clippedByDisplayCutout);

        // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
        // Also, we don't allow windows in multi-window mode to extend out of the screen.
        if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
                && !win.inMultiWindowMode()) {
            df.left = df.top = -10000;
            df.right = df.bottom = 10000;
        }

        if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
                + ": sim=#" + Integer.toHexString(sim)
                + " attach=" + attached + " type=" + type
                + String.format(" flags=0x%08x", fl)
                + " pf=" + pf.toShortString() + " df=" + df.toShortString());
                + " flags=" + ViewDebug.flagsToString(LayoutParams.class, "flags", fl)
                + " pf=" + pf.toShortString() + " df=" + df.toShortString()
                + " f=" + f.toShortString());

        if (!sTmpLastParentFrame.equals(pf)) {
            windowFrames.setContentChanged(true);
        }

        win.computeFrameAndUpdateSourceFrame(displayFrames);
        if (!windowFrames.mIsSimulatingDecorWindow) {
            win.setFrame();
        }
    }

    WindowState getTopFullscreenOpaqueWindow() {
Loading