summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Riddle Hsu <riddlehsu@google.com> 2019-04-03 13:08:47 +0800
committer Riddle Hsu <riddlehsu@google.com> 2019-04-11 02:05:59 +0000
commit61987bcaf58e5fca1b908b827784b8235c94ffaa (patch)
tree7f323482acfcd122a4284ba60436313cbfac5b7c
parent32fa3c237ded618c49269cf67924fd9d6510a8d0 (diff)
Ensure consistency of screenHeightDp for non-resizable activity
Originally the height of status bar (or other stable insets) is not excluded from screenHeightDp for size compatibility mode activity because the previous display where the activity resides may be removed or changed then there is no available and consistent display bounds to calculate the screen configuration. Now we precompute and store the display insets in each rotation, so the activity always has the original display insets to compute consistent screen configuration. Test: atest ActivityRecordTests Test: atest TaskRecordTests#testComputeConfigResourceOverrides Bug: 112288258 Change-Id: I5c769f8080fc5ae4eba966d2fa42cb650254074d
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java62
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java12
-rw-r--r--services/core/java/com/android/server/wm/TaskRecord.java33
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java27
5 files changed, 122 insertions, 17 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e2253e7f83ce..6cf36d692520 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -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);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6ae772003a9a..1934e2508c9b 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2775,6 +2775,16 @@ public class DisplayPolicy {
}
/**
+ * 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.
*
* @param displayRotation the current display rotation
@@ -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);
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 9713befc91f6..15060e1fc712 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -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) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 32e96a592207..44390b0c8d43 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -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
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index dc307b547a63..d87eed26b211 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -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);