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

Commit 5b145133 authored by Mariia Sandrikova's avatar Mariia Sandrikova
Browse files

Letterbox positioning (3/3): Configurable horizontal position.

This CL finishes letterbox positioning changes started in ag/13575049 and ag/13780285.

Fix: 1752121232
Test: SizeCompatTests and manual with an ADB command
adb shell cmd window set-letterbox-horizontal-position-multiplier <multiplier>

Change-Id: I0690bd6de0d476487eaab48ad6f0583bdeaf0c2b
parent 6788d2b5
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -4697,6 +4697,11 @@
     -->
    <color name="config_letterboxBackgroundColor">#000</color>

    <!-- Horizonal position of a center of the letterboxed app window.
        0 corresponds to the left side of the screen and 1 to the right side. If given value < 0
        or > 1, it is ignored and central positionis used (0.5). -->
    <item name="config_letterboxHorizontalPositionMultiplier" format="float" type="dimen">0.5</item>

    <!-- If true, hide the display cutout with display area -->
    <bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>

+1 −0
Original line number Diff line number Diff line
@@ -4183,6 +4183,7 @@
  <java-symbol type="dimen" name="config_letterboxBackgroundWallaperDarkScrimAlpha" />
  <java-symbol type="integer" name="config_letterboxBackgroundType" />
  <java-symbol type="color" name="config_letterboxBackgroundColor" />
  <java-symbol type="dimen" name="config_letterboxHorizontalPositionMultiplier" />

  <java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />

+67 −23
Original line number Diff line number Diff line
@@ -1133,6 +1133,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            pw.println(prefix + "  letterboxBackgroundWallpaperBlurRadius="
                    + getLetterboxWallpaperBlurRadius());
        }
        pw.println(prefix + "  letterboxHorizontalPositionMultiplier="
                + mWmService.getLetterboxHorizontalPositionMultiplier());
    }

    /**
@@ -7021,11 +7023,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // and back which can cause visible issues (see b/184078928).
        final int parentWindowingMode =
                newParentConfiguration.windowConfiguration.getWindowingMode();
        final boolean isFixedOrientationLetterboxAllowed =
                isSplitScreenWindowingMode(parentWindowingMode)
                        || parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
                        || parentWindowingMode == WINDOWING_MODE_FULLSCREEN;
        // TODO(b/181207944): Consider removing the if condition and always run
        // resolveFixedOrientationConfiguration() since this should be applied for all cases.
        if (isSplitScreenWindowingMode(parentWindowingMode)
                || parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
                || parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
        if (isFixedOrientationLetterboxAllowed) {
            resolveFixedOrientationConfiguration(newParentConfiguration);
        }

@@ -7046,12 +7050,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            resolveFullscreenConfiguration(newParentConfiguration);
        }

        if (isFixedOrientationLetterboxAllowed || mCompatDisplayInsets != null
                // In fullscreen, can be letterboxed for aspect ratio.
                || !inMultiWindowMode()) {
            updateResolvedBoundsHorizontalPosition(newParentConfiguration);
        }

        if (mVisibleRequested) {
            updateCompatDisplayInsets();
        }

        // TODO(b/175212232): Consolidate position logic from each "resolve" method above here.

        // Assign configuration sequence number into hierarchy because there is a different way than
        // ensureActivityConfiguration() in this class that uses configuration in WindowState during
        // layout traversals.
@@ -7082,6 +7090,47 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
    }


    /**
     * Adjusts horizontal position of resolved bounds if they doesn't fill the parent using gravity
     * requested in the config or via an ADB command. For more context see {@link
     * WindowManagerService#getLetterboxHorizontalPositionMultiplier}.
     */
    private void updateResolvedBoundsHorizontalPosition(Configuration newParentConfiguration) {
        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
        final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
        final Rect screenResolvedBounds =
                mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds;
        final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
        final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
        if (resolvedBounds.isEmpty() || parentBounds.width() == screenResolvedBounds.width()) {
            return;
        }

        int offsetX = 0;
        if (screenResolvedBounds.width() >= parentAppBounds.width()) {
            // If resolved bounds overlap with insets, center within app bounds.
            offsetX = getHorizontalCenterOffset(
                    parentAppBounds.width(), screenResolvedBounds.width());
        } else {
            float positionMultiplier = mWmService.getLetterboxHorizontalPositionMultiplier();
            positionMultiplier =
                    (positionMultiplier < 0.0f || positionMultiplier > 1.0f)
                            // Default to central position if invalid value is provided.
                            ? 0.5f : positionMultiplier;
            offsetX = (int) Math.ceil((parentAppBounds.width() - screenResolvedBounds.width())
                    * positionMultiplier);
        }

        if (mSizeCompatBounds != null) {
            mSizeCompatBounds.offset(offsetX, 0 /* offsetY */);
            final int dx = mSizeCompatBounds.left - resolvedBounds.left;
            offsetBounds(resolvedConfig, dx,  0 /* offsetY */);
        } else {
            offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
        }
    }

    /**
     * Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
     * orientation then aspect ratio restrictions are also already respected.
@@ -7159,7 +7208,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + height);
        } else {
            final int width = (int) Math.rint(parentHeight / aspect);
            final int left = parentBounds.centerX() - width / 2;
            final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
            final int left = width <= parentAppBounds.width()
                    // Avoid overlapping with the horizontal decor area when possible.
                    ? parentAppBounds.left : parentBounds.centerX() - width / 2;
            resolvedBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
        }

@@ -7211,12 +7263,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                    getFixedRotationTransformDisplayInfo());
        }
        if (needToBeCentered) {
            // Offset to center relative to parent's app bounds.
            final int offsetX = getHorizontalCenterOffset(
                    parentAppBounds.width(), resolvedBounds.width());
            offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
        }
    }

    /**
@@ -7314,8 +7360,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

        final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();

        // Calculates the scale and offset to horizontal center the size compatibility bounds into
        // the region which is available to application.
        // Calculates the scale the size compatibility bounds into the region which is available
        // to application.
        final int contentW = resolvedAppBounds.width();
        final int contentH = resolvedAppBounds.height();
        final int viewportW = containerAppBounds.width();
@@ -7323,8 +7369,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // Only allow to scale down.
        mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
                ? 1f : Math.min((float) viewportW / contentW, (float) viewportH / contentH);
        final int screenTopInset = containerAppBounds.top - containerBounds.top;
        final boolean topNotAligned = screenTopInset != resolvedAppBounds.top - resolvedBounds.top;
        final int containerTopInset = containerAppBounds.top - containerBounds.top;
        final boolean topNotAligned =
                containerTopInset != resolvedAppBounds.top - resolvedBounds.top;
        if (mSizeCompatScale != 1f || topNotAligned) {
            if (mSizeCompatBounds == null) {
                mSizeCompatBounds = new Rect();
@@ -7333,18 +7380,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            mSizeCompatBounds.offsetTo(0, 0);
            mSizeCompatBounds.scale(mSizeCompatScale);
            // The insets are included in height, e.g. the area of real cutout shouldn't be scaled.
            mSizeCompatBounds.bottom += screenTopInset;
            mSizeCompatBounds.bottom += containerTopInset;
        } else {
            mSizeCompatBounds = null;
        }

        // Center horizontally in parent (app bounds) and align to top of parent (bounds)
        // - this is a UX choice.
        final int offsetX = getHorizontalCenterOffset(
                (int) viewportW, (int) (contentW * mSizeCompatScale));
        // Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor
        // if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition.
        // Above coordinates are in "@" space, now place "*" and "#" to screen space.
        final int screenPosX = (fillContainer
                ? containerBounds.left : containerAppBounds.left) + offsetX;
        final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
        final int screenPosY = containerBounds.top;
        if (screenPosX != 0 || screenPosY != 0) {
            if (mSizeCompatBounds != null) {
+38 −0
Original line number Diff line number Diff line
@@ -1024,6 +1024,10 @@ public class WindowManagerService extends IWindowManager.Stub
    // Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead.
    private float mLetterboxBackgroundWallpaperDarkScrimAlpha;

    // horizontal position of a center of the letterboxed app window. 0 corresponds to the left
    // side of the screen and 1.0 to the right side.
    private float mLetterboxHorizontalPositionMultiplier;

    final InputManagerService mInputManager;
    final DisplayManagerInternal mDisplayManagerInternal;
    final DisplayManager mDisplayManager;
@@ -1265,6 +1269,8 @@ public class WindowManagerService extends IWindowManager.Stub
                com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
        mLetterboxBackgroundWallpaperDarkScrimAlpha = context.getResources().getFloat(
                com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
        mLetterboxHorizontalPositionMultiplier = context.getResources().getFloat(
                com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);

        mInputManager = inputManager; // Must be before createDisplayContentLocked.
        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
@@ -4053,6 +4059,38 @@ public class WindowManagerService extends IWindowManager.Stub
        return mLetterboxBackgroundWallpaperBlurRadius;
    }

    /*
     * Gets horizontal position of a center of the letterboxed app window specified
     * in {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}
     * or via an ADB command. 0 corresponds to the left side of the screen and 1 to the
     * right side.
     *
     * <p>This value can be outside of [0, 1] range so clients need to check and default to the
     * central position (0.5).
     */
    float getLetterboxHorizontalPositionMultiplier() {
        return mLetterboxHorizontalPositionMultiplier;
    }

    /**
     * Overrides horizontal position of a center of the letterboxed app window. If given value < 0
     * or > 1, then it and a value of {@link
     * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} are ignored and
     * central position (0.5) is used.
     */
    void setLetterboxHorizontalPositionMultiplier(float multiplier) {
        mLetterboxHorizontalPositionMultiplier = multiplier;
    }

    /**
     * Resets horizontal position of a center of the letterboxed app window to {@link
     * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}.
     */
    void resetLetterboxHorizontalPositionMultiplier() {
        mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat(
                com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier);
    }

    @Override
    public void setIgnoreOrientationRequest(int displayId, boolean ignoreOrientationRequest) {
        if (!checkCallingPermission(
+49 −0
Original line number Diff line number Diff line
@@ -143,6 +143,10 @@ public class WindowManagerShellCommand extends ShellCommand {
                    return runSetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
                case "get-letterbox-background-wallpaper-dark-scrim-alpha":
                    return runGetLetterboxBackgroundWallpaperDarkScrimAlpha(pw);
                case "set-letterbox-horizontal-position-multiplier":
                    return runSeLetterboxHorizontalPositionMultiplier(pw);
                case "get-letterbox-horizontal-position-multiplier":
                    return runGetLetterboxHorizontalPositionMultiplier(pw);
                case "set-sandbox-display-apis":
                    return runSandboxDisplayApis(pw);
                case "reset":
@@ -846,6 +850,43 @@ public class WindowManagerShellCommand extends ShellCommand {
        return 0;
    }

    private int runSeLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException {
        final float multiplier;
        try {
            String arg = getNextArgRequired();
            if ("reset".equals(arg)) {
                synchronized (mInternal.mGlobalLock) {
                    mInternal.resetLetterboxHorizontalPositionMultiplier();
                }
                return 0;
            }
            multiplier = Float.parseFloat(arg);
        } catch (NumberFormatException  e) {
            getErrPrintWriter().println("Error: bad multiplier format " + e);
            return -1;
        } catch (IllegalArgumentException  e) {
            getErrPrintWriter().println(
                    "Error: 'reset' or multiplier should be provided as an argument " + e);
            return -1;
        }
        synchronized (mInternal.mGlobalLock) {
            mInternal.setLetterboxHorizontalPositionMultiplier(multiplier);
        }
        return 0;
    }

    private int runGetLetterboxHorizontalPositionMultiplier(PrintWriter pw) throws RemoteException {
        synchronized (mInternal.mGlobalLock) {
            final float multiplier = mInternal.getLetterboxHorizontalPositionMultiplier();
            if (multiplier < 0) {
                pw.println("Letterbox horizontal position multiplier is not set");
            } else {
                pw.println("Letterbox horizontal position multiplier is " + multiplier);
            }
        }
        return 0;
    }

    private int runReset(PrintWriter pw) throws RemoteException {
        int displayId = getDisplayId(getNextArg());

@@ -888,6 +929,9 @@ public class WindowManagerShellCommand extends ShellCommand {
        // set-letterbox-background-wallpaper-dark-scrim-alpha
        mInternal.resetLetterboxBackgroundWallpaperDarkScrimAlpha();

        // set-letterbox-horizontal-position-multiplier
        mInternal.resetLetterboxHorizontalPositionMultiplier();

        // set-sandbox-display-apis
        mInternal.setSandboxDisplayApis(displayId, /* sandboxDisplayApis= */ true);

@@ -954,6 +998,11 @@ public class WindowManagerShellCommand extends ShellCommand {
        pw.println("    letterbox background. If alpha < 0 or >= 1 both it and");
        pw.println("    R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha are ignored and ");
        pw.println("    0.0 (transparent) is used instead.");
        pw.println("  set-letterbox-horizontal-position-multiplier [reset|multiplier]");
        pw.println("  get-letterbox-horizontal-position-multiplier");
        pw.println("    horizontal position of a center of a letterboxed app. If it < 0 or > 1");
        pw.println("    then both it and R.dimen.config_letterboxHorizontalPositionMultiplier");
        pw.println("    are ignored and central position (0.5) is used.");
        pw.println("  set-sandbox-display-apis [true|1|false|0]");
        pw.println("    Sets override of Display APIs getRealSize / getRealMetrics to reflect ");
        pw.println("    DisplayArea of the activity, or the window bounds if in letterbox or");
Loading