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

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

Merge "Don't let windows in non-fill-screen windowing modes control insets" into main

parents 0f352465 2bf469b4
Loading
Loading
Loading
Loading
+56 −22
Original line number Diff line number Diff line
@@ -31,12 +31,14 @@ 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.WindowInsetsController.BEHAVIOR_DEFAULT;
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_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_CONSUME_IME_INSETS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
@@ -82,6 +84,7 @@ import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.LoadedApk;
import android.app.ResourcesManager;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -1605,7 +1608,8 @@ public class DisplayPolicy {

            // Record the top-fullscreen-app-window which will be used to determine the system UI
            // controlling window.
            if (mTopFullscreenOpaqueWindowState == null && !exitingStartingWindow) {
            if (mTopFullscreenOpaqueWindowState == null && !exitingStartingWindow
                    && fillsDisplayWindowingMode(win)) {
                mTopFullscreenOpaqueWindowState = win;
            }

@@ -2606,30 +2610,49 @@ public class DisplayPolicy {
        updateSystemBarAttributes();
    }

    private boolean fillsDisplayWindowingMode(@NonNull WindowState win) {
        if (!com.android.window.flags.Flags.forceShowSystemBarForBubble()) {
            return true;
        }
        if (!WindowConfiguration.inMultiWindowMode(win.getWindowingMode())) {
            // Always accept the window not in multi-window mode.
            return true;
        }
        // Accept the window in multi-window mode only if it fills the display.
        // e.g., A maximized free-form window.
        final Task task = win.getTask();
        final Rect bounds = task != null ? task.getBounds() : win.getBounds();
        return bounds.equals(mDisplayContent.getBounds());
    }

    void updateSystemBarAttributes() {
        // If there is no window focused, there will be nobody to handle the events
        // anyway, so just hang on in whatever state we're in until things settle down.
        WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
        WindowState winCandidate =
                mFocusedWindow != null && fillsDisplayWindowingMode(mFocusedWindow)
                        ? mFocusedWindow
                        : mTopFullscreenOpaqueWindowState;
        if (winCandidate == null) {
        if (winCandidate == null && !com.android.window.flags.Flags.forceShowSystemBarForBubble()) {
            return;
        }

        // Immersive mode confirmation should never affect the system bar visibility, otherwise
        // it will unhide the navigation bar and hide itself.
        if ((winCandidate.mAttrs.privateFlags
        if (winCandidate != null && (winCandidate.mAttrs.privateFlags
                & PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW) != 0) {
            if (mNotificationShade != null && mNotificationShade.canReceiveKeys()) {
                // Let notification shade control the system bar visibility.
                winCandidate = mNotificationShade;
            } else if (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys()) {
            } else if (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys()
                    && fillsDisplayWindowingMode(mLastFocusedWindow)) {
                // Immersive mode confirmation took the focus from mLastFocusedWindow which was
                // controlling the system bar visibility. Let it keep controlling the visibility.
                winCandidate = mLastFocusedWindow;
            } else {
                winCandidate = mTopFullscreenOpaqueWindowState;
            }
            if (winCandidate == null) {
            if (winCandidate == null
                    && !com.android.window.flags.Flags.forceShowSystemBarForBubble()) {
                return;
            }
        }
@@ -2637,7 +2660,7 @@ public class DisplayPolicy {
        mSystemUiControllingWindow = win;

        final int displayId = getDisplayId();
        final int disableFlags = win.getDisableFlags();
        final int disableFlags = win != null ? win.getDisableFlags() : 0;
        final int opaqueAppearance = updateSystemBarsLw(win, disableFlags);
        if (!mRelaunchingSystemBarColorApps.isEmpty()) {
            // The appearance of system bars might change while relaunching apps. We don't report
@@ -2648,25 +2671,30 @@ public class DisplayPolicy {
                mDisplayContent.mInputMethodWindow, mHasBottomNavigationBar);
        final boolean isNavbarColorManagedByIme =
                navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
        final int appearance = updateLightNavigationBarLw(win.mAttrs.insetsFlags.appearance,
                navColorWin) | opaqueAppearance;
        final int appearance = updateLightNavigationBarLw(win != null
                        ? win.mAttrs.insetsFlags.appearance
                        : 0, navColorWin)
                | opaqueAppearance;
        final WindowState navBarControlWin = topAppHidesSystemBar(Type.navigationBars())
                ? mTopFullscreenOpaqueWindowState
                : win;
        final int behavior = navBarControlWin.mAttrs.insetsFlags.behavior;
        final String focusedApp = win.mAttrs.packageName;
        final boolean isFullscreen = !win.isRequestedVisible(Type.statusBars())
                || !win.isRequestedVisible(Type.navigationBars());
        final int behavior = navBarControlWin != null
                ? navBarControlWin.mAttrs.insetsFlags.behavior
                : BEHAVIOR_DEFAULT;
        final String focusedApp = win != null ? win.mAttrs.packageName : "none";
        final boolean isFullscreen = win != null && (!win.isRequestedVisible(Type.statusBars())
                || !win.isRequestedVisible(Type.navigationBars()));
        final AppearanceRegion[] statusBarAppearanceRegions =
                new AppearanceRegion[mStatusBarAppearanceRegionList.size()];
        mStatusBarAppearanceRegionList.toArray(statusBarAppearanceRegions);
        if (mLastDisableFlags != disableFlags) {
            mLastDisableFlags = disableFlags;
            final String cause = win.toString();
            final String cause = win != null ? win.toString() : "null";
            callStatusBarSafely(statusBar -> statusBar.setDisableFlags(displayId, disableFlags,
                    cause));
        }
        final @InsetsType int requestedVisibleTypes = win.getRequestedVisibleTypes();
        final @InsetsType int requestedVisibleTypes = win != null
                ? win.getRequestedVisibleTypes() : 0;
        final LetterboxDetails[] letterboxDetails = new LetterboxDetails[mLetterboxDetails.size()];
        mLetterboxDetails.toArray(letterboxDetails);
        if (mLastAppearance == appearance
@@ -2737,7 +2765,7 @@ public class DisplayPolicy {

    @VisibleForTesting
    int updateLightNavigationBarLw(int appearance, WindowState navColorWin) {
        if (navColorWin == null || !isLightBarAllowed(navColorWin, Type.navigationBars())) {
        if (!isLightBarAllowed(navColorWin, Type.navigationBars())) {
            // Clear the light flag while not allowed.
            appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
            return appearance;
@@ -2750,7 +2778,7 @@ public class DisplayPolicy {
        return appearance;
    }

    private int updateSystemBarsLw(WindowState win, int disableFlags) {
    private int updateSystemBarsLw(@Nullable WindowState win, int disableFlags) {
        final TaskDisplayArea defaultTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
        // TODO(b/407898759): Migrate to have WM Shell to override the insets visibility based on
        // top focused Task.
@@ -2798,15 +2826,17 @@ public class DisplayPolicy {
        if (wasImmersiveMode != isImmersiveMode) {
            mIsImmersiveMode = isImmersiveMode;
            // The immersive confirmation window should be attached to the immersive window root.
            final RootDisplayArea root = win.getRootDisplayArea();
            final int rootDisplayAreaId = root == null ? FEATURE_UNDEFINED : root.mFeatureId;
            final RootDisplayArea root = win != null ? win.getRootDisplayArea() : null;
            final int rootDisplayAreaId = root != null ? root.mFeatureId : FEATURE_UNDEFINED;
            final int windowType = win != null ? win.getWindowType() : INVALID_WINDOW_TYPE;
            // TODO(b/277290737): Move this to the client side, instead of using a proxy.
            callStatusBarSafely(statusBar -> statusBar.immersiveModeChanged(getDisplayId(),
                        rootDisplayAreaId, isImmersiveMode, win.getWindowType()));
                        rootDisplayAreaId, isImmersiveMode, windowType));
        }

        // Show transient bars for panic if needed.
        final boolean requestHideNavBar = !win.isRequestedVisible(Type.navigationBars());
        final boolean requestHideNavBar =
                win != null && !win.isRequestedVisible(Type.navigationBars());
        final long now = SystemClock.uptimeMillis();
        final boolean pendingPanic = mPendingPanicGestureUptime != 0
                && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
@@ -3118,6 +3148,10 @@ public class DisplayPolicy {
            pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
            pw.println(mTopFullscreenOpaqueWindowState);
        }
        if (mSystemUiControllingWindow != null) {
            pw.print(prefix); pw.print("mSystemUiControllingWindow=");
            pw.println(mSystemUiControllingWindow);
        }
        if (!mSystemBarColorApps.isEmpty()) {
            pw.print(prefix); pw.print("mSystemBarColorApps=");
            pw.println(mSystemBarColorApps);
+2 −2
Original line number Diff line number Diff line
@@ -728,7 +728,7 @@ class InsetsPolicy {
        return (mForciblyHidingTypes & types) == types;
    }

    void updateSystemBars(WindowState win, @InsetsType int displayForciblyShowingTypes,
    void updateSystemBars(@Nullable WindowState win, @InsetsType int displayForciblyShowingTypes,
            @InsetsType int displayForciblyHidingTypes, boolean showSystemBarsByLegacyPolicy) {
        final boolean hasDisplayOverride = displayForciblyShowingTypes != 0
                || displayForciblyHidingTypes != 0;
@@ -756,7 +756,7 @@ class InsetsPolicy {
        updateBarControlTarget(win);
    }

    private boolean forceShowingNavigationBars(WindowState win) {
    private boolean forceShowingNavigationBars(@Nullable WindowState win) {
        // When "force show navigation bar" is enabled, it means both force visible is true, and
        // we are in 3-button navigation. In this mode, the navigation bar is forcibly shown
        // when activity type is ACTIVITY_TYPE_STANDARD which means Launcher or Recent could
+27 −15
Original line number Diff line number Diff line
@@ -158,6 +158,22 @@ public class InsetsPolicyTest extends WindowTestsBase {
        assertNull(controls);
    }

    @Test
    @EnableFlags(Flags.FLAG_FORCE_SHOW_SYSTEM_BAR_FOR_BUBBLE)
    public void testControlsForDispatch_nonFullscreenMultiWindowTaskVisible() {
        addStatusBar();
        addNavigationBar();

        final WindowState win = newWindowBuilder("app", TYPE_APPLICATION).setActivityType(
                ACTIVITY_TYPE_STANDARD).setWindowingMode(WINDOWING_MODE_MULTI_WINDOW).setDisplay(
                mDisplayContent).build();
        win.getTask().setBounds(new Rect(1, 1, 10, 10));
        final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);

        // The non fullscreen multi window app window must not control any system bars.
        assertNull(controls);
    }

    @Test
    public void testControlsForDispatch_forceStatusBarVisible() {
        addStatusBar().mAttrs.forciblyShownTypes |= statusBars();
@@ -190,7 +206,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
        notifShade.mAttrs.forciblyShownTypes |= navigationBars();
        addNavigationBar();

        mDisplayContent.getInsetsPolicy().updateBarControlTarget(notifShade);
        mDisplayContent.getDisplayPolicy().focusChangedLw(null, notifShade);
        InsetsSourceControl[] controls
                = mDisplayContent.getInsetsStateController().getControlsForDispatch(notifShade);

@@ -232,7 +248,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
        displayPolicy.applyPostLayoutPolicyLw(dialog, dialog.mAttrs, fullscreenApp, null);
        displayPolicy.applyPostLayoutPolicyLw(fullscreenApp, fullscreenApp.mAttrs, null, null);
        displayPolicy.finishPostLayoutPolicyLw();
        mDisplayContent.getInsetsPolicy().updateBarControlTarget(dialog);
        displayPolicy.focusChangedLw(null, dialog);

        assertEquals(fullscreenApp, displayPolicy.getTopFullscreenOpaqueWindow());

@@ -255,12 +271,12 @@ public class InsetsPolicyTest extends WindowTestsBase {
        newFocusedFullscreenApp.setRequestedVisibleTypes(
                WindowInsets.Type.statusBars(), WindowInsets.Type.statusBars());
        // Make sure status bar is hidden by previous insets state.
        mDisplayContent.getInsetsPolicy().updateBarControlTarget(fullscreenApp);
        displayPolicy.focusChangedLw(dialog, fullscreenApp);

        final StatusBarManagerInternal sbmi =
                mDisplayContent.getDisplayPolicy().getStatusBarManagerInternal();
        clearInvocations(sbmi);
        mDisplayContent.getInsetsPolicy().updateBarControlTarget(newFocusedFullscreenApp);
        displayPolicy.focusChangedLw(fullscreenApp, newFocusedFullscreenApp);
        // The status bar should be shown by newFocusedFullscreenApp even
        // mTopFullscreenOpaqueWindowState is still fullscreenApp.
        verify(sbmi).setWindowState(mDisplayContent.mDisplayId, StatusBarManager.WINDOW_STATUS_BAR,
@@ -268,7 +284,7 @@ public class InsetsPolicyTest extends WindowTestsBase {

        // Add a system window: panel.
        final WindowState panel = addWindow(TYPE_STATUS_BAR_SUB_PANEL, "panel");
        mDisplayContent.getInsetsPolicy().updateBarControlTarget(panel);
        displayPolicy.focusChangedLw(newFocusedFullscreenApp, panel);

        // panel is the focused window, but it can only control navigation bar.
        // Because fullscreenApp is hiding status bar.
@@ -626,7 +642,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
        // Make both system bars invisible.
        mAppWindow.setRequestedVisibleTypes(
                0, navigationBars() | statusBars());
        policy.updateBarControlTarget(mAppWindow);
        mDisplayContent.getDisplayPolicy().focusChangedLw(null, mAppWindow);
        waitUntilWindowAnimatorIdle();
        assertFalse(mDisplayContent.getInsetsStateController().getRawInsetsState()
                .isSourceOrDefaultVisible(statusBarId, statusBars()));
@@ -656,8 +672,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
        addStatusBar().getControllableInsetProvider().getSource().setVisible(false);
        addNavigationBar().getControllableInsetProvider().setServerVisible(true);

        mDisplayContent.getDisplayPolicy().focusChangedLw(null, mAppWindow);
        final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
        policy.updateBarControlTarget(mAppWindow);
        policy.showTransient(navigationBars() | statusBars(),
                true /* isGestureOnSystemBar */);
        waitUntilWindowAnimatorIdle();
@@ -691,8 +707,8 @@ public class InsetsPolicyTest extends WindowTestsBase {
        mAppWindow.setRequestedVisibleTypes(0, navigationBars() | statusBars());
        mAppWindow.mAboveInsetsState.addSource(navBarSource);
        mAppWindow.mAboveInsetsState.addSource(statusBarSource);
        mDisplayContent.getDisplayPolicy().focusChangedLw(null, mAppWindow);
        final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
        policy.updateBarControlTarget(mAppWindow);
        policy.showTransient(navigationBars() | statusBars(),
                true /* isGestureOnSystemBar */);
        waitUntilWindowAnimatorIdle();
@@ -738,13 +754,10 @@ public class InsetsPolicyTest extends WindowTestsBase {
        final WindowState app = addWindow(TYPE_APPLICATION, "app");
        final WindowState app2 = addWindow(TYPE_APPLICATION, "app");

        mDisplayContent.getDisplayPolicy().focusChangedLw(null, app);
        final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
        policy.updateBarControlTarget(app);
        policy.showTransient(navigationBars() | statusBars(),
                true /* isGestureOnSystemBar */);
        final InsetsSourceControl[] controls =
                mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
        policy.updateBarControlTarget(app2);
        policy.showTransient(navigationBars() | statusBars(), true /* isGestureOnSystemBar */);
        mDisplayContent.getDisplayPolicy().focusChangedLw(app, app2);
        assertFalse(policy.isTransient(statusBars()));
        assertFalse(policy.isTransient(navigationBars()));
    }
@@ -941,7 +954,6 @@ public class InsetsPolicyTest extends WindowTestsBase {
        // Force update the focus in DisplayPolicy here. Otherwise, without server side focus
        // update, the policy relying on windowing type will never get updated.
        mDisplayContent.getDisplayPolicy().focusChangedLw(null, win);
        mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
        return mDisplayContent.getInsetsStateController().getControlsForDispatch(win);
    }
}