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

Commit b7e653ef authored by Mariia Sandrikova's avatar Mariia Sandrikova
Browse files

Refactor letterbox logic in separate classes.

Changes:
- Moves logic related to letterbox UI from ActivityRecord to LetterboxUiController.
- Moves logic related to letterbox config values and their get/set/reset methods from WindowManagerService to LetterboxConfiguration.
- Replace multiple letterbox ADB commands with one.

Fix: 183754168
Test: atest SizeCompatTests and adb shell cmd window get|set|reset-letterbox-style
Change-Id: Ic70c900f4f6571f8ecb7c7d5edc2a24014b766ed
parent 5b145133
Loading
Loading
Loading
Loading
+22 −236
Original line number Diff line number Diff line
@@ -189,6 +189,7 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
@@ -215,14 +216,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND;
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING;
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_SOLID_COLOR;
import static com.android.server.wm.WindowManagerService.LETTERBOX_BACKGROUND_WALLPAPER;
import static com.android.server.wm.WindowManagerService.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.letterboxBackgroundTypeToString;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
@@ -268,7 +263,6 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -344,7 +338,6 @@ import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.Task.ActivityState;
import com.android.server.wm.WindowManagerService.H;
import com.android.server.wm.WindowManagerService.LetterboxBackgroundType;
import com.android.server.wm.utils.InsetUtils;

import com.google.android.collect.Sets;
@@ -642,7 +635,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
     */
    private boolean mWillCloseOrEnterPip;

    private Letterbox mLetterbox;
    @VisibleForTesting
    final LetterboxUiController mLetterboxUiController;

    /**
     * The scale to fit at least one side of the activity to its parent. If the activity uses
@@ -671,8 +665,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    @Nullable
    private Rect mLetterboxBoundsForFixedOrientationAndAspectRatio;

    private boolean mShowWallpaperForLetterboxBackground;

    // activity is not displayed?
    // TODO: rename to mNoDisplay
    @VisibleForTesting
@@ -1097,61 +1089,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            }
        }

        dumpLetterboxInfo(pw, prefix);
    }

    private void dumpLetterboxInfo(PrintWriter pw, String prefix) {
        final WindowState mainWin = findMainWindow();
        if (mainWin == null) {
            return;
        }

        boolean areBoundsLetterboxed = mainWin.isLetterboxedAppWindow();
        pw.println(prefix + "areBoundsLetterboxed=" + areBoundsLetterboxed);
        if (!areBoundsLetterboxed) {
            return;
        }

        pw.println(prefix + "  letterboxReason=" + getLetterboxReasonString(mainWin));
        pw.println(prefix + "  letterboxAspectRatio=" + computeAspectRatio(getBounds()));

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

        if (!isLetterboxUiShown) {
            return;
        }
        pw.println(prefix + "  letterboxBackgroundColor=" + Integer.toHexString(
                getLetterboxBackgroundColor().toArgb()));
        pw.println(prefix + "  letterboxBackgroundType="
                + letterboxBackgroundTypeToString(mWmService.getLetterboxBackgroundType()));
        if (mWmService.getLetterboxBackgroundType() == LETTERBOX_BACKGROUND_WALLPAPER) {
            pw.println(prefix + "  isLetterboxWallpaperBlurSupported="
                    + isLetterboxWallpaperBlurSupported());
            pw.println(prefix + "  letterboxBackgroundWallpaperDarkScrimAlpha="
                    + getLetterboxWallpaperDarkScrimAlpha());
            pw.println(prefix + "  letterboxBackgroundWallpaperBlurRadius="
                    + getLetterboxWallpaperBlurRadius());
        }
        pw.println(prefix + "  letterboxHorizontalPositionMultiplier="
                + mWmService.getLetterboxHorizontalPositionMultiplier());
    }

    /**
     * Returns a string representing the reason for letterboxing. This method assumes the activity
     * is letterboxed.
     */
    private String getLetterboxReasonString(WindowState mainWin) {
        if (inSizeCompatMode()) {
            return "SIZE_COMPAT_MODE";
        }
        if (isLetterboxedForFixedOrientationAndAspectRatio()) {
            return "FIXED_ORIENTATION";
        }
        if (mainWin.isLetterboxedForDisplayCutout()) {
            return "DISPLAY_CUTOUT";
        }
        return "UNKNOWN_REASON";
        mLetterboxUiController.dump(pw, prefix);
    }

    void setAppTimeTracker(AppTimeTracker att) {
@@ -1417,183 +1355,29 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            }
        }

        if (mLetterbox != null) {
            mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId());
        }
        mLetterboxUiController.onMovedToDisplay(mDisplayContent.getDisplayId());
    }

    // TODO(b/183754168): Move letterbox UI logic into a separate class.
    void layoutLetterbox(WindowState winHint) {
        final WindowState w = findMainWindow();
        if (w == null || winHint != null && w != winHint) {
            return;
        }
        final boolean surfaceReady = w.isDrawn()  // Regular case
                || w.isDragResizeChanged();  // Waiting for relayoutWindow to call preserveSurface.
        final boolean needsLetterbox = surfaceReady && isLetterboxed(w);
        updateRoundedCorners(w);
        updateWallpaperForLetterbox(w);
        if (needsLetterbox) {
            if (mLetterbox == null) {
                mLetterbox = new Letterbox(() -> makeChildSurface(null),
                        mWmService.mTransactionFactory,
                        mWmService::isLetterboxActivityCornersRounded,
                        this::getLetterboxBackgroundColor,
                        this::hasWallpaperBackgroudForLetterbox,
                        this::getLetterboxWallpaperBlurRadius,
                        this::getLetterboxWallpaperDarkScrimAlpha);
                mLetterbox.attachInput(w);
            }
            getPosition(mTmpPoint);
            // Get the bounds of the "space-to-fill". The transformed bounds have the highest
            // priority because the activity is launched in a rotated environment. In multi-window
            // mode, the task-level represents this. In fullscreen-mode, the task container does
            // (since the orientation letterbox is also applied to the task).
            final Rect transformedBounds = getFixedRotationTransformDisplayBounds();
            final Rect spaceToFill = transformedBounds != null
                    ? transformedBounds
                    : inMultiWindowMode()
                            ? getRootTask().getBounds()
                            : getRootTask().getParent().getBounds();
            mLetterbox.layout(spaceToFill, w.getFrame(), mTmpPoint);
        } else if (mLetterbox != null) {
            mLetterbox.hide();
        }
    }

    private Color getLetterboxBackgroundColor() {
        final WindowState w = findMainWindow();
        if (w == null || w.isLetterboxedForDisplayCutout()) {
            return Color.valueOf(Color.BLACK);
        }
        @LetterboxBackgroundType int letterboxBackgroundType =
                mWmService.getLetterboxBackgroundType();
        switch (letterboxBackgroundType) {
            case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING:
                if (taskDescription != null && taskDescription.getBackgroundColorFloating() != 0) {
                    return Color.valueOf(taskDescription.getBackgroundColorFloating());
                }
                break;
            case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND:
                if (taskDescription != null && taskDescription.getBackgroundColor() != 0) {
                    return Color.valueOf(taskDescription.getBackgroundColor());
                }
                break;
            case LETTERBOX_BACKGROUND_WALLPAPER:
                if (hasWallpaperBackgroudForLetterbox()) {
                    // Color is used for translucent scrim that dims wallpaper.
                    return Color.valueOf(Color.BLACK);
                }
                Slog.w(TAG, "Wallpaper option is selected for letterbox background but "
                        + "blur is not supported by a device or not supported in the current "
                        + "window configuration or both alpha scrim and blur radius aren't "
                        + "provided so using solid color background");
                break;
            case LETTERBOX_BACKGROUND_SOLID_COLOR:
                return mWmService.getLetterboxBackgroundColor();
            default:
                throw new AssertionError(
                    "Unexpected letterbox background type: " + letterboxBackgroundType);
        }
        // If picked option configured incorrectly or not supported then default to a solid color
        // background.
        return mWmService.getLetterboxBackgroundColor();
    }

    /**
     * @return {@code true} when the main window is letterboxed, this activity isn't transparent
     * and doesn't show a wallpaper.
     */
    @VisibleForTesting
    boolean isLetterboxed(WindowState mainWindow) {
        return mainWindow.isLetterboxedAppWindow() && 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.
                && (mainWindow.mAttrs.flags & FLAG_SHOW_WALLPAPER) == 0;
    }

    private void updateRoundedCorners(WindowState mainWindow) {
        int cornersRadius =
                // Don't round corners if letterboxed only for display cutout.
                isLetterboxed(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout()
                        ? Math.max(0, mWmService.getLetterboxActivityCornersRadius()) : 0;
        setCornersRadius(mainWindow, cornersRadius);
    }

    private void setCornersRadius(WindowState mainWindow, int cornersRadius) {
        final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
        if (windowSurface != null && windowSurface.isValid()) {
            Transaction transaction = getSyncTransaction();
            transaction.setCornerRadius(windowSurface, cornersRadius);
        }
        mLetterboxUiController.layoutLetterbox(winHint);
    }

    boolean hasWallpaperBackgroudForLetterbox() {
        return mShowWallpaperForLetterboxBackground;
    }

    private void updateWallpaperForLetterbox(WindowState mainWindow) {
        @LetterboxBackgroundType int letterboxBackgroundType =
                mWmService.getLetterboxBackgroundType();
        boolean wallpaperShouldBeShown =
                letterboxBackgroundType == LETTERBOX_BACKGROUND_WALLPAPER
                        && isLetterboxed(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
                        && (getLetterboxWallpaperBlurRadius() > 0
                                || getLetterboxWallpaperDarkScrimAlpha() > 0)
                        // Check that blur is supported by a device if blur radius is provided.
                        && (getLetterboxWallpaperBlurRadius() <= 0
                                || isLetterboxWallpaperBlurSupported());
        if (mShowWallpaperForLetterboxBackground != wallpaperShouldBeShown) {
            mShowWallpaperForLetterboxBackground = wallpaperShouldBeShown;
            requestUpdateWallpaperIfNeeded();
        }
    }

    private int getLetterboxWallpaperBlurRadius() {
        int blurRadius = mWmService.getLetterboxBackgroundWallpaperBlurRadius();
        return blurRadius < 0 ? 0 : blurRadius;
    }

    private float getLetterboxWallpaperDarkScrimAlpha() {
        float alpha = mWmService.getLetterboxBackgroundWallpaperDarkScrimAlpha();
        // No scrim by default.
        return (alpha < 0 || alpha >= 1) ? 0.0f : alpha;
    }

    private boolean isLetterboxWallpaperBlurSupported() {
        return mWmService.mContext.getSystemService(WindowManager.class).isCrossWindowBlurEnabled();
        return mLetterboxUiController.hasWallpaperBackgroudForLetterbox();
    }

    void updateLetterboxSurface(WindowState winHint) {
        final WindowState w = findMainWindow();
        if (w != winHint && winHint != null && w != null) {
            return;
        }
        layoutLetterbox(winHint);
        if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
            mLetterbox.applySurfaceChanges(getSyncTransaction());
        }
        mLetterboxUiController.updateLetterboxSurface(winHint);
    }

    /** Gets the letterbox insets. The insets will be empty if there is no letterbox. */
    Rect getLetterboxInsets() {
        if (mLetterbox != null) {
            return mLetterbox.getInsets();
        } else {
            return new Rect();
        }
        return mLetterboxUiController.getLetterboxInsets();
    }

    /** Gets the inner bounds of letterbox. The bounds will be empty if there is no letterbox. */
    void getLetterboxInnerBounds(Rect outBounds) {
        if (mLetterbox != null) {
            outBounds.set(mLetterbox.getInnerFrame());
        } else {
            outBounds.setEmpty();
        }
        mLetterboxUiController.getLetterboxInnerBounds(outBounds);
    }

    /**
@@ -1601,7 +1385,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
     *     when the current activity is displayed.
     */
    boolean isFullyTransparentBarAllowed(Rect rect) {
        return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect);
        return mLetterboxUiController.isFullyTransparentBarAllowed(rect);
    }

    /**
@@ -1609,7 +1393,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
     * the given {@code rect}.
     */
    boolean isLetterboxOverlappingWith(Rect rect) {
        return mLetterbox != null && mLetterbox.isOverlappingWith(rect);
        return mLetterboxUiController.isLetterboxOverlappingWith(rect);
    }

    static class Token extends IApplicationToken.Stub {
@@ -1858,6 +1642,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

        mPersistentState = persistentState;
        taskDescription = _taskDescription;

        mLetterboxUiController = new LetterboxUiController(mWmService, this);

        if (_createTime > 0) {
            createTime = _createTime;
        }
@@ -3689,10 +3476,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            dc.setFocusedApp(null);
            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
        }
        if (mLetterbox != null) {
            mLetterbox.destroy();
            mLetterbox = null;
        }

        mLetterboxUiController.destroy();

        if (!delayed) {
            updateReportedVisibilityLocked();
@@ -7113,7 +6898,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            offsetX = getHorizontalCenterOffset(
                    parentAppBounds.width(), screenResolvedBounds.width());
        } else {
            float positionMultiplier = mWmService.getLetterboxHorizontalPositionMultiplier();
            float positionMultiplier =
                    mWmService.mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier();
            positionMultiplier =
                    (positionMultiplier < 0.0f || positionMultiplier > 1.0f)
                            // Default to central position if invalid value is provided.
@@ -7186,7 +6972,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
        // set-fixed-orientation-letterbox-aspect-ratio.
        final float letterboxAspectRatioOverride =
                mWmService.getFixedOrientationLetterboxAspectRatio();
                mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
        aspect = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
                ? letterboxAspectRatioOverride : aspect;

@@ -7704,7 +7490,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    /**
     * Returns the aspect ratio of the given {@code rect}.
     */
    private static float computeAspectRatio(Rect rect) {
    static float computeAspectRatio(Rect rect) {
        final int width = rect.width();
        final int height = rect.height();
        if (width == 0 || height == 0) {
+328 −0

File added.

Preview size limit exceeded, changes collapsed.

+336 −0

File added.

Preview size limit exceeded, changes collapsed.

+2 −291

File changed.

Preview size limit exceeded, changes collapsed.

+196 −246

File changed.

Preview size limit exceeded, changes collapsed.

Loading