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

Commit 19c430b1 authored by Mariia Sandrikova's avatar Mariia Sandrikova Committed by Android (Google) Code Review
Browse files

Merge "Respect aspect ratio restrictions in split screen and show letterbox surfaces." into sc-dev

parents e85e1513 f2a6b9fd
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -985,7 +985,7 @@ final class AccessibilityController {
                    }

                    // Count letterbox into nonMagnifiedBounds
                    if (windowState.isLetterboxedAppWindow()) {
                    if (windowState.areAppWindowBoundsLetterboxed()) {
                        Region letterboxBounds = getLetterboxBounds(windowState);
                        nonMagnifiedBounds.op(letterboxBounds, Region.Op.UNION);
                        availableBounds.op(letterboxBounds, Region.Op.DIFFERENCE);
@@ -1758,7 +1758,7 @@ final class AccessibilityController {
                }

                // Account for the space of letterbox.
                if (windowState.isLetterboxedAppWindow()) {
                if (windowState.areAppWindowBoundsLetterboxed()) {
                    unaccountedSpace.op(getLetterboxBounds(windowState), unaccountedSpace,
                            Region.Op.REVERSE_DIFFERENCE);
                }
+50 −15
Original line number Diff line number Diff line
@@ -671,6 +671,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    // naturally.
    private boolean mInSizeCompatModeForBounds = false;

    // Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
    // TODO(b/182268157): Aspect ratio can also be applie in resolveFixedOrientationConfiguration
    // but that isn't reflected in this boolean.
    private boolean mIsAspectRatioApplied = false;

    // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
    // for fixed orientation. If not null, they are used as parent container in
    // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets. If
@@ -6994,6 +6999,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            newParentConfiguration = mTmpConfig;
        }

        mIsAspectRatioApplied = false;

        // Can't use resolvedConfig.windowConfiguration.getWindowingMode() because it can be
        // different from windowing mode of the task (PiP) during transition from fullscreen to PiP
        // and back which can cause visible issues (see b/184078928).
@@ -7011,7 +7018,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

        if (mCompatDisplayInsets != null) {
            resolveSizeCompatModeConfiguration(newParentConfiguration);
        } else if (inMultiWindowMode()) {
        } else if (inMultiWindowMode() && !isFixedOrientationLetterboxAllowed) {
            // We ignore activities' requested orientation in multi-window modes. They may be
            // taken into consideration in resolveFixedOrientationConfiguration call above.
            resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
@@ -7023,7 +7030,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
        // are already calculated in resolveFixedOrientationConfiguration.
        } else if (!isLetterboxedForFixedOrientationAndAspectRatio()) {
            resolveFullscreenConfiguration(newParentConfiguration);
            resolveAspectRatioRestriction(newParentConfiguration);
        }

        if (isFixedOrientationLetterboxAllowed || mCompatDisplayInsets != null
@@ -7071,6 +7078,26 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
    }

    /**
     * Returns whether activity bounds are letterboxed.
     *
     * <p>Note that letterbox UI may not be shown even when this returns {@code true}. See {@link
     * LetterboxUiController#shouldShowLetterboxUi} for more context.
     */
    boolean areBoundsLetterboxed() {
        if (mInSizeCompatModeForBounds) {
            return true;
        }
        // Letterbox for fixed orientation. This check returns true only when an activity is
        // letterboxed for fixed orientation. Aspect ratio restrictions are also applied if
        // present. But this doesn't return true when the activity is letterboxed only because
        // of aspect ratio restrictions.
        if (isLetterboxedForFixedOrientationAndAspectRatio()) {
            return true;
        }
        // Letterbox for limited aspect ratio.
        return mIsAspectRatioApplied;
    }

    /**
     * Adjusts horizontal position of resolved bounds if they doesn't fill the parent using gravity
@@ -7111,6 +7138,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        } else {
            offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
        }

        // Since bounds has changed, the configuration needs to be computed accordingly.
        task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
    }

    /**
@@ -7222,12 +7252,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    }

    /**
     * Resolves the configuration of activity in fullscreen mode. If the bounds are restricted by
     * aspect ratio, the position will be centered horizontally in parent's app bounds to balance
     * the visual appearance. The policy of aspect ratio has higher priority than the requested
     * override bounds.
     * Resolves aspect ratio restrictions for an activity. If the bounds are restricted by
     * aspect ratio, the position will be adjusted later in {@link
     * updateResolvedBoundsHorizontalPosition} within parent's app bounds to balance the visual
     * appearance. The policy of aspect ratio has higher priority than the requested override
     * bounds.
     */
    private void resolveFullscreenConfiguration(Configuration newParentConfiguration) {
    private void resolveAspectRatioRestriction(Configuration newParentConfiguration) {
        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
        final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
        final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
@@ -7235,11 +7266,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // Use tmp bounds to calculate aspect ratio so we can know whether the activity should use
        // restricted size (resolved bounds may be the requested override bounds).
        mTmpBounds.setEmpty();
        applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
        mIsAspectRatioApplied = applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
        // If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
        // then there is space to be centered.
        final boolean needToBeCentered = !mTmpBounds.isEmpty();
        if (needToBeCentered) {
        // then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
        if (!mTmpBounds.isEmpty()) {
            resolvedBounds.set(mTmpBounds);
            // Exclude the horizontal decor area.
            resolvedBounds.left = parentAppBounds.left;
@@ -7300,6 +7330,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        resolvedBounds.set(containingBounds);
        // The size of floating task is fixed (only swap), so the aspect ratio is already correct.
        if (!mCompatDisplayInsets.mIsFloating) {
            mIsAspectRatioApplied =
                    applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
        }
        // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in
@@ -7618,9 +7649,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    /**
     * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
     * made to outBounds.
     *
     * @return {@code true} if aspect ratio restrictions were applied.
     */
    // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
    private void applyAspectRatio(Rect outBounds, Rect containingAppBounds,
    private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
            Rect containingBounds) {
        final float maxAspectRatio = info.getMaxAspectRatio();
        final Task rootTask = getRootTask();
@@ -7632,7 +7665,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                || isInVrUiMode(getConfiguration())) {
            // We don't enforce aspect ratio if the activity task is in multiwindow unless it
            // is in size-compat mode. We also don't set it if we are in VR mode.
            return;
            return false;
        }

        final int containingAppWidth = containingAppBounds.width();
@@ -7688,7 +7721,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

        if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) {
            // The display matches or is less than the activity aspect ratio, so nothing else to do.
            return;
            return false;
        }

        // Compute configuration based on max supported width and height.
@@ -7698,6 +7731,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        outBounds.set(containingBounds.left, containingBounds.top,
                activityWidth + containingAppBounds.left,
                activityHeight + containingAppBounds.top);

        return true;
    }

    /**
+2 −5
Original line number Diff line number Diff line
@@ -3694,11 +3694,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
                && mImeLayeringTarget != null
                && mImeLayeringTarget.mActivityRecord != null
                && mImeLayeringTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
                // An activity with override bounds should be letterboxed inside its parent bounds,
                // so it doesn't fill the screen.
                && mImeLayeringTarget.mActivityRecord.matchParentBounds()
                // IME is attached to non-Letterboxed app windows, other than windows with
                // LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER flag. (Refer to WS.isLetterboxedAppWindow())
                // IME is attached to app windows that fill display area. This excludes
                // letterboxed windows.
                && mImeLayeringTarget.matchesDisplayAreaBounds();
    }

+9 −9
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ final class LetterboxUiController {
        }
        final boolean surfaceReady = w.isDrawn()  // Regular case
                || w.isDragResizeChanged();  // Waiting for relayoutWindow to call preserveSurface.
        final boolean needsLetterbox = surfaceReady && isLetterboxed(w);
        final boolean needsLetterbox = surfaceReady && shouldShowLetterboxUi(w);
        updateRoundedCorners(w);
        updateWallpaperForLetterbox(w);
        if (needsLetterbox) {
@@ -166,8 +166,8 @@ final class LetterboxUiController {
     * and doesn't show a wallpaper.
     */
    @VisibleForTesting
    boolean isLetterboxed(WindowState mainWindow) {
        return mainWindow.isLetterboxedAppWindow() && mActivityRecord.fillsParent()
    boolean shouldShowLetterboxUi(WindowState mainWindow) {
        return mainWindow.areAppWindowBoundsLetterboxed() && mActivityRecord.fillsParent()
                // Check for FLAG_SHOW_WALLPAPER explicitly instead of using
                // WindowContainer#showWallpaper because the later will return true when this
                // activity is using blurred wallpaper for letterbox backgroud.
@@ -217,7 +217,7 @@ final class LetterboxUiController {
    private void updateRoundedCorners(WindowState mainWindow) {
        int cornersRadius =
                // Don't round corners if letterboxed only for display cutout.
                isLetterboxed(mainWindow)
                shouldShowLetterboxUi(mainWindow)
                                && !mainWindow.isLetterboxedForDisplayCutout()
                        ? Math.max(0, mLetterboxConfiguration.getLetterboxActivityCornersRadius())
                        : 0;
@@ -237,7 +237,7 @@ final class LetterboxUiController {
                mLetterboxConfiguration.getLetterboxBackgroundType();
        boolean wallpaperShouldBeShown =
                letterboxBackgroundType == LETTERBOX_BACKGROUND_WALLPAPER
                        && isLetterboxed(mainWindow)
                        && shouldShowLetterboxUi(mainWindow)
                        // Don't use wallpaper as a background if letterboxed for display cutout.
                        && !mainWindow.isLetterboxedForDisplayCutout()
                        // Check that dark scrim alpha or blur radius are provided
@@ -274,7 +274,7 @@ final class LetterboxUiController {
            return;
        }

        boolean areBoundsLetterboxed = mainWin.isLetterboxedAppWindow();
        boolean areBoundsLetterboxed = mainWin.areAppWindowBoundsLetterboxed();
        pw.println(prefix + "areBoundsLetterboxed=" + areBoundsLetterboxed);
        if (!areBoundsLetterboxed) {
            return;
@@ -284,10 +284,10 @@ final class LetterboxUiController {
        pw.println(prefix + "  letterboxAspectRatio="
                + mActivityRecord.computeAspectRatio(mActivityRecord.getBounds()));

        boolean isLetterboxUiShown = isLetterboxed(mainWin);
        pw.println(prefix + "isLetterboxUiShown=" + isLetterboxUiShown);
        boolean shouldShowLetterboxUi = shouldShowLetterboxUi(mainWin);
        pw.println(prefix + "shouldShowLetterboxUi=" + shouldShowLetterboxUi);

        if (!isLetterboxUiShown) {
        if (!shouldShowLetterboxUi) {
            return;
        }
        pw.println(prefix + "  letterboxBackgroundColor=" + Integer.toHexString(
+10 −19
Original line number Diff line number Diff line
@@ -3994,24 +3994,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        return mActivityRecord == null || (mActivityRecord.matchParentBounds() && !inMultiWindowMode());
    }

    /** @return true when the window should be letterboxed. */
    boolean isLetterboxedAppWindow() {
        // Fullscreen mode but doesn't fill display area.
        if (!inMultiWindowMode() && !matchesDisplayAreaBounds()) {
            return true;
        }
        if (mActivityRecord != null) {
            // Activity in size compat.
            if (mActivityRecord.inSizeCompatMode()) {
                return true;
            }
            // Letterbox for fixed orientation.
            if (mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio()) {
                return true;
            }
        }
        // Letterboxed for display cutout.
        return isLetterboxedForDisplayCutout();
    /**
     * @return true if activity bounds are letterboxed or letterboxed for diplay cutout.
     *
     * <p>Note that letterbox UI may not be shown even when this returns {@code true}. See {@link
     * LetterboxUiController#shouldShowLetterboxUi} for more context.
     */
    boolean areAppWindowBoundsLetterboxed() {
        return mActivityRecord != null
                && (mActivityRecord.areBoundsLetterboxed() || isLetterboxedForDisplayCutout());
    }

    /** Returns {@code true} if the window is letterboxed for the display cutout. */
@@ -5824,7 +5815,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        // the status bar). In that case we need to use the final frame.
        if (inFreeformWindowingMode()) {
            outFrame.set(getFrame());
        } else if (isLetterboxedAppWindow() || mToken.isFixedRotationTransforming()) {
        } else if (areAppWindowBoundsLetterboxed() || mToken.isFixedRotationTransforming()) {
            // 1. The letterbox surfaces should be animated with the owner activity, so use task
            //    bounds to include them.
            // 2. If the activity has fixed rotation transform, its windows are rotated in activity
Loading