Merge changes from topic "sandboxing-display" into sc-dev

* changes:
  Temporarily exclude Launcher from sandboxing; to be reverted once bug is addressed.
  Sandbox letterbox and size compat apps
This commit is contained in:
Naomi Musgrave
2021-03-10 17:00:01 +00:00
committed by Android (Google) Code Review
8 changed files with 817 additions and 41 deletions

View File

@@ -24,8 +24,11 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.KeyguardManager;
import android.app.WindowConfiguration;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -44,11 +47,14 @@ import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
import com.android.internal.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
* Provides information about the size and density of a logical display.
@@ -111,6 +117,12 @@ public final class Display {
*/
private boolean mMayAdjustByFixedRotation;
/**
* Cache if the application is the recents component.
* TODO(b/179308296) Remove once Launcher addresses issue
*/
private Optional<Boolean> mIsRecentsComponent = Optional.empty();
/**
* The default Display id, which is the id of the primary display assuming there is one.
*/
@@ -678,9 +690,9 @@ public final class Display {
@UnsupportedAppUsage
public DisplayAdjustments getDisplayAdjustments() {
if (mResources != null) {
final DisplayAdjustments currentAdjustements = mResources.getDisplayAdjustments();
if (!mDisplayAdjustments.equals(currentAdjustements)) {
mDisplayAdjustments = new DisplayAdjustments(currentAdjustements);
final DisplayAdjustments currentAdjustments = mResources.getDisplayAdjustments();
if (!mDisplayAdjustments.equals(currentAdjustments)) {
mDisplayAdjustments = new DisplayAdjustments(currentAdjustments);
}
}
@@ -1278,6 +1290,18 @@ public final class Display {
public void getRealSize(Point outSize) {
synchronized (this) {
updateDisplayInfoLocked();
if (shouldReportMaxBounds()) {
final Rect bounds = mResources.getConfiguration()
.windowConfiguration.getMaxBounds();
outSize.x = bounds.width();
outSize.y = bounds.height();
if (DEBUG) {
Log.d(TAG, "getRealSize determined from max bounds: " + outSize);
}
// Skip adjusting by fixed rotation, since if it is necessary, the configuration
// should already reflect the expected rotation.
return;
}
outSize.x = mDisplayInfo.logicalWidth;
outSize.y = mDisplayInfo.logicalHeight;
if (mMayAdjustByFixedRotation) {
@@ -1336,6 +1360,17 @@ public final class Display {
public void getRealMetrics(DisplayMetrics outMetrics) {
synchronized (this) {
updateDisplayInfoLocked();
if (shouldReportMaxBounds()) {
mDisplayInfo.getMaxBoundsMetrics(outMetrics,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO,
mResources.getConfiguration());
if (DEBUG) {
Log.d(TAG, "getRealMetrics determined from max bounds: " + outMetrics);
}
// Skip adjusting by fixed rotation, since if it is necessary, the configuration
// should already reflect the expected rotation.
return;
}
mDisplayInfo.getLogicalMetrics(outMetrics,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
if (mMayAdjustByFixedRotation) {
@@ -1344,6 +1379,53 @@ public final class Display {
}
}
/**
* Determines if {@link WindowConfiguration#getMaxBounds()} should be reported as the
* display dimensions. The max bounds field may be smaller than the logical dimensions
* when apps need to be sandboxed.
*
* Depends upon {@link WindowConfiguration#getMaxBounds()} being set in
* {@link com.android.server.wm.ConfigurationContainer#providesMaxBounds()}. In most cases, this
* value reflects the size of the current DisplayArea.
* @return {@code true} when max bounds should be applied.
*/
private boolean shouldReportMaxBounds() {
if (mResources == null) {
return false;
}
final Configuration config = mResources.getConfiguration();
// TODO(b/179308296) Temporarily exclude Launcher from being given max bounds, by checking
// if the caller is the recents component.
return config != null && !config.windowConfiguration.getMaxBounds().isEmpty()
&& !isRecentsComponent();
}
/**
* Returns {@code true} when the calling package is the recents component.
* TODO(b/179308296) Remove once Launcher addresses issue
*/
boolean isRecentsComponent() {
if (mIsRecentsComponent.isPresent()) {
return mIsRecentsComponent.get();
}
if (mResources == null) {
return false;
}
try {
String recentsComponent = mResources.getString(R.string.config_recentsComponentName);
if (recentsComponent == null) {
return false;
}
String recentsPackage = ComponentName.unflattenFromString(recentsComponent)
.getPackageName();
mIsRecentsComponent = Optional.of(recentsPackage != null
&& recentsPackage.equals(ActivityThread.currentPackageName()));
return mIsRecentsComponent.get();
} catch (Resources.NotFoundException e) {
return false;
}
}
/**
* Gets the state of the display, such as whether it is on or off.
*

View File

@@ -24,6 +24,7 @@ import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
import static android.view.DisplayInfoProto.NAME;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -615,11 +616,29 @@ public final class DisplayInfo implements Parcelable {
getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
}
/**
* Populates {@code outMetrics} with details of the logical display. Bounds are limited
* by the logical size of the display.
*
* @param outMetrics the {@link DisplayMetrics} to be populated
* @param compatInfo the {@link CompatibilityInfo} to be applied
* @param configuration the {@link Configuration}
*/
public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
Configuration configuration) {
getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
}
/**
* Similar to {@link #getLogicalMetrics}, but the limiting bounds are determined from
* {@link WindowConfiguration#getMaxBounds()}
*/
public void getMaxBoundsMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
Configuration configuration) {
Rect bounds = configuration.windowConfiguration.getMaxBounds();
getMetricsWithSize(outMetrics, compatInfo, configuration, bounds.width(), bounds.height());
}
public int getNaturalWidth() {
return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
logicalWidth : logicalHeight;

View File

@@ -0,0 +1,531 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_90;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.quality.Strictness;
import java.util.function.Consumer;
/**
* Tests for {@link Display}.
*
* <p>Build/Install/Run:
*
* atest FrameworksMockingCoreTests:android.view.DisplayTests
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
public class DisplayTests {
private static final int APP_WIDTH = 272;
private static final int APP_HEIGHT = 700;
// Tablet size device, ROTATION_0 corresponds to portrait.
private static final int LOGICAL_WIDTH = 700;
private static final int LOGICAL_HEIGHT = 1800;
// Bounds of the app when the device is in portrait mode.
private static Rect sAppBoundsPortrait = buildAppBounds(LOGICAL_WIDTH, LOGICAL_HEIGHT);
private static Rect sAppBoundsLandscape = buildAppBounds(LOGICAL_HEIGHT, LOGICAL_WIDTH);
private StaticMockitoSession mMockitoSession;
private DisplayManagerGlobal mDisplayManagerGlobal;
private Context mApplicationContext;
private DisplayInfo mDisplayInfo = new DisplayInfo();
@Before
public void setupTests() {
mMockitoSession = mockitoSession()
.mockStatic(DisplayManagerGlobal.class)
.strictness(Strictness.LENIENT)
.startMocking();
// Ensure no adjustments are set before each test.
mApplicationContext = ApplicationProvider.getApplicationContext();
DisplayAdjustments displayAdjustments =
mApplicationContext.getResources().getDisplayAdjustments();
displayAdjustments.setFixedRotationAdjustments(null);
mApplicationContext.getResources().overrideDisplayAdjustments(null);
mApplicationContext.getResources().getConfiguration().windowConfiguration.setAppBounds(
null);
mApplicationContext.getResources().getConfiguration().windowConfiguration.setMaxBounds(
null);
mDisplayInfo.rotation = ROTATION_0;
mDisplayManagerGlobal = mock(DisplayManagerGlobal.class);
doReturn(mDisplayInfo).when(mDisplayManagerGlobal).getDisplayInfo(anyInt());
}
@After
public void teardownTests() {
if (mMockitoSession != null) {
mMockitoSession.finishMocking();
}
Mockito.framework().clearInlineMocks();
}
@Test
public void testConstructor_defaultDisplayAdjustments_matchesDisplayInfo() {
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
assertThat(display.getDisplayAdjustments()).isEqualTo(
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
DisplayInfo actualDisplayInfo = new DisplayInfo();
display.getDisplayInfo(actualDisplayInfo);
verifyDisplayInfo(actualDisplayInfo, mDisplayInfo);
}
@Test
public void testConstructor_defaultResources_matchesDisplayInfo() {
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
assertThat(display.getDisplayAdjustments()).isEqualTo(
mApplicationContext.getResources().getDisplayAdjustments());
DisplayInfo actualDisplayInfo = new DisplayInfo();
display.getDisplayInfo(actualDisplayInfo);
verifyDisplayInfo(actualDisplayInfo, mDisplayInfo);
}
@Test
public void testGetRotation_defaultDisplayAdjustments_rotationNotAdjusted() {
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
assertThat(display.getRotation()).isEqualTo(ROTATION_0);
}
@Test
public void testGetRotation_displayAdjustmentsWithoutOverride_rotationNotAdjusted() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, but no override is set.
DisplayAdjustments displayAdjustments = DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
final FixedRotationAdjustments fixedRotationAdjustments =
new FixedRotationAdjustments(ROTATION_90, APP_WIDTH, APP_HEIGHT,
DisplayCutout.NO_CUTOUT);
displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
// GIVEN display is constructed with display adjustments.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
displayAdjustments);
// THEN rotation is not adjusted since no override was set.
assertThat(display.getRotation()).isEqualTo(ROTATION_0);
}
@Test
public void testGetRotation_resourcesWithoutOverride_rotationNotAdjusted() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, but no override is set.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN rotation is not adjusted since no override is set.
assertThat(display.getRotation()).isEqualTo(ROTATION_0);
}
@Test
public void testGetRotation_resourcesWithOverrideDisplayAdjustments_rotationAdjusted() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, and an override is set.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN rotation is adjusted since an override is set.
assertThat(display.getRotation()).isEqualTo(ROTATION_90);
}
@Test
public void testGetRealSize_defaultResourcesPortrait_matchesLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches display orientation.
verifyRealSizeIsPortrait(display);
}
@Test
public void testGetRealSize_defaultResourcesLandscape_matchesRotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches display orientation.
verifyRealSizeIsLandscape(display);
}
@Test
public void testGetRealSize_defaultDisplayAdjustmentsPortrait_matchesLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
// THEN real size matches display orientation.
verifyRealSizeIsPortrait(display);
}
@Test
public void testGetRealSize_defaultDisplayAdjustmentsLandscape_matchesLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
// THEN real size matches display orientation.
verifyRealSizeIsLandscape(display);
}
@Test
public void testGetRealSize_resourcesPortraitWithFixedRotation_notRotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches display orientation.
verifyRealSizeIsLandscape(display);
}
@Test
public void testGetRealSize_resourcesWithLandscapeFixedRotation_notRotatedLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches display orientation.
verifyRealSizeIsPortrait(display);
}
@Test
public void testGetRealSize_resourcesWithPortraitOverrideRotation_rotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, and an override is set.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app orientation.
verifyRealSizeIsPortrait(display);
}
@Test
public void testGetRealSize_resourcesWithLandscapeOverrideRotation_rotatedLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated, and an override is set.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app orientation.
verifyRealSizeIsLandscape(display);
}
@Test
public void testGetRealSize_resourcesPortraitSandboxed_matchesSandboxBounds() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN app is letterboxed.
setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
sAppBoundsPortrait);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app bounds.
verifyRealSizeMatchesApp(display, sAppBoundsPortrait);
}
@Test
public void testGetRealSize_resourcesLandscapeSandboxed_matchesSandboxBounds() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN app is letterboxed.
setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
sAppBoundsLandscape);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real size matches app bounds.
verifyRealSizeMatchesApp(display, sAppBoundsLandscape);
}
@Test
public void testGetRealMetrics_defaultResourcesPortrait_matchesLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches display orientation.
verifyRealMetricsIsPortrait(display);
}
@Test
public void testGetRealMetrics_defaultResourcesLandscape_matchesRotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches display orientation.
verifyRealMetricsIsLandscape(display);
}
@Test
public void testGetRealMetrics_defaultDisplayAdjustmentsPortrait_matchesLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
// THEN real metrics matches display orientation.
verifyRealMetricsIsPortrait(display);
}
@Test
public void testGetRealMetrics_defaultDisplayAdjustmentsLandscape_matchesLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
// THEN real metrics matches display orientation.
verifyRealMetricsIsLandscape(display);
}
@Test
public void testGetRealMetrics_resourcesPortraitWithFixedRotation_notRotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches display orientation.
verifyRealMetricsIsLandscape(display);
}
@Test
public void testGetRealMetrics_resourcesWithLandscapeFixedRotation_notRotatedLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches display orientation.
verifyRealMetricsIsPortrait(display);
}
@Test
public void testGetRealMetrics_resourcesWithPortraitOverrideRotation_rotatedLogicalSize() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated with an override.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_0);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app orientation.
verifyRealMetricsIsPortrait(display);
}
@Test
public void testGetRealMetrics_resourcesWithLandscapeOverrideRotation_rotatedLogicalSize() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN fixed rotation adjustments are rotated.
setOverrideFixedRotationAdjustments(mApplicationContext.getResources(), ROTATION_90);
// GIVEN display is constructed with default resources.
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app orientation.
verifyRealMetricsIsLandscape(display);
}
@Test
public void testGetRealMetrics_resourcesPortraitSandboxed_matchesSandboxBounds() {
// GIVEN display is not rotated.
setDisplayInfoPortrait(mDisplayInfo);
// GIVEN app is letterboxed.
setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
sAppBoundsPortrait);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app bounds.
verifyRealMetricsMatchesApp(display, sAppBoundsPortrait);
}
@Test
public void testGetRealMetrics_resourcesLandscapeSandboxed_matchesSandboxBounds() {
// GIVEN display is rotated.
setDisplayInfoLandscape(mDisplayInfo);
// GIVEN app is letterboxed.
setMaxBoundsSandboxedToMatchAppBounds(mApplicationContext.getResources(),
sAppBoundsLandscape);
final Display display = new Display(mDisplayManagerGlobal, DEFAULT_DISPLAY, mDisplayInfo,
mApplicationContext.getResources());
// THEN real metrics matches app bounds.
verifyRealMetricsMatchesApp(display, sAppBoundsLandscape);
}
// Given rotated display dimensions, calculate the letterboxed app bounds.
private static Rect buildAppBounds(int displayWidth, int displayHeight) {
final int midWidth = displayWidth / 2;
final int left = midWidth - (APP_WIDTH / 2);
final int right = midWidth + (APP_WIDTH / 2);
final int midHeight = displayHeight / 2;
// Coordinate system starts at top left.
final int top = midHeight - (APP_HEIGHT / 2);
final int bottom = midHeight + (APP_HEIGHT / 2);
return new Rect(left, top, right, bottom);
}
private static void setDisplayInfoLandscape(DisplayInfo displayInfo) {
displayInfo.rotation = ROTATION_90;
// Flip width & height assignment since the device is rotated.
displayInfo.logicalWidth = LOGICAL_HEIGHT;
displayInfo.logicalHeight = LOGICAL_WIDTH;
}
private static void setDisplayInfoPortrait(DisplayInfo displayInfo) {
displayInfo.rotation = ROTATION_0;
displayInfo.logicalWidth = LOGICAL_WIDTH;
displayInfo.logicalHeight = LOGICAL_HEIGHT;
}
/**
* Set max bounds to be sandboxed to the app bounds, indicating the app is in
* size compat mode or letterbox.
*/
private static void setMaxBoundsSandboxedToMatchAppBounds(Resources resources, Rect appBounds) {
resources.getConfiguration().windowConfiguration.setMaxBounds(appBounds);
}
/**
* Do not compare entire display info, since it is updated to match display the test is run on.
*/
private static void verifyDisplayInfo(DisplayInfo actual, DisplayInfo expected) {
assertThat(actual.displayId).isEqualTo(expected.displayId);
assertThat(actual.rotation).isEqualTo(expected.rotation);
assertThat(actual.logicalWidth).isEqualTo(LOGICAL_WIDTH);
assertThat(actual.logicalHeight).isEqualTo(LOGICAL_HEIGHT);
}
private static void verifyRealSizeIsLandscape(Display display) {
Point size = new Point();
display.getRealSize(size);
// Flip the width and height check since the device is rotated.
assertThat(size).isEqualTo(new Point(LOGICAL_HEIGHT, LOGICAL_WIDTH));
}
private static void verifyRealMetricsIsLandscape(Display display) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
// Flip the width and height check since the device is rotated.
assertThat(metrics.widthPixels).isEqualTo(LOGICAL_HEIGHT);
assertThat(metrics.heightPixels).isEqualTo(LOGICAL_WIDTH);
}
private static void verifyRealSizeIsPortrait(Display display) {
Point size = new Point();
display.getRealSize(size);
assertThat(size).isEqualTo(new Point(LOGICAL_WIDTH, LOGICAL_HEIGHT));
}
private static void verifyRealMetricsIsPortrait(Display display) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
assertThat(metrics.widthPixels).isEqualTo(LOGICAL_WIDTH);
assertThat(metrics.heightPixels).isEqualTo(LOGICAL_HEIGHT);
}
private static void verifyRealSizeMatchesApp(Display display, Rect appBounds) {
Point size = new Point();
display.getRealSize(size);
assertThat(size).isEqualTo(new Point(appBounds.width(), appBounds.height()));
}
private static void verifyRealMetricsMatchesApp(Display display, Rect appBounds) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
assertThat(metrics.widthPixels).isEqualTo(appBounds.width());
assertThat(metrics.heightPixels).isEqualTo(appBounds.height());
}
private static FixedRotationAdjustments setOverrideFixedRotationAdjustments(
Resources resources, @Surface.Rotation int rotation) {
FixedRotationAdjustments fixedRotationAdjustments =
setFixedRotationAdjustments(resources, rotation);
resources.overrideDisplayAdjustments(
buildOverrideRotationAdjustments(fixedRotationAdjustments));
return fixedRotationAdjustments;
}
private static FixedRotationAdjustments setFixedRotationAdjustments(Resources resources,
@Surface.Rotation int rotation) {
final FixedRotationAdjustments fixedRotationAdjustments =
new FixedRotationAdjustments(rotation, APP_WIDTH, APP_HEIGHT,
DisplayCutout.NO_CUTOUT);
resources.getDisplayAdjustments().setFixedRotationAdjustments(fixedRotationAdjustments);
return fixedRotationAdjustments;
}
private static Consumer<DisplayAdjustments> buildOverrideRotationAdjustments(
FixedRotationAdjustments fixedRotationAdjustments) {
return consumedDisplayAdjustments
-> consumedDisplayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
}
}

View File

@@ -1219,6 +1219,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DragState.java"
},
"-681380736": {
"message": "Sandbox max bounds for uid %s to bounds %s due to letterboxing from mismatch with parent bounds? %s size compat mode %s",
"level": "DEBUG",
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
"-677449371": {
"message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b",
"level": "DEBUG",

View File

@@ -16,6 +16,7 @@
package com.android.server.wm;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
@@ -86,6 +87,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.res.Configuration.EMPTY;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -205,6 +207,7 @@ import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.ACTIVITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -278,6 +281,7 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.permission.PermissionManager;
import android.service.dreams.DreamActivity;
import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
@@ -6955,6 +6959,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// layout traversals.
mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
getResolvedOverrideConfiguration().seq = mConfigurationSeq;
// Sandbox max bounds by setting it to the app bounds, if activity is letterboxed or in
// size compat mode.
if (providesMaxBounds()) {
if (DEBUG_CONFIGURATION) {
ProtoLog.d(WM_DEBUG_CONFIGURATION, "Sandbox max bounds for uid %s to bounds %s "
+ "due to letterboxing from mismatch with parent bounds? %s size compat "
+ "mode %s", getUid(),
resolvedConfig.windowConfiguration.getBounds(), !matchParentBounds(),
inSizeCompatMode());
}
resolvedConfig.windowConfiguration
.setMaxBounds(resolvedConfig.windowConfiguration.getBounds());
}
}
/**
@@ -7296,6 +7314,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return super.getBounds();
}
@Override
public boolean providesMaxBounds() {
// System and SystemUI should always be able to access the physical display bounds,
// so do not provide it with the overridden maximum bounds.
// TODO(b/179179513) check WindowState#mOwnerCanAddInternalSystemWindow instead
if (getUid() == SYSTEM_UID || PermissionManager.checkPermission(INTERNAL_SYSTEM_WINDOW,
getPid(), info.applicationInfo.uid) == PERMISSION_GRANTED) {
return false;
}
// Max bounds should be sandboxed where an activity is letterboxed (activity bounds will be
// smaller than task bounds) or put in size compat mode.
return !matchParentBounds() || inSizeCompatMode();
}
@VisibleForTesting
@Override
Rect getAnimationBounds(int appRootTaskClipMode) {

View File

@@ -367,8 +367,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
* Returns {@code true} if this {@link ConfigurationContainer} provides the maximum bounds to
* its child {@link ConfigurationContainer}s. Returns {@code false}, otherwise.
* <p>
* The maximum bounds is how large a window can be expanded. Currently only
* {@link DisplayContent} and {@link DisplayArea} effect this property.
* The maximum bounds is how large a window can be expanded.
* </p>
*/
protected boolean providesMaxBounds() {

View File

@@ -40,6 +40,8 @@ import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -117,18 +119,19 @@ public class SizeCompatTests extends WindowTestsBase {
@Test
public void testKeepBoundsWhenChangingFromFreeformToFullscreen() {
removeGlobalMinSizeRestriction();
// create freeform display and a freeform app
// Create landscape freeform display and a freeform app.
DisplayContent display = new TestDisplayContent.Builder(mAtm, 2000, 1000)
.setCanRotate(false)
.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM).build();
setUpApp(display);
// Put app window into freeform and then make it a compat app.
// Put app window into portrait freeform and then make it a compat app.
final Rect bounds = new Rect(100, 100, 400, 600);
mTask.setBounds(bounds);
prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
assertEquals(bounds, mActivity.getBounds());
// Activity is not yet in size compat mode; it is filling the freeform window.
assertMaxBoundsInheritDisplayAreaBounds();
// The activity should be able to accept negative x position [-150, 100 - 150, 600].
final int dx = bounds.left + bounds.width() / 2;
@@ -137,7 +140,7 @@ public class SizeCompatTests extends WindowTestsBase {
final int density = mActivity.getConfiguration().densityDpi;
// change display configuration to fullscreen
// Change display configuration to fullscreen.
Configuration c = new Configuration(display.getRequestedOverrideConfiguration());
c.windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
display.onRequestedOverrideConfigurationChanged(c);
@@ -147,6 +150,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(bounds.width(), mActivity.getBounds().width());
assertEquals(bounds.height(), mActivity.getBounds().height());
assertEquals(density, mActivity.getConfiguration().densityDpi);
// Size compat mode is sandboxed at the activity level.
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -172,6 +177,12 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(appBounds.height(), appBounds.width() * aspectRatio, 0.5f /* delta */);
// The decor height should be a part of the effective bounds.
assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight);
// Activity max bounds should be sandboxed; activity is letterboxed due to aspect ratio.
assertActivityMaxBoundsSandboxed();
// Activity max bounds ignore notch, since an app can be shown past the notch (although app
// is currently limited by the notch).
assertThat(mActivity.getWindowConfiguration().getMaxBounds().height())
.isEqualTo(displayBounds.height());
mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertFitted();
@@ -181,9 +192,17 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */);
// The notch is no longer on top.
assertEquals(appBounds, mActivity.getBounds());
// Activity max bounds are sandboxed.
assertActivityMaxBoundsSandboxed();
mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertFitted();
// Activity max bounds should be sandboxed; activity is letterboxed due to aspect ratio.
assertActivityMaxBoundsSandboxed();
// Activity max bounds ignore notch, since an app can be shown past the notch (although app
// is currently limited by the notch).
assertThat(mActivity.getWindowConfiguration().getMaxBounds().height())
.isEqualTo(displayBounds.height());
}
@Test
@@ -206,6 +225,9 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(originalBounds.width(), mActivity.getBounds().width());
assertEquals(originalBounds.height(), mActivity.getBounds().height());
assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
// Activity is sandboxed; it is in size compat mode since it is not resizable and has a
// max aspect ratio.
assertActivityMaxBoundsSandboxed();
assertScaled();
}
@@ -213,11 +235,13 @@ public class SizeCompatTests extends WindowTestsBase {
public void testFixedScreenBoundsWhenDisplaySizeChanged() {
setUpDisplaySizeWithApp(1000, 2500);
prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
final DisplayContent display = mActivity.mDisplayContent;
assertFitted();
// Activity inherits bounds from TaskDisplayArea, since not sandboxed.
assertMaxBoundsInheritDisplayAreaBounds();
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(display, 1000, 2000);
@@ -234,6 +258,8 @@ public class SizeCompatTests extends WindowTestsBase {
// The position of configuration bounds should be the same as compat bounds.
assertEquals(mActivity.getBounds().left, currentBounds.left);
assertEquals(mActivity.getBounds().top, currentBounds.top);
// Activity is sandboxed to the offset size compat bounds.
assertActivityMaxBoundsSandboxed();
// Change display size to a different orientation
resizeDisplay(display, 2000, 1000);
@@ -242,6 +268,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(origBounds.height(), currentBounds.height());
assertEquals(ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);
assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation);
// Activity is sandboxed to the offset size compat bounds.
assertActivityMaxBoundsSandboxed();
// 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
@@ -261,6 +289,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(origBounds.height(), currentBounds.height());
assertEquals(offsetX, currentBounds.left);
assertScaled();
// Activity is sandboxed due to size compat mode.
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -276,6 +306,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(bounds.width(), bounds.height() * maxAspect, 0.0001f /* delta */);
// The position should be horizontal centered.
assertEquals((displayWidth - bounds.width()) / 2, bounds.left);
// Activity max bounds should be sandboxed since it is letterboxed.
assertActivityMaxBoundsSandboxed();
mActivity.mDisplayContent.setImeLayeringTarget(addWindowToActivity(mActivity));
// Make sure IME cannot attach to the app, otherwise IME window will also be shifted.
@@ -287,6 +319,8 @@ public class SizeCompatTests extends WindowTestsBase {
// It should keep non-attachable because the resolved bounds will be computed according to
// the aspect ratio that won't match its parent bounds.
assertFalse(mActivity.mDisplayContent.isImeAttachedToApp());
// Activity max bounds should be sandboxed since it is letterboxed.
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -312,14 +346,13 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
public void testMoveToDifferentOrientDisplay() {
public void testMoveToDifferentOrientationDisplay() {
setUpDisplaySizeWithApp(1000, 2500);
prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
assertFitted();
final Rect configBounds = mActivity.getWindowConfiguration().getBounds();
final int origWidth = configBounds.width();
final int origHeight = configBounds.height();
final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
final Rect originalBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
final int notchHeight = 100;
final DisplayContent newDisplay = new TestDisplayContent.Builder(mAtm, 2000, 1000)
@@ -328,37 +361,45 @@ public class SizeCompatTests extends WindowTestsBase {
// Move the non-resizable activity to the new display.
mTask.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */);
// The configuration bounds [820, 0 - 1820, 2500] should keep the same.
assertEquals(origWidth, configBounds.width());
assertEquals(origHeight, configBounds.height());
assertEquals(originalBounds.width(), currentBounds.width());
assertEquals(originalBounds.height(), currentBounds.height());
assertScaled();
// Activity max bounds are sandboxed due to size compat mode on the new display.
assertActivityMaxBoundsSandboxed();
final Rect newDisplayBounds = newDisplay.getWindowConfiguration().getBounds();
// The scaled bounds should exclude notch area (1000 - 100 == 360 * 2500 / 1000 = 900).
assertEquals(newDisplayBounds.height() - notchHeight,
(int) ((float) mActivity.getBounds().width() * origHeight / origWidth));
(int) ((float) mActivity.getBounds().width() * originalBounds.height()
/ originalBounds.width()));
// Recompute the natural configuration in the new display.
mActivity.clearSizeCompatMode();
mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
// Because the display cannot rotate, the portrait activity will fit the short side of
// display with keeping portrait bounds [200, 0 - 700, 1000] in center.
assertEquals(newDisplayBounds.height(), configBounds.height());
assertEquals(configBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(),
configBounds.width());
assertEquals(newDisplayBounds.height(), currentBounds.height());
assertEquals(currentBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(),
currentBounds.width());
assertFitted();
// The appBounds should be [200, 100 - 700, 1000].
final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
assertEquals(configBounds.width(), appBounds.width());
assertEquals(configBounds.height() - notchHeight, appBounds.height());
assertEquals(currentBounds.width(), appBounds.width());
assertEquals(currentBounds.height() - notchHeight, appBounds.height());
// Activity max bounds are sandboxed due to letterboxing from orientation mismatch with
// display.
assertActivityMaxBoundsSandboxed();
}
@Test
public void testFixedOrientRotateCutoutDisplay() {
public void testFixedOrientationRotateCutoutDisplay() {
// Create a display with a notch/cutout
final int notchHeight = 60;
setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2500)
final int width = 1000;
setUpApp(new TestDisplayContent.Builder(mAtm, width, 2500)
.setNotch(notchHeight).build());
// Bounds=[0, 0 - 1000, 1460], AppBounds=[0, 60 - 1000, 1460].
// Bounds=[0, 0 - 1000, 1400], AppBounds=[0, 60 - 1000, 1460].
final float maxAspect = 1.4f;
prepareUnresizable(mActivity, 1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
@@ -366,6 +407,11 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect origBounds = new Rect(currentBounds);
final Rect origAppBounds = new Rect(appBounds);
// Activity is sandboxed, and bounds include the area consumed by the notch.
assertActivityMaxBoundsSandboxed();
assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds().height())
.isEqualTo(Math.round(width * maxAspect) + notchHeight);
// Although the activity is fixed orientation, force rotate the display.
rotateDisplay(mActivity.mDisplayContent, ROTATION_270);
assertEquals(ROTATION_270, mTask.getWindowConfiguration().getRotation());
@@ -381,10 +427,13 @@ public class SizeCompatTests extends WindowTestsBase {
// The position in configuration should be global coordinates.
assertEquals(mActivity.getBounds().left, currentBounds.left);
assertEquals(mActivity.getBounds().top, currentBounds.top);
// Activity max bounds are sandboxed due to size compat mode.
assertActivityMaxBoundsSandboxed();
}
@Test
public void testFixedAspOrientChangeOrient() {
public void testFixedAspectRatioOrientationChangeOrientation() {
setUpDisplaySizeWithApp(1000, 2500);
final float maxAspect = 1.4f;
@@ -396,6 +445,8 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect originalAppBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds());
assertEquals((int) (originalBounds.width() * maxAspect), originalBounds.height());
// Activity is sandboxed due to fixed aspect ratio.
assertActivityMaxBoundsSandboxed();
// Change the fixed orientation.
mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -407,6 +458,8 @@ public class SizeCompatTests extends WindowTestsBase {
mActivity.getWindowConfiguration().getAppBounds().height());
assertEquals(originalAppBounds.height(),
mActivity.getWindowConfiguration().getAppBounds().width());
// Activity is sandboxed due to fixed aspect ratio.
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -455,6 +508,8 @@ public class SizeCompatTests extends WindowTestsBase {
// restarted and the override configuration won't be cleared.
verify(mActivity, never()).restartProcessIfVisible();
assertScaled();
// Activity max bounds are sandboxed due to size compat mode, even if is not visible.
assertActivityMaxBoundsSandboxed();
// Change display density
display.mBaseDisplayDensity = (int) (0.7f * display.mBaseDisplayDensity);
@@ -568,12 +623,16 @@ public class SizeCompatTests extends WindowTestsBase {
// in multi-window mode.
mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
assertFalse(activity.shouldCreateCompatDisplayInsets());
// Activity should not be sandboxed.
assertMaxBoundsInheritDisplayAreaBounds();
// The non-resizable activity should not be size compat because the display support
// changing windowing mode from fullscreen to freeform.
mTask.mDisplayContent.setDisplayWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
assertFalse(activity.shouldCreateCompatDisplayInsets());
// Activity should not be sandboxed.
assertMaxBoundsInheritDisplayAreaBounds();
}
@Test
@@ -637,6 +696,9 @@ public class SizeCompatTests extends WindowTestsBase {
// be transparent.
assertFalse(displayPolicy.isFullyTransparentAllowed(w, TYPE_STATUS_BAR));
// Activity is sandboxed.
assertActivityMaxBoundsSandboxed();
// Make the activity fill the display.
prepareUnresizable(mActivity, 10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
@@ -646,6 +708,7 @@ public class SizeCompatTests extends WindowTestsBase {
// The letterbox should only cover the notch area, so status bar can be transparent.
assertEquals(new Rect(notchHeight, 0, 0, 0), mActivity.getLetterboxInsets());
assertTrue(displayPolicy.isFullyTransparentAllowed(w, TYPE_STATUS_BAR));
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -668,6 +731,7 @@ public class SizeCompatTests extends WindowTestsBase {
// App should launch in fixed orientation letterbox.
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
// Activity bounds should be 700x1400 with the ratio as the display.
assertEquals(displayBounds.height(), activityBounds.height());
@@ -789,6 +853,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertScaled();
assertEquals(activityBounds.width(), newActivityBounds.width());
assertEquals(activityBounds.height(), newActivityBounds.height());
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -800,29 +865,29 @@ public class SizeCompatTests extends WindowTestsBase {
// Portrait fixed app without max aspect.
prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
Rect activityBounds = new Rect(mActivity.getBounds());
// App should launch in fullscreen.
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertEquals(displayBounds, activityBounds);
// Activity inherits max bounds from TaskDisplayArea.
assertMaxBoundsInheritDisplayAreaBounds();
// Rotate display to landscape.
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
activityBounds = new Rect(mActivity.getBounds());
assertTrue(displayBounds.width() > displayBounds.height());
final Rect rotatedDisplayBounds = new Rect(mActivity.mDisplayContent.getBounds());
final Rect rotatedActivityBounds = new Rect(mActivity.getBounds());
assertTrue(rotatedDisplayBounds.width() > rotatedDisplayBounds.height());
// App should be in size compat.
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
assertThat(mActivity.inSizeCompatMode()).isTrue();
assertActivityMaxBoundsSandboxed();
// App bounds should be 700x1400 with the ratio as the display.
assertEquals(displayBounds.height(), activityBounds.height());
assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(),
activityBounds.width());
assertEquals(rotatedDisplayBounds.height(), rotatedActivityBounds.height());
assertEquals(rotatedDisplayBounds.height() * rotatedDisplayBounds.height()
/ rotatedDisplayBounds.width(), rotatedActivityBounds.width());
}
@Test
@@ -859,6 +924,7 @@ public class SizeCompatTests extends WindowTestsBase {
// has 700x1400 bounds with the ratio as the display.
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(newActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
assertEquals(taskBounds, displayBounds);
assertEquals(displayBounds.height(), newActivityBounds.height());
assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(),
@@ -899,6 +965,11 @@ public class SizeCompatTests extends WindowTestsBase {
// Task bounds should fill parent bounds.
assertEquals(displayBounds, taskBounds);
// Prior and new activity max bounds are sandboxed due to letterbox.
assertThat(newActivity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(newActivityBounds);
assertActivityMaxBoundsSandboxed();
// Activity bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio.
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(newActivity.inSizeCompatMode());
@@ -927,6 +998,9 @@ public class SizeCompatTests extends WindowTestsBase {
// App should be in size compat.
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
assertThat(mActivity.inSizeCompatMode()).isTrue();
// Activity max bounds are sandboxed due to size compat mode.
assertActivityMaxBoundsSandboxed();
final Rect activityBounds = new Rect(mActivity.getBounds());
mTask.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */);
@@ -936,6 +1010,8 @@ public class SizeCompatTests extends WindowTestsBase {
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
assertEquals(activityBounds, mActivity.getBounds());
// Activity max bounds are sandboxed due to size compat.
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -951,6 +1027,7 @@ public class SizeCompatTests extends WindowTestsBase {
// In fixed orientation letterbox
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
// Rotate display to portrait.
rotateDisplay(display, ROTATION_90);
@@ -958,13 +1035,15 @@ public class SizeCompatTests extends WindowTestsBase {
// App should be in size compat.
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
assertActivityMaxBoundsSandboxed();
// Rotate display to landscape.
rotateDisplay(display, ROTATION_180);
// In Task letterbox
// In activity letterbox
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -982,20 +1061,23 @@ public class SizeCompatTests extends WindowTestsBase {
// In fixed orientation letterbox
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
// Rotate display to portrait.
// Rotate display to landscape.
rotateDisplay(display, ROTATION_90);
// App should be in size compat.
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertScaled();
assertActivityMaxBoundsSandboxed();
// Rotate display to landscape.
// Rotate display to portrait.
rotateDisplay(display, ROTATION_180);
// In fixed orientation letterbox
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertActivityMaxBoundsSandboxed();
}
@Test
@@ -1012,12 +1094,18 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(ORIENTATION_LANDSCAPE, display.getConfiguration().orientation);
assertEquals(2800, displayBounds.width());
assertEquals(1400, displayBounds.height());
taskDisplayArea.setBounds(0, 0, 2400, 1000);
Rect displayAreaBounds = new Rect(0, 0, 2400, 1000);
taskDisplayArea.setBounds(displayAreaBounds);
final Rect activityBounds = new Rect(mActivity.getBounds());
assertFalse(mActivity.inSizeCompatMode());
assertEquals(2400, activityBounds.width());
assertEquals(1000, activityBounds.height());
// Task and activity maximum bounds inherit from TaskDisplayArea bounds.
assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(displayAreaBounds);
assertThat(mTask.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(displayAreaBounds);
}
@Test
@@ -1042,6 +1130,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertScaled();
assertEquals(originalBounds,
mActivity.getConfiguration().windowConfiguration.getBounds());
assertActivityMaxBoundsSandboxed();
// Recompute the natural configuration of the non-resizable activity and the split screen.
mActivity.clearSizeCompatMode();
@@ -1053,12 +1142,13 @@ public class SizeCompatTests extends WindowTestsBase {
addWindowToActivity(mActivity);
mActivity.mRootWindowContainer.performSurfacePlacement();
// Split screen is also in portrait [1000,1400], so activty should be in fixed orientation
// Split screen is also in portrait [1000,1400], so activity should be in fixed orientation
// letterbox.
assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation);
assertEquals(ORIENTATION_LANDSCAPE, mActivity.getConfiguration().orientation);
assertFitted();
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertActivityMaxBoundsSandboxed();
// Letterbox should fill the gap between the split screen and the letterboxed activity.
final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds());
@@ -1165,6 +1255,22 @@ public class SizeCompatTests extends WindowTestsBase {
assertFalse(mActivity.hasSizeCompatBounds());
}
/** Asserts the activity max bounds inherit from the TaskDisplayArea. */
private void assertMaxBoundsInheritDisplayAreaBounds() {
assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(mTask.getDisplayArea().getBounds());
}
/**
* Asserts activity-level letterbox or size compat mode size compat mode, so activity max
* bounds are sandboxed.
*/
private void assertActivityMaxBoundsSandboxed() {
// Activity max bounds are sandboxed due to size compat mode.
assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds())
.isEqualTo(mActivity.getWindowConfiguration().getBounds());
}
static Configuration rotateDisplay(DisplayContent display, int rotation) {
final Configuration c = new Configuration();
display.getDisplayRotation().setRotation(rotation);

View File

@@ -136,6 +136,7 @@ class TestDisplayContent extends DisplayContent {
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
final TestDisplayContent newDisplay = createInternal(display);
// disable the normal system decorations
final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy();
spyOn(displayPolicy);