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

Commit 80438479 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce a near-pure method to layout display"

parents 4fa449f9 c7175768
Loading
Loading
Loading
Loading
+104 −43
Original line number Diff line number Diff line
@@ -335,6 +335,13 @@ public class DisplayPolicy {

    IApplicationToken mFocusedApp;

    // The states of decor windows from the last layout. These are used to generate another display
    // layout in different bounds but with the same states.
    private boolean mLastNavVisible;
    private boolean mLastNavTranslucent;
    private boolean mLastNavAllowedHidden;
    private boolean mLastNotificationShadeForcesShowingNavigation;

    int mLastSystemUiFlags;
    // Bits that we are in the process of clearing, so we want to prevent
    // them from being set by applications until everything has been updated
@@ -1425,6 +1432,46 @@ public class DisplayPolicy {
        }
    }

    private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames, int uiMode,
            InsetsState insetsState, WindowFrames simulatedWindowFrames, Runnable layout) {
        win.setSimulatedWindowFrames(simulatedWindowFrames);
        try {
            layout.run();
        } finally {
            win.setSimulatedWindowFrames(null);
        }
        mDisplayContent.getInsetsStateController().computeSimulatedState(insetsState, win,
                displayFrames, simulatedWindowFrames);
    }

    /**
     * Computes the frames of display (its logical size, rotation and cutout should already be set)
     * used to layout window. The result of display frames and insets state should be the same as
     * using {@link #beginLayoutLw}, but this method only changes the given display frames, insets
     * state and some temporal states. In other words, it doesn't change the window frames used to
     * show on screen.
     */
    void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState, int uiMode) {
        displayFrames.onBeginLayout();
        final WindowFrames simulatedWindowFrames = new WindowFrames();
        if (mNavigationBar != null) {
            simulateLayoutDecorWindow(
                    mNavigationBar, displayFrames, uiMode, insetsState, simulatedWindowFrames,
                    () -> layoutNavigationBar(displayFrames, uiMode, mLastNavVisible,
                            mLastNavTranslucent, mLastNavAllowedHidden,
                            mLastNotificationShadeForcesShowingNavigation,
                            false /* isRealLayout */));
        }
        if (mStatusBar != null) {
            simulateLayoutDecorWindow(
                    mStatusBar, displayFrames, uiMode, insetsState, simulatedWindowFrames,
                    () -> layoutStatusBar(displayFrames, mLastSystemUiFlags,
                            false /* isRealLayout */));
        }
        layoutScreenDecorWindows(displayFrames, simulatedWindowFrames);
        postAdjustDisplayFrames(displayFrames);
    }

    /**
     * Called when layout of the windows is about to start.
     *
@@ -1483,14 +1530,23 @@ public class DisplayPolicy {
        navVisible |= !canHideNavigationBar();

        boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
                navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation);
                navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation,
                true /* isRealLayout */);
        if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
        updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
        updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, true /* isRealLayout */);
        if (updateSysUiVisibility) {
            updateSystemUiVisibilityLw();
        }
        layoutScreenDecorWindows(displayFrames);
        layoutScreenDecorWindows(displayFrames, null /* transientFrames */);
        postAdjustDisplayFrames(displayFrames);
        mLastNavVisible = navVisible;
        mLastNavTranslucent = navTranslucent;
        mLastNavAllowedHidden = navAllowedHidden;
        mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation;
    }

    /** Enforces the last layout policy for display frames. */
    private void postAdjustDisplayFrames(DisplayFrames displayFrames) {
        if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
            // Make sure that the zone we're avoiding for the cutout is at least as tall as the
            // status bar; otherwise fullscreen apps will end up cutting halfway into the status
@@ -1509,7 +1565,15 @@ public class DisplayPolicy {
        displayFrames.mContent.inset(mForwardedInsets);
    }

    private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
    /**
     * Layout the decor windows with {@link #PRIVATE_FLAG_IS_SCREEN_DECOR}.
     *
     * @param displayFrames The display frames to be layouted.
     * @param simulatedFrames Non-null if the caller only needs the result of display frames (see
     *                        {@link WindowState#mSimulatedWindowFrames}).
     */
    private void layoutScreenDecorWindows(DisplayFrames displayFrames,
            WindowFrames simulatedFrames) {
        if (mScreenDecorWindows.isEmpty()) {
            return;
        }
@@ -1527,17 +1591,24 @@ public class DisplayPolicy {
                continue;
            }

            w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
            final boolean isSimulatedLayout = simulatedFrames != null;
            if (isSimulatedLayout) {
                w.setSimulatedWindowFrames(simulatedFrames);
            }
            final WindowFrames windowFrames = w.getLayoutingWindowFrames();
            windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
                    displayFrames.mUnrestricted /* displayFrame */,
                    displayFrames.mUnrestricted /* contentFrame */,
                    displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
                    displayFrames.mUnrestricted /* stableFrame */);
            w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
            w.computeFrameLw();
            if (w.getControllableInsetProvider() != null) {
                w.getControllableInsetProvider().updateSourceFrame();
            try {
                w.computeFrame(displayFrames);
            } finally {
                if (isSimulatedLayout) {
                    w.setSimulatedWindowFrames(null);
                }
            final Rect frame = w.getFrameLw();
            }
            final Rect frame = windowFrames.mFrame;

            if (frame.left <= 0 && frame.top <= 0) {
                // Docked at left or top.
@@ -1580,29 +1651,21 @@ public class DisplayPolicy {
        displayFrames.mContent.set(dockFrame);
    }

    private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
            boolean isKeyguardShowing) {
    private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui, boolean isRealLayout) {
        // decide where the status bar goes ahead of time
        if (mStatusBar == null) {
            return false;
        }
        // apply any navigation bar insets
        sTmpRect.setEmpty();
        final WindowFrames windowFrames = mStatusBar.getWindowFrames();
        final WindowFrames windowFrames = mStatusBar.getLayoutingWindowFrames();
        windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
                displayFrames.mUnrestricted /* displayFrame */,
                displayFrames.mStable /* contentFrame */,
                displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
                displayFrames.mStable /* stableFrame */);
        windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);

        // Let the status bar determine its size.
        mStatusBar.computeFrameLw();

        // Update the source frame to provide insets to other windows during layout.
        if (mStatusBar.getControllableInsetProvider() != null) {
            mStatusBar.getControllableInsetProvider().updateSourceFrame();
        }
        mStatusBar.computeFrame(displayFrames);

        // For layout, the status bar is always at the top with our fixed height.
        displayFrames.mStable.top = displayFrames.mUnrestricted.top
@@ -1611,12 +1674,14 @@ public class DisplayPolicy {
        displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
                displayFrames.mDisplayCutoutSafe.top);

        // Tell the bar controller where the collapsed status bar content is
        sTmpRect.set(mStatusBar.getContentFrameLw());
        if (isRealLayout) {
            // Tell the bar controller where the collapsed status bar content is.
            sTmpRect.set(windowFrames.mContentFrame);
            sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
        sTmpRect.top = mStatusBar.getContentFrameLw().top;  // Ignore top display cutout inset
            sTmpRect.top = windowFrames.mContentFrame.top; // Ignore top display cutout inset
            sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
            mStatusBarController.setContentFrame(sTmpRect);
        }

        boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0
                || mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR);
@@ -1651,7 +1716,7 @@ public class DisplayPolicy {

    private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
            boolean navTranslucent, boolean navAllowedHidden,
            boolean statusBarForcesShowingNavigation) {
            boolean statusBarForcesShowingNavigation, boolean isRealLayout) {
        if (mNavigationBar == null) {
            return false;
        }
@@ -1665,13 +1730,13 @@ public class DisplayPolicy {
        final int displayHeight = displayFrames.mDisplayHeight;
        final int displayWidth = displayFrames.mDisplayWidth;
        final Rect dockFrame = displayFrames.mDock;
        mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
        final int navBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);

        final Rect cutoutSafeUnrestricted = sTmpRect;
        cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
        cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);

        if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
        if (navBarPosition == NAV_BAR_BOTTOM) {
            // It's a system nav bar or a portrait screen; nav bar goes on bottom.
            final int top = cutoutSafeUnrestricted.bottom
                    - getNavigationBarHeight(rotation, uiMode);
@@ -1695,7 +1760,7 @@ public class DisplayPolicy {
                // of animating on or off, then we can tell the app that it is covered by it.
                displayFrames.mSystem.bottom = top;
            }
        } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
        } else if (navBarPosition == NAV_BAR_RIGHT) {
            // Landscape screen; nav bar goes to the right.
            final int left = cutoutSafeUnrestricted.right
                    - getNavigationBarWidth(rotation, uiMode);
@@ -1717,7 +1782,7 @@ public class DisplayPolicy {
                // animating on or off, then we can tell the app that it is covered by it.
                displayFrames.mSystem.right = left;
            }
        } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
        } else if (navBarPosition == NAV_BAR_LEFT) {
            // Seascape screen; nav bar goes to the left.
            final int right = cutoutSafeUnrestricted.left
                    + getNavigationBarWidth(rotation, uiMode);
@@ -1748,17 +1813,17 @@ public class DisplayPolicy {
        displayFrames.mContent.set(dockFrame);
        // And compute the final frame.
        sTmpRect.setEmpty();
        mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
        final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames();
        windowFrames.setFrames(navigationFrame /* parentFrame */,
                navigationFrame /* displayFrame */,
                displayFrames.mDisplayCutoutSafe /* contentFrame */,
                navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
                navigationFrame /* stableFrame */);
        mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
        mNavigationBar.computeFrameLw();
        if (mNavigationBar.getControllableInsetProvider() != null) {
            mNavigationBar.getControllableInsetProvider().updateSourceFrame();
        mNavigationBar.computeFrame(displayFrames);
        if (isRealLayout) {
            mNavigationBarPosition = navBarPosition;
            mNavigationBarController.setContentFrame(windowFrames.mContentFrame);
        }
        mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());

        if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
        return mNavigationBarController.checkHiddenLw();
@@ -1886,7 +1951,6 @@ public class DisplayPolicy {
        final Rect sf = windowFrames.mStableFrame;
        dcf.setEmpty();
        windowFrames.setParentFrameWasClippedByDisplayCutout(false);
        windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);

        final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
                && mNavigationBar.isVisibleLw();
@@ -2311,10 +2375,7 @@ public class DisplayPolicy {
            windowFrames.setContentChanged(true);
        }

        win.computeFrameLw();
        if (win.getControllableInsetProvider() != null) {
            win.getControllableInsetProvider().updateSourceFrame();
        }
        win.computeFrame(displayFrames);
        // Dock windows carve out the bottom of the screen, so normal windows
        // can't appear underneath them.
        if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
+11 −0
Original line number Diff line number Diff line
@@ -186,6 +186,17 @@ class InsetsSourceProvider {
        }
    }

    /** @return A new source computed by the specified window frame in the given display frames. */
    InsetsSource createSimulatedSource(DisplayFrames displayFrames, WindowFrames windowFrames) {
        final InsetsSource source = new InsetsSource(mSource);
        mTmpRect.set(windowFrames.mFrame);
        if (mFrameProvider != null) {
            mFrameProvider.accept(displayFrames, mWin, mTmpRect);
        }
        source.setFrame(mTmpRect);
        return source;
    }

    /**
     * Called when a layout pass has occurred.
     */
+18 −0
Original line number Diff line number Diff line
@@ -179,6 +179,24 @@ class InsetsStateController {
        }
    }

    /**
     * Computes insets state of the insets provider window in the display frames.
     *
     * @param state The output state.
     * @param win The owner window of insets provider.
     * @param displayFrames The display frames to create insets source.
     * @param windowFrames The specified frames to represent the owner window.
     */
    void computeSimulatedState(InsetsState state, WindowState win, DisplayFrames displayFrames,
            WindowFrames windowFrames) {
        for (int i = mProviders.size() - 1; i >= 0; i--) {
            final InsetsSourceProvider provider = mProviders.valueAt(i);
            if (provider.mWin == win) {
                state.addSource(provider.createSimulatedSource(displayFrames, windowFrames));
            }
        }
    }

    boolean isFakeTarget(@InternalInsetsType int type, InsetsControlTarget target) {
        return mTypeFakeControlTargetMap.get(type) == target;
    }
+115 −84

File changed.

Preview size limit exceeded, changes collapsed.

+51 −1
Original line number Diff line number Diff line
@@ -73,6 +73,9 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * Tests for the {@link DisplayPolicy} class.
 *
@@ -122,9 +125,13 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
    }

    private void updateDisplayFrames() {
        mFrames = createDisplayFrames();
    }

    private DisplayFrames createDisplayFrames() {
        final Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
                mHasDisplayCutout);
        mFrames = new DisplayFrames(mDisplayContent.getDisplayId(), info.first, info.second);
        return new DisplayFrames(mDisplayContent.getDisplayId(), info.first, info.second);
    }

    @Test
@@ -824,6 +831,49 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
        assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
    }

    /**
     * Verify that {@link DisplayPolicy#simulateLayoutDisplay} outputs the same display frames as
     * {@link DisplayPolicy#beginLayoutLw}.
     */
    @Test
    public void testSimulateLayoutDisplay() {
        assertSimulateLayoutSameDisplayFrames();
        setRotation(ROTATION_90);
        assertSimulateLayoutSameDisplayFrames();
        addDisplayCutout();
        assertSimulateLayoutSameDisplayFrames();
    }

    private void assertSimulateLayoutSameDisplayFrames() {
        final int uiMode = 0;
        final String prefix = "";
        final InsetsState simulatedInsetsState = new InsetsState();
        final DisplayFrames simulatedDisplayFrames = createDisplayFrames();
        mDisplayContent.mDisplayFrames = mFrames;
        mDisplayPolicy.beginLayoutLw(mFrames, uiMode);
        mDisplayContent.getInsetsStateController().onPostLayout();
        mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState, uiMode);

        final StringWriter realFramesDump = new StringWriter();
        mFrames.dump(prefix, new PrintWriter(realFramesDump));
        final StringWriter simulatedFramesDump = new StringWriter();
        simulatedDisplayFrames.dump(prefix, new PrintWriter(simulatedFramesDump));

        assertEquals(realFramesDump.toString(), simulatedFramesDump.toString());

        final StringWriter realInsetsDump = new StringWriter();
        final InsetsState realInsetsState = new InsetsState(
                mDisplayContent.getInsetsStateController().getRawInsetsState());
        // Exclude comparing IME insets because currently the simulated layout only focuses on the
        // insets from status bar and navigation bar.
        realInsetsState.removeSource(InsetsState.ITYPE_IME);
        realInsetsState.dump(prefix, new PrintWriter(realInsetsDump));
        final StringWriter simulatedInsetsDump = new StringWriter();
        simulatedInsetsState.dump(prefix, new PrintWriter(simulatedInsetsDump));

        assertEquals(realInsetsDump.toString(), simulatedInsetsDump.toString());
    }

    @Test
    public void forceShowSystemBars_clearsSystemUIFlags() {
        mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN;