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

Commit d5f2cd95 authored by Chris Li's avatar Chris Li
Browse files

Clear the previous CompatDisplayInsets when new activity is launched

When a new activity is launched from Task letterbox activity, it will
first use the existing Task bounds, so we need to make sure the size
compat for that bounds is cleared when it requests orientation.

Bug: 170725334
Bug: 155431879
Test: atest WmTests:SizeCompatTests
Test: manual: adb shell wm set-ignore-orientation-request true
Change-Id: I86a206be030c3c250fb40590e7515e75620eaaf7
parent da97d53c
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -6543,15 +6543,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        mCompatDisplayInsets = new CompatDisplayInsets(mDisplayContent, this);
    }

    @VisibleForTesting
    void clearSizeCompatMode() {
    void clearSizeCompatMode(boolean recomputeTask) {
        mSizeCompatScale = 1f;
        mSizeCompatBounds = null;
        mCompatDisplayInsets = null;

        if (recomputeTask) {
            // Recompute from Task because letterbox can also happen on Task level.
            task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration());
        }
    }

    @VisibleForTesting
    void clearSizeCompatMode() {
        clearSizeCompatMode(true /* recomputeTask */);
    }

    @Override
    public boolean matchParentBounds() {
+1 −1
Original line number Diff line number Diff line
@@ -1303,7 +1303,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp

    @Override
    boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
            ConfigurationContainer requestingContainer) {
            WindowContainer requestingContainer) {
        final Configuration config = updateOrientation(
                getRequestedOverrideConfiguration(), freezeDisplayToken, false /* forceUpdate */);
        // If display rotation class tells us that it doesn't consider app requested orientation,
+13 −1
Original line number Diff line number Diff line
@@ -3274,7 +3274,7 @@ class Task extends WindowContainer<WindowContainer> {

    @Override
    public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
            ConfigurationContainer requestingContainer) {
            WindowContainer requestingContainer) {
        if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
            return true;
        }
@@ -3282,6 +3282,18 @@ class Task extends WindowContainer<WindowContainer> {
        // No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
        // it if possible.
        if (getParent() != null) {
            final ActivityRecord activity = requestingContainer.asActivityRecord();
            if (activity != null) {
                // Clear the size compat cache to recompute the bounds for requested orientation;
                // otherwise when Task#computeFullscreenBounds(), it will not try to do Task level
                // letterboxing because app may prefer to keep its original size (size compat).
                //
                // Normally, ActivityRecord#clearSizeCompatMode() recomputes from its parent Task,
                // which is the leaf Task. However, because this orientation request is new to all
                // Tasks, pass false to clearSizeCompatMode, and trigger onConfigurationChanged from
                // here (root Task) to make sure all Tasks are up-to-date.
                activity.clearSizeCompatMode(false /* recomputeTask */);
            }
            onConfigurationChanged(getParent().getConfiguration());
            return true;
        }
+3 −3
Original line number Diff line number Diff line
@@ -1144,7 +1144,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     * @return {@code true} if handled; {@code false} otherwise.
     */
    boolean onDescendantOrientationChanged(@Nullable IBinder freezeDisplayToken,
            @Nullable ConfigurationContainer requestingContainer) {
            @Nullable WindowContainer requestingContainer) {
        final WindowContainer parent = getParent();
        if (parent == null) {
            return false;
@@ -1156,7 +1156,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
    /**
     * Check if this container or its parent will handle orientation changes from descendants. It's
     * different from the return value of {@link #onDescendantOrientationChanged(IBinder,
     * ConfigurationContainer)} in the sense that the return value of this method tells if this
     * WindowContainer)} in the sense that the return value of this method tells if this
     * container or its parent will handle the request eventually, while the return value of the
     * other method is if it handled the request synchronously.
     *
@@ -1230,7 +1230,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     *                            to ensure it gets correct configuration.
     */
    void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken,
            @Nullable ConfigurationContainer requestingContainer) {
            @Nullable WindowContainer requestingContainer) {
        if (mOrientation == orientation) {
            return;
        }
+91 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.Task.ActivityState.STOPPED;

@@ -35,8 +36,11 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.doCallRealMethod;

import android.app.ActivityManager;
@@ -628,7 +632,6 @@ public class SizeCompatTests extends WindowTestsBase {
        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);

        final Rect displayBounds = mActivity.mDisplayContent.getBounds();
        final Rect newTaskBounds = mTask.getBounds();
        final Rect newActivityBounds = mActivity.getBounds();
        assertTrue(displayBounds.width() < displayBounds.height());

@@ -673,6 +676,93 @@ public class SizeCompatTests extends WindowTestsBase {
                activityBounds.width());
    }

    @Test
    public void testDisplayIgnoreOrientationRequest_newLaunchedOrientationAppInTaskLetterbox() {
        // Set up a display in landscape and ignoring orientation request.
        setUpDisplaySizeWithApp(2800, 1400);
        final DisplayContent display = mActivity.mDisplayContent;
        display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);

        // Portrait fixed app without max aspect.
        prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);

        assertTrue(mTask.isTaskLetterboxed());
        assertFalse(mActivity.inSizeCompatMode());

        // Launch another portrait fixed app.
        spyOn(mTask);
        setBooted(display.mWmService.mAtmService);
        final ActivityRecord newActivity = new ActivityBuilder(display.mWmService.mAtmService)
                .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .setTask(mTask)
                .build();

        // Update with new activity requested orientation and recompute bounds with no previous
        // size compat cache.
        verify(mTask).onDescendantOrientationChanged(any(), same(newActivity));
        verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
        verify(newActivity).clearSizeCompatMode(false /* recomputeTask */);

        final Rect displayBounds = display.getBounds();
        final Rect taskBounds = mTask.getBounds();
        final Rect newActivityBounds = newActivity.getBounds();

        // Task and app bounds should be 700x1400 with the ratio as the display.
        assertTrue(mTask.isTaskLetterboxed());
        assertFalse(newActivity.inSizeCompatMode());
        assertEquals(taskBounds, newActivityBounds);
        assertEquals(displayBounds.height(), taskBounds.height());
        assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(),
                taskBounds.width());
    }

    @Test
    public void testDisplayIgnoreOrientationRequest_newLaunchedMaxAspectApp() {
        // Set up a display in landscape and ignoring orientation request.
        setUpDisplaySizeWithApp(2800, 1400);
        final DisplayContent display = mActivity.mDisplayContent;
        display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);

        // Portrait fixed app without max aspect.
        prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);

        assertTrue(mTask.isTaskLetterboxed());
        assertFalse(mActivity.inSizeCompatMode());

        // Launch another portrait fixed app with max aspect ratio as 1.3.
        spyOn(mTask);
        setBooted(display.mWmService.mAtmService);
        final ActivityRecord newActivity = new ActivityBuilder(display.mWmService.mAtmService)
                .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
                .setMaxAspectRatio(1.3f)
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .setTask(mTask)
                .build();

        // Update with new activity requested orientation and recompute bounds with no previous
        // size compat cache.
        verify(mTask).onDescendantOrientationChanged(any(), same(newActivity));
        verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
        verify(newActivity).clearSizeCompatMode(false /* recomputeTask */);

        final Rect displayBounds = display.getBounds();
        final Rect taskBounds = mTask.getBounds();
        final Rect newActivityBounds = newActivity.getBounds();

        // Task bounds should be 700x1400 with the ratio as the display.
        assertTrue(mTask.isTaskLetterboxed());
        assertEquals(displayBounds.height(), taskBounds.height());
        assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(),
                taskBounds.width());

        // App bounds should be 700x(710 x 1.3 = 910)
        assertFalse(newActivity.inSizeCompatMode());
        assertEquals(taskBounds.width(), newActivityBounds.width());
        assertEquals((long) Math.rint(taskBounds.width() * newActivity.info.maxAspectRatio),
                newActivityBounds.height());
    }

    private static WindowState addWindowToActivity(ActivityRecord activity) {
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;