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

Commit e3424aef authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Use orientation to determine size compat bounds

If a display is resized to different orientation, the mapping between
rotation and orientation is also inverted. So it may be inaccurate to
calculate compat bounds according to current rotation. While the given
orientation is better because it is relative to the width and height.
That makes sure either the requested orientation takes effect or just
inherit parent's configuration.

Also consider the following cases:
 - Display rotation changed but activity orientation is not changed.
   The display is forced rotated and the activity is fixed orientation.
 - Display orientation changed but rotation is not changed.
   Resize fixed rotation display between portrait and landscape.

Fixes: 166822610
Test: SizeCompatTests#testFixedScreenBoundsWhenDisplaySizeChanged
Change-Id: I329325c134f37e08ecdb6311bff5cd331e3bc7c3
parent faead856
Loading
Loading
Loading
Loading
+27 −29
Original line number Diff line number Diff line
@@ -7784,42 +7784,40 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        /** Gets the horizontal centered container bounds for size compatibility mode. */
        void getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation,
                boolean orientationRequested, boolean canChangeOrientation) {
            if (mIsFloating) {
            getFrameByOrientation(outBounds, orientation);
            if (mIsFloating) {
                outAppBounds.set(outBounds);
                return;
            }

            if (canChangeOrientation) {
                getBoundsByRotation(outBounds, rotation);
                if (orientationRequested) {
                    getFrameByOrientation(outAppBounds, orientation);
                } else {
                    outAppBounds.set(outBounds);
                }
            } else {
                if (orientationRequested) {
                    getFrameByOrientation(outBounds, orientation);
                    if ((outBounds.width() > outBounds.height()) != (mWidth > mHeight)) {
                        // The orientation is mismatched but the display cannot rotate. The bounds
                        // will fit to the short side of display.
            getBoundsByRotation(outAppBounds, rotation);
            final int dW = outAppBounds.width();
            final int dH = outAppBounds.height();
            final boolean isOrientationMismatched =
                    ((outBounds.width() > outBounds.height()) != (dW > dH));

            if (isOrientationMismatched && !canChangeOrientation && orientationRequested) {
                // The orientation is mismatched but the display cannot rotate. The bounds will fit
                // to the short side of container.
                if (orientation == ORIENTATION_LANDSCAPE) {
                            outBounds.bottom = (int) ((float) mWidth * mWidth / mHeight);
                            outBounds.right = mWidth;
                    outBounds.bottom = (int) ((float) dW * dW / dH);
                    outBounds.right = dW;
                } else {
                            outBounds.bottom = mHeight;
                            outBounds.right = (int) ((float) mHeight * mHeight / mWidth);
                    outBounds.bottom = dH;
                    outBounds.right = (int) ((float) dH * dH / dW);
                }
                        outBounds.offset(
                                getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
                    }
                } else {
                    outBounds.set(0, 0, mWidth, mHeight);
                outBounds.offset(getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
            }
            outAppBounds.set(outBounds);
            }

            if (rotation != ROTATION_UNDEFINED) {
            if (isOrientationMismatched) {
                // One side of container is smaller than the requested size, then it will be scaled
                // and the final position will be calculated according to the parent container and
                // scale, so the original size shouldn't be shrunk by insets.
                final Rect insets = mNonDecorInsets[rotation];
                outBounds.offset(insets.left, insets.top);
                outAppBounds.offset(insets.left, insets.top);
            } else if (rotation != ROTATION_UNDEFINED) {
                // Ensure the app bounds won't overlap with insets.
                Task.intersectWithInsetsIfFits(outAppBounds, outBounds, mNonDecorInsets[rotation]);
            }
+33 −3
Original line number Diff line number Diff line
@@ -35,7 +35,9 @@ 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.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doCallRealMethod;

import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
@@ -216,22 +218,50 @@ public class SizeCompatTests extends WindowTestsBase {

        final Rect origBounds = new Rect(mActivity.getBounds());
        final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
        final DisplayContent display = mActivity.mDisplayContent;

        // Change the size of current display.
        resizeDisplay(mStack.mDisplayContent, 1000, 2000);

        resizeDisplay(display, 1000, 2000);
        // The bounds should be [100, 0 - 1100, 2500].
        assertEquals(origBounds.width(), currentBounds.width());
        assertEquals(origBounds.height(), currentBounds.height());
        assertScaled();

        // The scale is 2000/2500=0.8. The horizontal centered offset is (1000-(1000*0.8))/2=100.
        final float scale = (float) display.mBaseDisplayHeight / currentBounds.height();
        final int offsetX = (int) (display.mBaseDisplayWidth - (origBounds.width() * scale)) / 2;
        assertEquals(offsetX, currentBounds.left);

        // The position of configuration bounds should be the same as compat bounds.
        assertEquals(mActivity.getBounds().left, currentBounds.left);
        assertEquals(mActivity.getBounds().top, currentBounds.top);

        // Change display size to a different orientation
        resizeDisplay(mStack.mDisplayContent, 2000, 1000);
        resizeDisplay(display, 2000, 1000);
        // The bounds should be [800, 0 - 1800, 2500].
        assertEquals(origBounds.width(), currentBounds.width());
        assertEquals(origBounds.height(), currentBounds.height());
        assertEquals(Configuration.ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);
        assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);

        // The previous resize operation doesn't consider the rotation change after size changed.
        // These setups apply the requested orientation to rotation as real case that the top fixed
        // portrait activity will determine the display rotation.
        final DisplayRotation displayRotation = display.getDisplayRotation();
        doCallRealMethod().when(displayRotation).updateRotationUnchecked(anyBoolean());
        // Skip unrelated layout procedures.
        mAtm.deferWindowLayout();
        display.reconfigureDisplayLocked();
        displayRotation.updateOrientation(display.getOrientation(), true /* forceUpdate */);
        display.sendNewConfiguration();

        assertEquals(Configuration.ORIENTATION_PORTRAIT, display.getConfiguration().orientation);
        assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
        // The size should still be in portrait [100, 0 - 1100, 2500] = 1000x2500.
        assertEquals(origBounds.width(), currentBounds.width());
        assertEquals(origBounds.height(), currentBounds.height());
        assertEquals(offsetX, currentBounds.left);
        assertScaled();
    }

    @Test