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

Commit 3ffe3995 authored by Graciela Wissen Putri's avatar Graciela Wissen Putri
Browse files

Hide aspect ratio button when not visibly letterboxed

In some close to square displays, status bar and cutout have been
decoupled from the configuration. Only navigation bar/taskbar insets are
considered in resolving fixed orientation configurations.

With taskbar insets, the aspect ratio of the containingAppBounds in
these displays can be <= activity aspect ratio, even if the orientation
is not respected with insets e.g. portrait app in portrait display
(which is landscape with taskbar insets). Don't letterbox the activity
in this case if the resulting fixed orientation bounds still matches the
parent bounds.

Don't show the aspect ratio button if the letterboxed activity is only
minimally letterboxed (activity bounds are more or equal to stable
bounds).

Bug: 319088395
Test: atest SizeCompatTests
      atest UserAspectRatioSettingsWindowManagerTest
Change-Id: I972945ced8f346304899413487d432edc0e8ee83
parent 72dc708c
Loading
Loading
Loading
Loading
+20 −8
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.window.TaskConstants.TASK_CHILD_LAYER_COMPAT_UI;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppCompatTaskInfo;
import android.app.TaskInfo;
import android.content.Context;
import android.content.Intent;
@@ -88,7 +89,8 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
        mShellExecutor = shellExecutor;
        mUserAspectRatioButtonShownChecker = userAspectRatioButtonStateChecker;
        mUserAspectRatioButtonStateConsumer = userAspectRatioButtonShownConsumer;
        mHasUserAspectRatioSettingsButton = getHasUserAspectRatioSettingsButton(taskInfo);
        mHasUserAspectRatioSettingsButton = shouldShowUserAspectRatioSettingsButton(
                taskInfo.appCompatTaskInfo, taskInfo.baseIntent);
        mCompatUIHintsState = compatUIHintsState;
        mOnButtonClicked = onButtonClicked;
        mDisappearTimeSupplier = disappearTimeSupplier;
@@ -134,7 +136,8 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
    public boolean updateCompatInfo(@NonNull TaskInfo taskInfo,
            @NonNull ShellTaskOrganizer.TaskListener taskListener, boolean canShow) {
        final boolean prevHasUserAspectRatioSettingsButton = mHasUserAspectRatioSettingsButton;
        mHasUserAspectRatioSettingsButton = getHasUserAspectRatioSettingsButton(taskInfo);
        mHasUserAspectRatioSettingsButton = shouldShowUserAspectRatioSettingsButton(
                taskInfo.appCompatTaskInfo, taskInfo.baseIntent);

        if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) {
            return false;
@@ -227,12 +230,21 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
        return SystemClock.uptimeMillis() + hideDelay;
    }

    private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
        final Intent intent = taskInfo.baseIntent;
        return taskInfo.appCompatTaskInfo.topActivityEligibleForUserAspectRatioButton
                && (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed
                    || taskInfo.appCompatTaskInfo.isUserFullscreenOverrideEnabled)
                && !taskInfo.appCompatTaskInfo.isSystemFullscreenOverrideEnabled
    private boolean shouldShowUserAspectRatioSettingsButton(@NonNull AppCompatTaskInfo taskInfo,
            @NonNull Intent intent) {
        final Rect stableBounds = getTaskStableBounds();
        final int letterboxHeight = taskInfo.topActivityLetterboxHeight;
        final int letterboxWidth = taskInfo.topActivityLetterboxWidth;
        // App is not visibly letterboxed if it covers status bar/bottom insets or matches the
        // stable bounds, so don't show the button
        if (stableBounds.height() <= letterboxHeight && stableBounds.width() <= letterboxWidth) {
            return false;
        }

        return taskInfo.topActivityEligibleForUserAspectRatioButton
                && (taskInfo.topActivityBoundsLetterboxed
                    || taskInfo.isUserFullscreenOverrideEnabled)
                && !taskInfo.isSystemFullscreenOverrideEnabled
                && Intent.ACTION_MAIN.equals(intent.getAction())
                && intent.hasCategory(Intent.CATEGORY_LAUNCHER)
                && (!mUserAspectRatioButtonShownChecker.get() || isShowingButton());
+40 −1
Original line number Diff line number Diff line
@@ -113,8 +113,22 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
        mExecutor = new TestShellExecutor();
        mTaskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
                false, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);
        final DisplayInfo displayInfo = new DisplayInfo();
        final int displayWidth = 1000;
        final int displayHeight = 1200;
        displayInfo.logicalWidth = displayWidth;
        displayInfo.logicalHeight = displayHeight;
        final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
                mContext.getResources(), /* hasNavigationBar= */ true, /* hasStatusBar= */ false);
        InsetsState insetsState = new InsetsState();
        insetsState.setDisplayFrame(new Rect(0, 0, displayWidth, displayHeight));
        InsetsSource insetsSource = new InsetsSource(
                InsetsSource.createId(null, 0, navigationBars()), navigationBars());
        insetsSource.setFrame(0, displayHeight - 200, displayWidth, displayHeight);
        insetsState.addSource(insetsSource);
        displayLayout.setInsets(mContext.getResources(), insetsState);
        mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo,
                mSyncTransactionQueue, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
                mSyncTransactionQueue, mTaskListener, displayLayout, new CompatUIHintsState(),
                mOnUserAspectRatioSettingsButtonClicked, mExecutor, flags -> 0,
                mUserAspectRatioButtonShownChecker, s -> {});
        spyOn(mWindowManager);
@@ -252,6 +266,31 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
        verify(mWindowManager).inflateLayout();
    }

    @Test
    public void testEligibleButtonHiddenIfLetterboxBoundsEqualToStableBounds() {
        TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
                true, /* topActivityBoundsLetterboxed */ true, ACTION_MAIN, CATEGORY_LAUNCHER);

        final Rect stableBounds = mWindowManager.getTaskStableBounds();
        final int stableHeight = stableBounds.height();

        // Letterboxed activity bounds equal to stable bounds, layout shouldn't be inflated
        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = stableHeight;
        taskInfo.appCompatTaskInfo.topActivityLetterboxWidth = stableBounds.width();

        mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);

        verify(mWindowManager, never()).inflateLayout();

        // Letterboxed activity bounds smaller than stable bounds, layout should be inflated
        taskInfo.appCompatTaskInfo.topActivityLetterboxHeight = stableHeight - 100;

        clearInvocations(mWindowManager);
        mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);

        verify(mWindowManager).inflateLayout();
    }

    @Test
    public void testUpdateDisplayLayout() {
        final DisplayInfo displayInfo = new DisplayInfo();
+9 −0
Original line number Diff line number Diff line
@@ -8873,6 +8873,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            }
        }

        // Fixed orientation bounds are the same as its parent container, so clear the fixed
        // orientation bounds. This can happen in close to square displays where the orientation
        // is not respected with insets, but the display still matches or is less than the
        // activity aspect ratio.
        if (resolvedBounds.equals(parentBounds)) {
            resolvedBounds.set(prevResolvedBounds);
            return;
        }

        // Calculate app bounds using fixed orientation bounds because they will be needed later
        // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
        getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
+47 −22
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -100,6 +101,7 @@ import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Binder;
import android.os.RemoteException;
@@ -153,6 +155,8 @@ public class SizeCompatTests extends WindowTestsBase {
    private static final String CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES =
            "never_constrain_display_apis_all_packages";

    private static final float DELTA_ASPECT_RATIO_TOLERANCE = 0.005f;

    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();

@@ -2143,7 +2147,7 @@ public class SizeCompatTests extends WindowTestsBase {
        final Rect afterBounds = mActivity.getBounds();
        final float actualAspectRatio = 1f * afterBounds.height() / afterBounds.width();
        assertEquals(LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW,
                actualAspectRatio, 0.001f);
                actualAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
        assertTrue(mActivity.areBoundsLetterboxed());
    }

@@ -2179,7 +2183,7 @@ public class SizeCompatTests extends WindowTestsBase {
        // default letterbox aspect ratio for multi-window.
        final Rect afterBounds = mActivity.getBounds();
        final float actualAspectRatio = 1f * afterBounds.height() / afterBounds.width();
        assertEquals(minAspectRatio, actualAspectRatio, 0.001f);
        assertEquals(minAspectRatio, actualAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
        assertTrue(mActivity.areBoundsLetterboxed());
    }

@@ -2487,7 +2491,7 @@ public class SizeCompatTests extends WindowTestsBase {
        final float afterAspectRatio =
                (float) Math.max(width, height) / (float) Math.min(width, height);

        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -2512,7 +2516,7 @@ public class SizeCompatTests extends WindowTestsBase {
        float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight);
        final Rect afterBounds = activity.getBounds();
        final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -2537,7 +2541,7 @@ public class SizeCompatTests extends WindowTestsBase {
        float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth);
        final Rect afterBounds = activity.getBounds();
        final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -2563,7 +2567,7 @@ public class SizeCompatTests extends WindowTestsBase {
        float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight);
        final Rect afterBounds = activity.getBounds();
        final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -2589,7 +2593,7 @@ public class SizeCompatTests extends WindowTestsBase {
        float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth);
        final Rect afterBounds = activity.getBounds();
        final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -2629,7 +2633,7 @@ public class SizeCompatTests extends WindowTestsBase {
        float expectedAspectRatio = 1f * screenHeight / getExpectedSplitSize(screenWidth);
        final Rect afterBounds = activity.getBounds();
        final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width();
        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
        assertFalse(activity.areBoundsLetterboxed());
    }

@@ -2670,7 +2674,7 @@ public class SizeCompatTests extends WindowTestsBase {
        float expectedAspectRatio = 1f * screenWidth / getExpectedSplitSize(screenHeight);
        final Rect afterBounds = activity.getBounds();
        final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height();
        assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f);
        assertEquals(expectedAspectRatio, afterAspectRatio, DELTA_ASPECT_RATIO_TOLERANCE);
        assertFalse(activity.areBoundsLetterboxed());
    }

@@ -2847,9 +2851,8 @@ public class SizeCompatTests extends WindowTestsBase {
        assertFitted();
        // Check that the display aspect ratio is used by the app.
        final float targetMinAspectRatio = 1f * displayHeight / displayWidth;
        final float delta = 0.01f;
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(mActivity.getBounds()), delta);
                .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -2883,9 +2886,8 @@ public class SizeCompatTests extends WindowTestsBase {
        assertFitted();
        // Check that the display aspect ratio is used by the app.
        final float targetMinAspectRatio = 1f * displayWidth / displayHeight;
        final float delta = 0.01f;
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(mActivity.getBounds()), delta);
                .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -2910,9 +2912,8 @@ public class SizeCompatTests extends WindowTestsBase {
        assertFitted();
        // Check that the display aspect ratio is used by the app.
        final float targetMinAspectRatio = 1f * displayHeight / displayWidth;
        final float delta = 0.01f;
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(mActivity.getBounds()), delta);
                .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -2937,9 +2938,8 @@ public class SizeCompatTests extends WindowTestsBase {
        assertFitted();
        // Check that the display aspect ratio is used by the app.
        final float targetMinAspectRatio = 1f * displayWidth / displayHeight;
        final float delta = 0.01f;
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(mActivity.getBounds()), delta);
                .computeAspectRatio(mActivity.getBounds()), DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -4052,6 +4052,32 @@ public class SizeCompatTests extends WindowTestsBase {
        assertEquals(sizeCompatScaled, mActivity.getBounds());
    }

    @Test
    public void testPortraitCloseToSquareDisplayWithTaskbar_notLetterboxed() {
        // Set up portrait close to square display
        setUpDisplaySizeWithApp(2200, 2280);
        final DisplayContent display = mActivity.mDisplayContent;
        // Simulate taskbar, final app bounds are (0, 0, 2200, 2130) - landscape
        final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent,
                "navbar");
        final Binder owner = new Binder();
        navbar.mAttrs.providedInsets = new InsetsFrameProvider[] {
                new InsetsFrameProvider(owner, 0, WindowInsets.Type.navigationBars())
                        .setInsetsSize(Insets.of(0, 0, 0, 150))
        };
        display.getDisplayPolicy().addWindowLw(navbar, navbar.mAttrs);
        assertTrue(navbar.providesDisplayDecorInsets()
                && display.getDisplayPolicy().updateDecorInsetsInfo());
        display.sendNewConfiguration();

        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);

        // Activity is fullscreen even though orientation is not respected with insets, because
        // the display still matches or is less than the activity aspect ratio
        assertEquals(display.getBounds(), mActivity.getBounds());
        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
    }

    @Test
    public void testApplyAspectRatio_activityAlignWithParentAppVertical() {
        // The display's app bounds will be (0, 100, 1000, 2350)
@@ -4275,7 +4301,7 @@ public class SizeCompatTests extends WindowTestsBase {
                .getFixedOrientationLetterboxAspectRatio(parentConfig);
        float expected = mActivity.mLetterboxUiController.getSplitScreenAspectRatio();

        assertEquals(expected, actual, 0.01);
        assertEquals(expected, actual, DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test
@@ -4671,13 +4697,12 @@ public class SizeCompatTests extends WindowTestsBase {
                .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);
                .computeAspectRatio(fixedOrientationAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(minAspectRatioAppBounds), delta);
                .computeAspectRatio(minAspectRatioAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
        assertEquals(targetMinAspectRatio, ActivityRecord
                .computeAspectRatio(sizeCompatAppBounds), delta);
                .computeAspectRatio(sizeCompatAppBounds), DELTA_ASPECT_RATIO_TOLERANCE);
    }

    @Test