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

Commit 1f790e33 authored by Shivam Agrawal's avatar Shivam Agrawal
Browse files

Unify Aspect Ratio Logic in ActivityRecord

Use the existing aspect ratio logic when resolving
fixed orientation bounds.

Test: atest AppConfigurationTests AspectRatioTests SizeCompatTests
            ActivityRecordTests TaskTests CompatChangeTests
Bug: b/191070948 b/182268157
Change-Id: I174661f69dc90d57c0c966baa2360adb6a5ab8a4
parent 9b3a6c28
Loading
Loading
Loading
Loading
+105 −85
Original line number Original line Diff line number Diff line
@@ -698,8 +698,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    private boolean mInSizeCompatModeForBounds = false;
    private boolean mInSizeCompatModeForBounds = false;


    // Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
    // 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;
    private boolean mIsAspectRatioApplied = false;


    // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
    // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
@@ -7352,11 +7350,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
     * requested orientation. If not, it may be necessary to letterbox the window.
     * requested orientation. If not, it may be necessary to letterbox the window.
     * @param parentBounds are the new parent bounds passed down to the activity and should be used
     * @param parentBounds are the new parent bounds passed down to the activity and should be used
     *                     to compute the stable bounds.
     *                     to compute the stable bounds.
     * @param outBounds will store the stable bounds, which are the bounds with insets applied.
     * @param outStableBounds will store the stable bounds, which are the bounds with insets
     *                  These should be used to compute letterboxed bounds if orientation is not
     *                        applied, if orientation is not respected when insets are applied.
     *                  respected when insets are applied.
     *                        Otherwise outStableBounds will be empty. Stable bounds should be used
     */
     *                        to compute letterboxed bounds if orientation is not respected when
    private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outBounds) {
     *                        insets are applied.
     */
    private boolean orientationRespectedWithInsets(Rect parentBounds, Rect outStableBounds) {
        outStableBounds.setEmpty();
        if (mDisplayContent == null) {
        if (mDisplayContent == null) {
            return true;
            return true;
        }
        }
@@ -7371,17 +7372,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // Compute orientation from stable parent bounds (= parent bounds with insets applied)
        // Compute orientation from stable parent bounds (= parent bounds with insets applied)
        final Task task = getTask();
        final Task task = getTask();
        task.calculateInsetFrames(mTmpOutNonDecorBounds /* outNonDecorBounds */,
        task.calculateInsetFrames(mTmpOutNonDecorBounds /* outNonDecorBounds */,
                outBounds /* outStableBounds */, parentBounds /* bounds */,
                outStableBounds /* outStableBounds */, parentBounds /* bounds */,
                mDisplayContent.getDisplayInfo());
                mDisplayContent.getDisplayInfo());
        final int orientationWithInsets = outBounds.height() >= outBounds.width()
        final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
                ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
                ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
        // If orientation does not match the orientation with insets applied, then a
        // If orientation does not match the orientation with insets applied, then a
        // display rotation will not be enough to respect orientation. However, even if they do
        // display rotation will not be enough to respect orientation. However, even if they do
        // not match but the orientation with insets applied matches the requested orientation, then
        // not match but the orientation with insets applied matches the requested orientation, then
        // there is no need to modify the bounds because when insets are applied, the activity will
        // there is no need to modify the bounds because when insets are applied, the activity will
        // have the desired orientation.
        // have the desired orientation.
        return orientation == orientationWithInsets
        final boolean orientationRespectedWithInsets = orientation == orientationWithInsets
                || orientationWithInsets == requestedOrientation;
                || orientationWithInsets == requestedOrientation;
        if (orientationRespectedWithInsets) {
            outStableBounds.setEmpty();
        }
        return orientationRespectedWithInsets;
    }
    }


    /**
    /**
@@ -7399,9 +7404,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            int windowingMode) {
            int windowingMode) {
        mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
        mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
        final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
        final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
        final Rect containerBounds = new Rect(parentBounds);
        final Rect stableBounds = new Rect();
        // If orientation is respected when insets are applied, then stableBounds will be empty.
        boolean orientationRespectedWithInsets =
        boolean orientationRespectedWithInsets =
                orientationRespectedWithInsets(parentBounds, containerBounds);
                orientationRespectedWithInsets(parentBounds, stableBounds);
        if (handlesOrientationChangeFromDescendant() && orientationRespectedWithInsets) {
        if (handlesOrientationChangeFromDescendant() && orientationRespectedWithInsets) {
            // No need to letterbox because of fixed orientation. Display will handle
            // No need to letterbox because of fixed orientation. Display will handle
            // fixed-orientation requests and a display rotation is enough to respect requested
            // fixed-orientation requests and a display rotation is enough to respect requested
@@ -7438,71 +7444,68 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            return;
            return;
        }
        }


        // TODO(b/182268157) merge aspect ratio logic here and in
        // TODO(b/182268157): Explore using only one type of parentBoundsWithInsets, either app
        // {@link ActivityRecord#applyAspectRatio}
        // bounds or stable bounds to unify aspect ratio logic.
        // if no aspect ratio constraints are provided, parent aspect ratio is used
        final Rect parentBoundsWithInsets = orientationRespectedWithInsets
        float aspectRatio = computeAspectRatio(parentBounds);
                ? newParentConfig.windowConfiguration.getAppBounds() : stableBounds;

        final Rect containingBounds = new Rect();
        // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
        final Rect containingBoundsWithInsets = new Rect();
        // set-fixed-orientation-letterbox-aspect-ratio.
        // Need to shrink the containing bounds into a square because the parent orientation
        final float letterboxAspectRatioOverride =
        // does not match the activity requested orientation.
                mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
        aspectRatio = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
            // Landscape is defined as width > height. Make the container respect landscape
                ? letterboxAspectRatioOverride : aspectRatio;
            // orientation by shrinking height to one less than width. Landscape activity will be

            // vertically centered within parent bounds with insets, so position vertical bounds
        // Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
            // within parent bounds with insets to prevent insets from unnecessarily trimming
        // order to use the extra available space.
            // vertical bounds.
        final float maxAspectRatio = info.getMaxAspectRatio();
            final int bottom = Math.min(parentBoundsWithInsets.top + parentBounds.width() - 1,
        final float minAspectRatio = info.getMinAspectRatio();
                    parentBoundsWithInsets.bottom);
        if (aspectRatio > maxAspectRatio && maxAspectRatio != 0) {
            containingBounds.set(parentBounds.left, parentBoundsWithInsets.top, parentBounds.right,
            aspectRatio = maxAspectRatio;
                    bottom);
        } else if (aspectRatio < minAspectRatio) {
            containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
            aspectRatio = minAspectRatio;
                    parentBoundsWithInsets.right, bottom);
        } else {
            // Portrait is defined as width <= height. Make the container respect portrait
            // orientation by shrinking width to match height. Portrait activity will be
            // horizontally centered within parent bounds with insets, so position horizontal bounds
            // within parent bounds with insets to prevent insets from unnecessarily trimming
            // horizontal bounds.
            final int right = Math.min(parentBoundsWithInsets.left + parentBounds.height(),
                    parentBoundsWithInsets.right);
            containingBounds.set(parentBoundsWithInsets.left, parentBounds.top, right,
                    parentBounds.bottom);
            containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top,
                    right, parentBoundsWithInsets.bottom);
        }
        }


        // Store the current bounds to be able to revert to size compat mode values below if needed.
        // Store the current bounds to be able to revert to size compat mode values below if needed.
        final Rect prevResolvedBounds = new Rect(resolvedBounds);
        final Rect prevResolvedBounds = new Rect(resolvedBounds);
        resolvedBounds.set(containingBounds);


        // Compute other dimension based on aspect ratio. Use bounds intersected with insets, stored
        // Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
        // in containerBounds after calling {@link ActivityRecord#orientationRespectedWithInsets()},
        // set-fixed-orientation-letterbox-aspect-ratio.
        // to ensure that aspect ratio is respected after insets are applied.
        final float letterboxAspectRatioOverride =
        int activityWidth;
                mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
        int activityHeight;
        final float desiredAspectRatio =
                letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
                        ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
        // Apply aspect ratio to resolved bounds
        mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
                containingBounds, desiredAspectRatio, true);

        // Vertically center if orientation is landscape. Center within parent bounds with insets
        // to ensure that insets do not trim height. Bounds will later be horizontally centered in
        // {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
            activityWidth = parentBounds.width();
            final int offsetY = parentBoundsWithInsets.centerY() - resolvedBounds.centerY();
            // Compute height from stable bounds width to ensure orientation respected after insets.
            resolvedBounds.offset(0, offsetY);
            activityHeight = (int) Math.rint(containerBounds.width() / aspectRatio);
            // Landscape is defined as width > height. To ensure activity is landscape when aspect
            // ratio is close to 1, reduce the height by one pixel.
            if (activityWidth == activityHeight) {
                activityHeight -= 1;
            }
            // Center vertically within stable bounds in landscape to ensure insets do not trim
            // height.
            final int top = containerBounds.centerY() - activityHeight / 2;
            resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + activityHeight);
        } else {
            activityHeight = parentBounds.height();
            // Compute width from stable bounds height to ensure orientation respected after insets.
            activityWidth = (int) Math.rint(containerBounds.height() / aspectRatio);
            // Center horizontally in portrait. For now, align to left and allow
            // {@link ActivityRecord#updateResolvedBoundsHorizontalPosition()} to center
            // horizontally. Exclude left insets from parent to ensure cutout does not trim width.
            final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
            resolvedBounds.set(parentAppBounds.left, parentBounds.top,
                    parentAppBounds.left + activityWidth, parentBounds.bottom);
        }
        }


        if (mCompatDisplayInsets != null) {
        if (mCompatDisplayInsets != null) {
            mCompatDisplayInsets.getBoundsByRotation(
            mCompatDisplayInsets.getBoundsByRotation(
                    mTmpBounds, newParentConfig.windowConfiguration.getRotation());
                    mTmpBounds, newParentConfig.windowConfiguration.getRotation());
            // Insets may differ between different rotations, for example in the case of a display
            if (resolvedBounds.width() != mTmpBounds.width()
            // cutout. To ensure consistent bounds across rotations, compare the activity dimensions
                    || resolvedBounds.height() != mTmpBounds.height()) {
            // minus insets from the rotation the compat bounds were computed in.
            Task.intersectWithInsetsIfFits(mTmpBounds, parentBounds,
                    mCompatDisplayInsets.mStableInsets[mCompatDisplayInsets.mOriginalRotation]);
            if (activityWidth != mTmpBounds.width()
                    || activityHeight != mTmpBounds.height()) {
                // The app shouldn't be resized, we only do fixed orientation letterboxing if the
                // The app shouldn't be resized, we only do fixed orientation letterboxing if the
                // compat bounds are also from the same fixed orientation letterbox. Otherwise,
                // compat bounds are also from the same fixed orientation letterbox. Otherwise,
                // clear the fixed orientation bounds to show app in size compat mode.
                // clear the fixed orientation bounds to show app in size compat mode.
@@ -7538,8 +7541,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
        // then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
        if (!mTmpBounds.isEmpty()) {
        if (!mTmpBounds.isEmpty()) {
            resolvedBounds.set(mTmpBounds);
            resolvedBounds.set(mTmpBounds);
            // Exclude the horizontal decor area.
            resolvedBounds.left = parentAppBounds.left;
        }
        }
        if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
        if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
            // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
            // Compute the configuration based on the resolved bounds. If aspect ratio doesn't
@@ -7600,13 +7601,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            mIsAspectRatioApplied =
            mIsAspectRatioApplied =
                    applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
                    applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
        }
        }
        // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in
        // the container app bounds. Otherwise the entire container bounds are available.
        final boolean fillContainer = resolvedBounds.equals(containingBounds);
        if (!fillContainer) {
            // The horizontal position should not cover insets.
            resolvedBounds.left = containingAppBounds.left;
        }


        // Use resolvedBounds to compute other override configurations such as appBounds. The bounds
        // Use resolvedBounds to compute other override configurations such as appBounds. The bounds
        // are calculated in compat container space. The actual position on screen will be applied
        // are calculated in compat container space. The actual position on screen will be applied
@@ -7673,6 +7667,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        // Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor
        // Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor
        // if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition.
        // if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition.
        // Above coordinates are in "@" space, now place "*" and "#" to screen space.
        // Above coordinates are in "@" space, now place "*" and "#" to screen space.
        final boolean fillContainer = resolvedBounds.equals(containingBounds);
        final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
        final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
        final int screenPosY = containerBounds.top;
        final int screenPosY = containerBounds.top;
        if (screenPosX != 0 || screenPosY != 0) {
        if (screenPosX != 0 || screenPosY != 0) {
@@ -7913,6 +7908,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        return true;
        return true;
    }
    }


    private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
            Rect containingBounds) {
        return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
                0 /* desiredAspectRatio */, false /* fixedOrientationLetterboxed */);
    }

    /**
    /**
     * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
     * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
     * made to outBounds.
     * made to outBounds.
@@ -7921,17 +7922,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
     */
     */
    // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
    // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
    private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
    private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
            Rect containingBounds) {
            Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) {
        final float maxAspectRatio = info.getMaxAspectRatio();
        final float maxAspectRatio = info.getMaxAspectRatio();
        final Task rootTask = getRootTask();
        final Task rootTask = getRootTask();
        final float minAspectRatio = info.getMinAspectRatio();
        final float minAspectRatio = info.getMinAspectRatio();


        if (task == null || rootTask == null
        if (task == null || rootTask == null
                || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets())
                || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets()
                || (maxAspectRatio == 0 && minAspectRatio == 0)
                && !fixedOrientationLetterboxed)
                || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1)
                || isInVrUiMode(getConfiguration())) {
                || isInVrUiMode(getConfiguration())) {
            // We don't enforce aspect ratio if the activity task is in multiwindow unless it
            // We don't enforce aspect ratio if the activity task is in multiwindow unless it is in
            // is in size-compat mode. We also don't set it if we are in VR mode.
            // size-compat mode or is letterboxed from fixed orientation. We also don't set it if we
            // are in VR mode.
            return false;
            return false;
        }
        }


@@ -7939,20 +7942,30 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        final int containingAppHeight = containingAppBounds.height();
        final int containingAppHeight = containingAppBounds.height();
        final float containingRatio = computeAspectRatio(containingAppBounds);
        final float containingRatio = computeAspectRatio(containingAppBounds);


        if (desiredAspectRatio < 1) {
            desiredAspectRatio = containingRatio;
        }

        if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
            desiredAspectRatio = maxAspectRatio;
        } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
            desiredAspectRatio = minAspectRatio;
        }

        int activityWidth = containingAppWidth;
        int activityWidth = containingAppWidth;
        int activityHeight = containingAppHeight;
        int activityHeight = containingAppHeight;


        if (containingRatio > maxAspectRatio && maxAspectRatio != 0) {
        if (containingRatio > desiredAspectRatio) {
            if (containingAppWidth < containingAppHeight) {
            if (containingAppWidth < containingAppHeight) {
                // Width is the shorter side, so we use that to figure-out what the max. height
                // Width is the shorter side, so we use that to figure-out what the max. height
                // should be given the aspect ratio.
                // should be given the aspect ratio.
                activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f);
                activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f);
            } else {
            } else {
                // Height is the shorter side, so we use that to figure-out what the max. width
                // Height is the shorter side, so we use that to figure-out what the max. width
                // should be given the aspect ratio.
                // should be given the aspect ratio.
                activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f);
                activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
            }
            }
        } else if (containingRatio < minAspectRatio) {
        } else if (containingRatio < desiredAspectRatio) {
            boolean adjustWidth;
            boolean adjustWidth;
            switch (getRequestedConfigurationOrientation()) {
            switch (getRequestedConfigurationOrientation()) {
                case ORIENTATION_LANDSCAPE:
                case ORIENTATION_LANDSCAPE:
@@ -7980,9 +7993,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                    break;
                    break;
            }
            }
            if (adjustWidth) {
            if (adjustWidth) {
                activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f);
                activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f);
            } else {
            } else {
                activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f);
                activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f);
            }
            }
        }
        }


@@ -8006,6 +8019,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
        }
        outBounds.set(containingBounds.left, containingBounds.top, right, bottom);
        outBounds.set(containingBounds.left, containingBounds.top, right, bottom);


        // If the bounds are restricted by fixed aspect ratio, then out bounds should be put in the
        // container app bounds. Otherwise the entire container bounds are available.
        if (!outBounds.equals(containingBounds)) {
            // The horizontal position should not cover insets (e.g. display cutout).
            outBounds.left = containingAppBounds.left;
        }

        return true;
        return true;
    }
    }


+55 −0
Original line number Original line Diff line number Diff line
@@ -1963,6 +1963,61 @@ public class SizeCompatTests extends WindowTestsBase {
        assertTrue(mActivity.areBoundsLetterboxed());
        assertTrue(mActivity.areBoundsLetterboxed());
    }
    }


    /**
     * Tests that all three paths in which aspect ratio logic can be applied yield the same
     * result, which is that aspect ratio is respected on app bounds. The three paths are
     * fixed orientation, no fixed orientation but fixed aspect ratio, and size compat mode.
     */
    @Test
    public void testAllAspectRatioLogicConsistent() {
        // Create display that has all stable insets and does not rotate. Make sure that status bar
        // height is greater than notch height so that stable bounds do not equal app bounds.
        final int notchHeight = 75;
        final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1080, 600)
                .setSystemDecorations(true).setNotch(notchHeight)
                .setStatusBarHeight(notchHeight + 20).setCanRotate(false).build();

        // Create task on test display.
        final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();

        // Target min aspect ratio must be larger than parent aspect ratio to be applied.
        final float targetMinAspectRatio = 3.0f;

        // Create fixed portait activity with min aspect ratio greater than parent aspect ratio.
        final ActivityRecord fixedOrientationActivity = new ActivityBuilder(mAtm)
                .setTask(task).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .setMinAspectRatio(targetMinAspectRatio).build();
        final Rect fixedOrientationAppBounds = new Rect(fixedOrientationActivity.getConfiguration()
                .windowConfiguration.getAppBounds());

        // Create activity with no fixed orientation and min aspect ratio greater than parent aspect
        // ratio.
        final ActivityRecord minAspectRatioActivity = new ActivityBuilder(mAtm).setTask(task)
                .setMinAspectRatio(targetMinAspectRatio).build();
        final Rect minAspectRatioAppBounds = new Rect(minAspectRatioActivity.getConfiguration()
                .windowConfiguration.getAppBounds());

        // Create unresizeable fixed portait activity with min aspect ratio greater than parent
        // aspect ratio.
        final ActivityRecord sizeCompatActivity = new ActivityBuilder(mAtm)
                .setTask(task).setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .setMinAspectRatio(targetMinAspectRatio).build();
        // Resize display running unresizeable activity to make it enter size compat mode.
        resizeDisplay(display, 1800, 1000);
        final Rect sizeCompatAppBounds = new Rect(sizeCompatActivity.getConfiguration()
                .windowConfiguration.getAppBounds());

        // Check that aspect ratio of app bounds is equal to the min aspect ratio.
        final float delta = 0.01f;
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(fixedOrientationAppBounds), delta);
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(minAspectRatioAppBounds), delta);
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(sizeCompatAppBounds), delta);
    }

    private void assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
    private void assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
            float letterboxHorizontalPositionMultiplier) {
            float letterboxHorizontalPositionMultiplier) {
        // Set up a display in landscape and ignoring orientation request.
        // Set up a display in landscape and ignoring orientation request.
+15 −0
Original line number Original line Diff line number Diff line
@@ -19,7 +19,9 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;


import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -77,6 +79,7 @@ class TestDisplayContent extends DisplayContent {
        private int mPosition = POSITION_BOTTOM;
        private int mPosition = POSITION_BOTTOM;
        protected final ActivityTaskManagerService mService;
        protected final ActivityTaskManagerService mService;
        private boolean mSystemDecorations = false;
        private boolean mSystemDecorations = false;
        private int mStatusBarHeight = 0;


        Builder(ActivityTaskManagerService service, int width, int height) {
        Builder(ActivityTaskManagerService service, int width, int height) {
            mService = service;
            mService = service;
@@ -125,6 +128,10 @@ class TestDisplayContent extends DisplayContent {
                    Insets.of(0, height, 0, 0), null, new Rect(20, 0, 80, height), null, null);
                    Insets.of(0, height, 0, 0), null, new Rect(20, 0, 80, height), null, null);
            return this;
            return this;
        }
        }
        Builder setStatusBarHeight(int height) {
            mStatusBarHeight = height;
            return this;
        }
        Builder setCanRotate(boolean canRotate) {
        Builder setCanRotate(boolean canRotate) {
            mCanRotate = canRotate;
            mCanRotate = canRotate;
            return this;
            return this;
@@ -158,6 +165,14 @@ class TestDisplayContent extends DisplayContent {
                doReturn(false).when(displayPolicy).hasStatusBar();
                doReturn(false).when(displayPolicy).hasStatusBar();
                doReturn(false).when(newDisplay).supportsSystemDecorations();
                doReturn(false).when(newDisplay).supportsSystemDecorations();
            }
            }
            if (mStatusBarHeight > 0) {
                doReturn(true).when(displayPolicy).hasStatusBar();
                doAnswer(invocation -> {
                    Rect inOutInsets = (Rect) invocation.getArgument(0);
                    inOutInsets.top = mStatusBarHeight;
                    return null;
                }).when(displayPolicy).convertNonDecorInsetsToStableInsets(any(), anyInt());
            }
            Configuration c = new Configuration();
            Configuration c = new Configuration();
            newDisplay.computeScreenConfiguration(c);
            newDisplay.computeScreenConfiguration(c);
            c.windowConfiguration.setWindowingMode(mWindowingMode);
            c.windowConfiguration.setWindowingMode(mWindowingMode);