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

Commit dedbe4d4 authored by Riddle Hsu's avatar Riddle Hsu Committed by android-build-merger
Browse files

Ensure consistency of screenHeightDp for non-resizable activity

am: 61987bca

Change-Id: I97527f8599b42ec31902c9825e1dc03721af699b
parents e04b9991 61987bca
Loading
Loading
Loading
Loading
+59 −3
Original line number Diff line number Diff line
@@ -88,6 +88,8 @@ import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;

import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
@@ -195,6 +197,7 @@ import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
import android.view.DisplayCutout;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
import android.view.RemoteAnimationDefinition;
@@ -382,6 +385,12 @@ final class ActivityRecord extends ConfigurationContainer {
    private int[] mHorizontalSizeConfigurations;
    private int[] mSmallestSizeConfigurations;

    /**
     * The precomputed display insets for resolving configuration. It will be non-null if
     * {@link #shouldUseSizeCompatMode} returns {@code true}.
     */
    private CompatDisplayInsets mCompatDisplayInsets;

    boolean pendingVoiceInteractionStart;   // Waiting for activity-invoked voice session
    IVoiceInteractionSession voiceSession;  // Voice interaction session for this activity

@@ -2833,6 +2842,11 @@ final class ActivityRecord extends ConfigurationContainer {
                // The smallest screen width is the short side of screen bounds. Because the bounds
                // and density won't be changed, smallestScreenWidthDp is also fixed.
                overrideConfig.smallestScreenWidthDp = parentConfig.smallestScreenWidthDp;

                final ActivityDisplay display = getDisplay();
                if (display != null && display.mDisplayContent != null) {
                    mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent);
                }
            }
        }
        onRequestedOverrideConfigurationChanged(overrideConfig);
@@ -2849,7 +2863,7 @@ final class ActivityRecord extends ConfigurationContainer {
            super.resolveOverrideConfiguration(newParentConfiguration);
            if (hasOverrideBounds) {
                task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
                        newParentConfiguration, true /* insideParentBounds */);
                        newParentConfiguration);
            }
        }

@@ -2922,9 +2936,8 @@ final class ActivityRecord extends ConfigurationContainer {
            resolvedBounds.right -= resolvedAppBounds.left;
        }

        // In size compatibility mode, activity is allowed to have larger bounds than its parent.
        task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                false /* insideParentBounds */);
                mCompatDisplayInsets);
        // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside
        // the parent bounds appropriately.
        if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
@@ -3450,6 +3463,7 @@ final class ActivityRecord extends ConfigurationContainer {
        // configuration.
        getRequestedOverrideConfiguration().setToDefaults();
        getResolvedOverrideConfiguration().setToDefaults();
        mCompatDisplayInsets = null;
        if (visible) {
            // Configuration will be ensured when becoming visible, so if it is already visible,
            // then the manual update is needed.
@@ -3796,4 +3810,46 @@ final class ActivityRecord extends ConfigurationContainer {
        writeToProto(proto);
        proto.end(token);
    }

    /**
     * The precomputed insets of the display in each rotation. This is used to make the size
     * compatibility mode activity compute the configuration without relying on its current display.
     */
    static class CompatDisplayInsets {
        final int mDisplayWidth;
        final int mDisplayHeight;

        /** The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. */
        final Rect[] mNonDecorInsets = new Rect[4];
        /**
         * The stableInsets for each rotation. Includes the status bar inset and the
         * nonDecorInsets. It is used to compute {@link Configuration#screenWidthDp} and
         * {@link Configuration#screenHeightDp}.
         */
        final Rect[] mStableInsets = new Rect[4];

        CompatDisplayInsets(DisplayContent display) {
            mDisplayWidth = display.mBaseDisplayWidth;
            mDisplayHeight = display.mBaseDisplayHeight;
            final DisplayPolicy policy = display.getDisplayPolicy();
            final DisplayCutout cutout = display.getDisplayInfo().displayCutout;
            for (int rotation = 0; rotation < 4; rotation++) {
                mNonDecorInsets[rotation] = new Rect();
                mStableInsets[rotation] = new Rect();
                final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
                final int dw = rotated ? mDisplayHeight : mDisplayWidth;
                final int dh = rotated ? mDisplayWidth : mDisplayHeight;
                policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]);
                mStableInsets[rotation].set(mNonDecorInsets[rotation]);
                policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation);
            }
        }

        void getDisplayBounds(Rect outBounds, int rotation) {
            final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
            final int dw = rotated ? mDisplayHeight : mDisplayWidth;
            final int dh = rotated ? mDisplayWidth : mDisplayHeight;
            outBounds.set(0, 0, dw, dh);
        }
    }
}
+11 −1
Original line number Diff line number Diff line
@@ -2774,6 +2774,16 @@ public class DisplayPolicy {
        return mShowingDream;
    }

    /**
     * Calculates the stable insets if we already have the non-decor insets.
     *
     * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
     * @param rotation The current display rotation.
     */
    void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
        inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
    }

    /**
     * Calculates the stable insets without running a layout.
     *
@@ -2789,7 +2799,7 @@ public class DisplayPolicy {

        // Navigation bar and status bar.
        getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
        outInsets.top = Math.max(outInsets.top, mStatusBarHeightForRotation[displayRotation]);
        convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
    }

    /**
+23 −10
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -2048,15 +2049,12 @@ class TaskRecord extends ConfigurationContainer {
        }
        mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);

        policy.getStableInsetsLw(displayInfo.rotation,
                displayInfo.logicalWidth, displayInfo.logicalHeight, displayInfo.displayCutout,
                mTmpInsets);
        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);

        policy.getNonDecorInsetsLw(displayInfo.rotation,
                displayInfo.logicalWidth, displayInfo.logicalHeight, displayInfo.displayCutout,
                mTmpInsets);
        policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
                displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
        intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);

        policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
    }

    /**
@@ -2073,7 +2071,7 @@ class TaskRecord extends ConfigurationContainer {

    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
            @NonNull Configuration parentConfig) {
        computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */);
        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
    }

    /**
@@ -2085,7 +2083,8 @@ class TaskRecord extends ConfigurationContainer {
     * just be inherited from the parent configuration.
     **/
    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
            @NonNull Configuration parentConfig, boolean insideParentBounds) {
            @NonNull Configuration parentConfig,
            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
        int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
            windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2103,6 +2102,9 @@ class TaskRecord extends ConfigurationContainer {
            inOutConfig.windowConfiguration.setAppBounds(bounds);
            outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
        }
        // Non-null compatibility insets means the activity prefers to keep its original size, so
        // the out bounds doesn't need to be restricted by the parent.
        final boolean insideParentBounds = compatInsets == null;
        if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
            final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
            if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
@@ -2125,6 +2127,17 @@ class TaskRecord extends ConfigurationContainer {
                // Set to app bounds because it excludes decor insets.
                mTmpNonDecorBounds.set(outAppBounds);
                mTmpStableBounds.set(outAppBounds);

                // Apply the given non-decor and stable insets to calculate the corresponding bounds
                // for screen size of configuration.
                final int rotation = parentConfig.windowConfiguration.getRotation();
                if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
                    compatInsets.getDisplayBounds(mTmpBounds, rotation);
                    intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
                            compatInsets.mNonDecorInsets[rotation]);
                    intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
                            compatInsets.mStableInsets[rotation]);
                }
            }

            if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+5 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
import android.util.MutableBoolean;
import android.view.DisplayInfo;

import androidx.test.filters.MediumTest;

@@ -87,6 +88,10 @@ public class ActivityRecordTests extends ActivityTestsBase {

        doReturn(false).when(mService).isBooting();
        doReturn(true).when(mService).isBooted();

        final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
        doReturn(mock(DisplayPolicy.class)).when(displayContent).getDisplayPolicy();
        doReturn(mock(DisplayInfo.class)).when(displayContent).getDisplayInfo();
    }

    @Test
+24 −3
Original line number Diff line number Diff line
@@ -25,7 +25,10 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.Surface.ROTATION_0;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.server.wm.WindowContainer.POSITION_TOP;

import static org.hamcrest.Matchers.not;
@@ -35,6 +38,8 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;

import android.app.ActivityManager;
@@ -357,6 +362,7 @@ public class TaskRecordTests extends ActivityTestsBase {
        parentConfig.densityDpi = 400;
        parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
        parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
        parentConfig.windowConfiguration.setRotation(ROTATION_0);

        // Portrait bounds.
        inOutConfig.windowConfiguration.getBounds().set(0, 0, shortSide, longSide);
@@ -370,12 +376,27 @@ public class TaskRecordTests extends ActivityTestsBase {
        inOutConfig.setToDefaults();
        // Landscape bounds.
        inOutConfig.windowConfiguration.getBounds().set(0, 0, longSide, shortSide);

        // Setup the display with a top stable inset. The later assertion will ensure the inset is
        // excluded from screenHeightDp.
        final int statusBarHeight = 100;
        final DisplayContent displayContent = mock(DisplayContent.class);
        final DisplayPolicy policy = mock(DisplayPolicy.class);
        doAnswer(invocationOnMock -> {
            final Rect insets = invocationOnMock.<Rect>getArgument(0);
            insets.top = statusBarHeight;
            return null;
        }).when(policy).convertNonDecorInsetsToStableInsets(any(), eq(ROTATION_0));
        doReturn(policy).when(displayContent).getDisplayPolicy();
        doReturn(mock(DisplayInfo.class)).when(displayContent).getDisplayInfo();

        // Without limiting to be inside the parent bounds, the out screen size should keep relative
        // to the input bounds.
        task.computeConfigResourceOverrides(inOutConfig, parentConfig,
                false /* insideParentBounds */);
        final ActivityRecord.CompatDisplayInsets compatIntsets =
                new ActivityRecord.CompatDisplayInsets(displayContent);
        task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);

        assertEquals(shortSide * DENSITY_DEFAULT / parentConfig.densityDpi,
        assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
                inOutConfig.screenHeightDp);
        assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
                inOutConfig.screenWidthDp);