diff options
6 files changed, 461 insertions, 59 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 1d2cd0a0a350..c2fe93110b1b 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -995,7 +995,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp getPendingTransaction().apply(); // Setup the policy and build the display area hierarchy. - mDisplayAreaPolicy = mWmService.mDisplayAreaPolicyProvider.instantiate( + mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate( mWmService, this /* content */, this /* root */, mImeWindowsContainers); // Sets the display content for the children. diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index cf6468d66b57..6242fe9a1444 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1152,10 +1152,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< /** * Check if this container or its parent will handle orientation changes from descendants. It's - * different from the return value of {@link #onDescendantOrientationChanged(IBinder, - * WindowContainer)} in the sense that the return value of this method tells if this - * container or its parent will handle the request eventually, while the return value of the - * other method is if it handled the request synchronously. + * different from the return value of {@link #onDescendantOrientationChanged(WindowContainer)} + * in the sense that the return value of this method tells if this container or its parent will + * handle the request eventually, while the return value of the other method is if it handled + * the request synchronously. * * @return {@code true} if it handles or will handle orientation change in the future; {@code * false} if it won't handle the change at anytime. @@ -1221,7 +1221,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } /** - * Calls {@link #setOrientation(int, IBinder, WindowContainer)} with {@code null} to the last 2 + * Calls {@link #setOrientation(int, WindowContainer)} with {@code null} to the last 2 * parameters. * * @param orientation the specified orientation. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d4efa8a7ab91..a4dc21842f1b 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -459,7 +459,7 @@ public class WindowManagerService extends IWindowManager.Stub final WindowTracing mWindowTracing; - final DisplayAreaPolicy.Provider mDisplayAreaPolicyProvider; + private final DisplayAreaPolicy.Provider mDisplayAreaPolicyProvider; final private KeyguardDisableHandler mKeyguardDisableHandler; // TODO: eventually unify all keyguard state in a common place instead of having it spread over @@ -1378,6 +1378,10 @@ public class WindowManagerService extends IWindowManager.Stub mStartingSurfaceController = new StartingSurfaceController(this); } + DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() { + return mDisplayAreaPolicyProvider; + } + private void setGlobalShadowSettings() { final TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0); float lightY = a.getDimension(R.styleable.Lighting_lightY, 0); diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java new file mode 100644 index 000000000000..73e886f67cd3 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2020 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 com.android.server.wm; + +import static android.content.ActivityInfoProto.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.view.Surface.ROTATION_90; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; +import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; +import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; +import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.SizeCompatTests.prepareUnresizable; +import static com.android.server.wm.SizeCompatTests.rotateDisplay; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.content.res.Configuration; +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; +import android.view.Display; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tests for the Dual DisplayAreaGroup device behavior. + * + * Build/Install/Run: + * atest WmTests:DualDisplayAreaGroupPolicyTest + */ +@SmallTest +@Presubmit +@RunWith(WindowTestRunner.class) +public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { + private static final int FEATURE_FIRST_ROOT = FEATURE_VENDOR_FIRST; + private static final int FEATURE_FIRST_TASK_CONTAINER = FEATURE_DEFAULT_TASK_CONTAINER; + private static final int FEATURE_SECOND_ROOT = FEATURE_VENDOR_FIRST + 1; + private static final int FEATURE_SECOND_TASK_CONTAINER = FEATURE_VENDOR_FIRST + 2; + + private DualDisplayContent mDisplay; + private DisplayAreaGroup mFirstRoot; + private DisplayAreaGroup mSecondRoot; + private TaskDisplayArea mFirstTda; + private TaskDisplayArea mSecondTda; + private Task mFirstTask; + private Task mSecondTask; + private ActivityRecord mFirstActivity; + private ActivityRecord mSecondActivity; + + @Before + public void setUp() { + // Let the Display to be created with the DualDisplay policy. + final DisplayAreaPolicy.Provider policyProvider = new DualDisplayTestPolicyProvider(); + doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider(); + + // Display: 1920x1200 (landscape). First and second display are both 860x1200 (portrait). + mDisplay = (DualDisplayContent) new DualDisplayContent.Builder(mAtm, 1920, 1200).build(); + mFirstRoot = mDisplay.mFirstRoot; + mSecondRoot = mDisplay.mSecondRoot; + mFirstTda = mDisplay.getTaskDisplayArea(FEATURE_FIRST_TASK_CONTAINER); + mSecondTda = mDisplay.getTaskDisplayArea(FEATURE_SECOND_TASK_CONTAINER); + mFirstTask = new TaskBuilder(mSupervisor) + .setTaskDisplayArea(mFirstTda) + .setCreateActivity(true) + .build() + .getBottomMostTask(); + mSecondTask = new TaskBuilder(mSupervisor) + .setTaskDisplayArea(mSecondTda) + .setCreateActivity(true) + .build() + .getBottomMostTask(); + mFirstActivity = mFirstTask.getTopNonFinishingActivity(); + mSecondActivity = mSecondTask.getTopNonFinishingActivity(); + + spyOn(mDisplay); + spyOn(mFirstRoot); + spyOn(mSecondRoot); + } + + @Test + public void testNotIgnoreOrientationRequest_differentOrientationFromDisplay_reversesRequest() { + mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + mDisplay.setLastFocusedTaskDisplayArea(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE); + + assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT); + assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT); + + assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE); + assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT); + } + + @Test + public void testNotIgnoreOrientationRequest_onlyRespectsFocusedTaskDisplayArea() { + mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */); + mDisplay.setLastFocusedTaskDisplayArea(mFirstTda); + + // Second TDA is not focused, so Display won't get the request + prepareUnresizable(mSecondActivity, SCREEN_ORIENTATION_LANDSCAPE); + + assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED); + + // First TDA is focused, so Display gets the request + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE); + + assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT); + } + + @Test + public void testIgnoreOrientationRequest_displayDoesNotReceiveOrientationChange() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.setLastFocusedTaskDisplayArea(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE); + + verify(mFirstRoot).onDescendantOrientationChanged(any()); + verify(mDisplay, never()).onDescendantOrientationChanged(any()); + } + + @Test + public void testLaunchPortraitApp_fillsDisplayAreaGroup() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.setLastFocusedTaskDisplayArea(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT); + final Rect dagBounds = new Rect(mFirstRoot.getBounds()); + final Rect taskBounds = new Rect(mFirstTask.getBounds()); + final Rect activityBounds = new Rect(mFirstActivity.getBounds()); + + // DAG is portrait (860x1200), so Task and Activity fill DAG. + assertThat(mFirstTask.isTaskLetterboxed()).isFalse(); + assertThat(mFirstActivity.inSizeCompatMode()).isFalse(); + assertThat(taskBounds).isEqualTo(dagBounds); + assertThat(activityBounds).isEqualTo(taskBounds); + } + + @Test + public void testLaunchPortraitApp_sizeCompatAfterRotation() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.setLastFocusedTaskDisplayArea(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT); + final Rect dagBounds = new Rect(mFirstRoot.getBounds()); + final Rect activityBounds = new Rect(mFirstActivity.getBounds()); + + rotateDisplay(mDisplay, ROTATION_90); + final Rect newDagBounds = new Rect(mFirstRoot.getBounds()); + final Rect newTaskBounds = new Rect(mFirstTask.getBounds()); + final Rect activitySizeCompatBounds = new Rect(mFirstActivity.getBounds()); + final Rect activityConfigBounds = + new Rect(mFirstActivity.getConfiguration().windowConfiguration.getBounds()); + + // DAG is landscape (1200x860), Task fills parent + assertThat(mFirstTask.isTaskLetterboxed()).isFalse(); + assertThat(mFirstActivity.inSizeCompatMode()).isTrue(); + assertThat(newDagBounds.width()).isEqualTo(dagBounds.height()); + assertThat(newDagBounds.height()).isEqualTo(dagBounds.width()); + assertThat(newTaskBounds).isEqualTo(newDagBounds); + + // Activity config bounds is unchanged, size compat bounds is (860x[860x860/1200=616]) + assertThat(mFirstActivity.getSizeCompatScale()).isLessThan(1f); + assertThat(activityConfigBounds.width()).isEqualTo(activityBounds.width()); + assertThat(activityConfigBounds.height()).isEqualTo(activityBounds.height()); + assertThat(activitySizeCompatBounds.height()).isEqualTo(newTaskBounds.height()); + assertThat(activitySizeCompatBounds.width()).isEqualTo( + newTaskBounds.height() * newTaskBounds.height() / newTaskBounds.width()); + } + + @Test + public void testLaunchLandscapeApp_taskIsLetterboxInDisplayAreaGroup() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.setLastFocusedTaskDisplayArea(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE); + final Rect dagBounds = new Rect(mFirstRoot.getBounds()); + final Rect taskBounds = new Rect(mFirstTask.getBounds()); + final Rect activityBounds = new Rect(mFirstActivity.getBounds()); + + // DAG is portrait (860x1200), so Task is letterbox (860x[860x860/1200=616]) + assertThat(mFirstTask.isTaskLetterboxed()).isTrue(); + assertThat(mFirstActivity.inSizeCompatMode()).isFalse(); + assertThat(taskBounds.width()).isEqualTo(dagBounds.width()); + assertThat(taskBounds.height()) + .isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height()); + assertThat(activityBounds).isEqualTo(taskBounds); + } + + @Test + public void testLaunchLandscapeApp_taskLetterboxBecomesActivityLetterboxAfterRotation() { + mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mDisplay.setLastFocusedTaskDisplayArea(mFirstTda); + + prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE); + final Rect dagBounds = new Rect(mFirstRoot.getBounds()); + final Rect activityBounds = new Rect(mFirstActivity.getBounds()); + + rotateDisplay(mDisplay, ROTATION_90); + final Rect newDagBounds = new Rect(mFirstRoot.getBounds()); + final Rect newTaskBounds = new Rect(mFirstTask.getBounds()); + final Rect newActivityBounds = new Rect(mFirstActivity.getBounds()); + + // DAG is landscape (1200x860), Task fills parent + // Task letterbox size + assertThat(mFirstTask.isTaskLetterboxed()).isFalse(); + assertThat(mFirstActivity.inSizeCompatMode()).isTrue(); + assertThat(newDagBounds.width()).isEqualTo(dagBounds.height()); + assertThat(newDagBounds.height()).isEqualTo(dagBounds.width()); + assertThat(newTaskBounds).isEqualTo(newDagBounds); + + // Because we don't scale up, there is no size compat bounds and app bounds is the same as + // the previous bounds. + assertThat(mFirstActivity.hasSizeCompatBounds()).isFalse(); + assertThat(newActivityBounds.width()).isEqualTo(activityBounds.width()); + assertThat(newActivityBounds.height()).isEqualTo(activityBounds.height()); + } + + /** Display with two {@link DisplayAreaGroup}. Each of them take half of the screen. */ + private static class DualDisplayContent extends TestDisplayContent { + final DisplayAreaGroup mFirstRoot; + final DisplayAreaGroup mSecondRoot; + final Rect mLastDisplayBounds; + + /** Please use the {@link Builder} to create. */ + DualDisplayContent(RootWindowContainer rootWindowContainer, + Display display) { + super(rootWindowContainer, display); + + mFirstRoot = getGroupRoot(FEATURE_FIRST_ROOT); + mSecondRoot = getGroupRoot(FEATURE_SECOND_ROOT); + mLastDisplayBounds = new Rect(getBounds()); + updateDisplayAreaGroupBounds(); + } + + DisplayAreaGroup getGroupRoot(int rootFeatureId) { + DisplayArea da = getDisplayArea(rootFeatureId); + assertThat(da).isInstanceOf(DisplayAreaGroup.class); + return (DisplayAreaGroup) da; + } + + TaskDisplayArea getTaskDisplayArea(int tdaFeatureId) { + DisplayArea da = getDisplayArea(tdaFeatureId); + assertThat(da).isInstanceOf(TaskDisplayArea.class); + return (TaskDisplayArea) da; + } + + DisplayArea getDisplayArea(int featureId) { + final DisplayArea displayArea = + getItemFromDisplayAreas(da -> da.mFeatureId == featureId ? da : null); + assertThat(displayArea).isNotNull(); + return displayArea; + } + + @Override + public void onConfigurationChanged(Configuration newParentConfig) { + super.onConfigurationChanged(newParentConfig); + + final Rect curBounds = getBounds(); + if (mLastDisplayBounds != null && !mLastDisplayBounds.equals(curBounds)) { + mLastDisplayBounds.set(curBounds); + updateDisplayAreaGroupBounds(); + } + } + + /** Updates first and second {@link DisplayAreaGroup} to take half of the screen. */ + private void updateDisplayAreaGroupBounds() { + if (mFirstRoot == null || mSecondRoot == null) { + return; + } + + final Rect bounds = mLastDisplayBounds; + Rect groupBounds1, groupBounds2; + if (bounds.width() >= bounds.height()) { + groupBounds1 = new Rect(bounds.left, bounds.top, + (bounds.right + bounds.left) / 2, bounds.bottom); + + groupBounds2 = new Rect((bounds.right + bounds.left) / 2, bounds.top, + bounds.right, bounds.bottom); + } else { + groupBounds1 = new Rect(bounds.left, bounds.top, + bounds.right, (bounds.top + bounds.bottom) / 2); + + groupBounds2 = new Rect(bounds.left, + (bounds.top + bounds.bottom) / 2, bounds.right, bounds.bottom); + } + mFirstRoot.setBounds(groupBounds1); + mSecondRoot.setBounds(groupBounds2); + } + + static class Builder extends TestDisplayContent.Builder { + + Builder(ActivityTaskManagerService service, int width, int height) { + super(service, width, height); + } + + @Override + TestDisplayContent createInternal(Display display) { + return new DualDisplayContent(mService.mRootWindowContainer, display); + } + } + } + + /** Policy to create a dual {@link DisplayAreaGroup} policy in test. */ + private static class DualDisplayTestPolicyProvider implements DisplayAreaPolicy.Provider { + + @Override + public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content, + RootDisplayArea root, DisplayArea.Tokens imeContainer) { + // Root + // Include FEATURE_WINDOWED_MAGNIFICATION because it will be used as the screen rotation + // layer + DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy = + new DisplayAreaPolicyBuilder.HierarchyBuilder(root) + .setImeContainer(imeContainer) + .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder( + wmService.mPolicy, + "WindowedMagnification", FEATURE_WINDOWED_MAGNIFICATION) + .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) + .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) + .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new) + .build()); + + // First + final RootDisplayArea firstRoot = new DisplayAreaGroup(wmService, "FirstRoot", + FEATURE_FIRST_ROOT); + final TaskDisplayArea firstTaskDisplayArea = new TaskDisplayArea(content, wmService, + "FirstTaskDisplayArea", FEATURE_FIRST_TASK_CONTAINER); + final List<TaskDisplayArea> firstTdaList = new ArrayList<>(); + firstTdaList.add(firstTaskDisplayArea); + DisplayAreaPolicyBuilder.HierarchyBuilder firstHierarchy = + new DisplayAreaPolicyBuilder.HierarchyBuilder(firstRoot) + .setTaskDisplayAreas(firstTdaList); + + // Second + final RootDisplayArea secondRoot = new DisplayAreaGroup(wmService, "SecondRoot", + FEATURE_SECOND_ROOT); + final TaskDisplayArea secondTaskDisplayArea = new TaskDisplayArea(content, wmService, + "SecondTaskDisplayArea", FEATURE_SECOND_TASK_CONTAINER); + final List<TaskDisplayArea> secondTdaList = new ArrayList<>(); + secondTdaList.add(secondTaskDisplayArea); + DisplayAreaPolicyBuilder.HierarchyBuilder secondHierarchy = + new DisplayAreaPolicyBuilder.HierarchyBuilder(secondRoot) + .setTaskDisplayAreas(secondTdaList); + + return new DisplayAreaPolicyBuilder() + .setRootHierarchy(rootHierarchy) + .addDisplayAreaGroupHierarchy(firstHierarchy) + .addDisplayAreaGroupHierarchy(secondHierarchy) + .build(wmService); + } + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index da00198030e4..dd6e490b8282 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -92,7 +92,7 @@ public class SizeCompatTests extends WindowTestsBase { mActivity.mVisibleRequested = true; mActivity.setSavedState(null /* savedState */); mActivity.setState(Task.ActivityState.RESUMED, "testRestart"); - prepareUnresizable(1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); + prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); final Rect originalOverrideBounds = new Rect(mActivity.getBounds()); resizeDisplay(mTask.mDisplayContent, 600, 1200); @@ -115,7 +115,7 @@ public class SizeCompatTests extends WindowTestsBase { // Put app window into freeform and then make it a compat app. final Rect bounds = new Rect(100, 100, 400, 600); mTask.setBounds(bounds); - prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); assertEquals(bounds, mActivity.getBounds()); // The activity should be able to accept negative x position [-150, 100 - 150, 600]. @@ -145,7 +145,7 @@ public class SizeCompatTests extends WindowTestsBase { final Rect displayBounds = mActivity.mDisplayContent.getWindowConfiguration().getBounds(); final float aspectRatio = 1.2f; mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = aspectRatio; - prepareUnresizable(-1f, SCREEN_ORIENTATION_UNSPECIFIED); + prepareUnresizable(mActivity, -1f, SCREEN_ORIENTATION_UNSPECIFIED); final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds(); // The parent configuration doesn't change since the first resolved configuration, so the @@ -205,7 +205,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testFixedScreenBoundsWhenDisplaySizeChanged() { setUpDisplaySizeWithApp(1000, 2500); - prepareUnresizable(-1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); assertFitted(); final Rect origBounds = new Rect(mActivity.getBounds()); @@ -262,7 +262,7 @@ public class SizeCompatTests extends WindowTestsBase { setUpDisplaySizeWithApp(displayWidth, 1000); final float maxAspect = 1.5f; - prepareUnresizable(maxAspect, SCREEN_ORIENTATION_LANDSCAPE); + prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_LANDSCAPE); assertFitted(); final Rect bounds = mActivity.getBounds(); @@ -286,7 +286,7 @@ public class SizeCompatTests extends WindowTestsBase { public void testAspectRatioMatchParentBoundsAndImeAttachable() { setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2000) .setSystemDecorations(true).build()); - prepareUnresizable(2f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); + prepareUnresizable(mActivity, 2f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); assertFitted(); rotateDisplay(mActivity.mDisplayContent, ROTATION_90); @@ -307,7 +307,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testMoveToDifferentOrientDisplay() { setUpDisplaySizeWithApp(1000, 2500); - prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); assertFitted(); final Rect configBounds = mActivity.getWindowConfiguration().getBounds(); @@ -352,7 +352,7 @@ public class SizeCompatTests extends WindowTestsBase { setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2500) .setNotch(notchHeight).build()); // Bounds=[0, 0 - 1000, 1460], AppBounds=[0, 60 - 1000, 1460]. - prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, 1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); final Rect currentBounds = mActivity.getWindowConfiguration().getBounds(); final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds(); @@ -381,7 +381,7 @@ public class SizeCompatTests extends WindowTestsBase { setUpDisplaySizeWithApp(1000, 2500); final float maxAspect = 1.4f; - prepareUnresizable(maxAspect, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_PORTRAIT); // The display aspect ratio 2.5 > 1.4 (max of activity), so the size is fitted. assertFitted(); @@ -415,7 +415,7 @@ public class SizeCompatTests extends WindowTestsBase { Configuration c = new Configuration(mTask.getRequestedOverrideConfiguration()); c.screenLayout = fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR; mTask.onRequestedOverrideConfigurationChanged(c); - prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED); + prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_UNSPECIFIED); // The initial configuration should inherit from parent. assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR, @@ -433,7 +433,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testResetNonVisibleActivity() { setUpDisplaySizeWithApp(1000, 2500); - prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED); + prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_UNSPECIFIED); final DisplayContent display = mTask.mDisplayContent; // Resize the display so the activity is in size compatibility mode. resizeDisplay(display, 900, 1800); @@ -472,7 +472,7 @@ public class SizeCompatTests extends WindowTestsBase { setUpDisplaySizeWithApp(1000, 2000); ActivityRecord activity = mActivity; activity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatMode"); - prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); assertFitted(); final ArrayList<IBinder> compatTokens = new ArrayList<>(); @@ -545,7 +545,7 @@ public class SizeCompatTests extends WindowTestsBase { mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN); mActivity.mDisplayContent.mOpeningApps.add(mActivity); final float maxAspect = 1.8f; - prepareUnresizable(maxAspect, SCREEN_ORIENTATION_LANDSCAPE); + prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_LANDSCAPE); assertFitted(); assertTrue(mActivity.isFixedRotationTransforming()); @@ -576,7 +576,7 @@ public class SizeCompatTests extends WindowTestsBase { assertFalse(statusBarController.isTransparentAllowed(w)); // Make the activity fill the display. - prepareUnresizable(10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE); + prepareUnresizable(mActivity, 10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE); w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; // Refresh the letterbox. mActivity.mRootWindowContainer.performSurfacePlacement(); @@ -593,11 +593,11 @@ public class SizeCompatTests extends WindowTestsBase { mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app without max aspect. - prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); - final Rect displayBounds = mActivity.mDisplayContent.getBounds(); - final Rect taskBounds = mTask.getBounds(); - final Rect activityBounds = mActivity.getBounds(); + final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); + final Rect taskBounds = new Rect(mTask.getBounds()); + final Rect activityBounds = new Rect(mActivity.getBounds()); // Display shouldn't be rotated. assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, @@ -622,15 +622,15 @@ public class SizeCompatTests extends WindowTestsBase { mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app without max aspect. - prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); - final Rect activityBounds = mActivity.getBounds(); + final Rect activityBounds = new Rect(mActivity.getBounds()); // Rotate display to portrait. rotateDisplay(mActivity.mDisplayContent, ROTATION_90); - final Rect displayBounds = mActivity.mDisplayContent.getBounds(); - final Rect newActivityBounds = mActivity.getBounds(); + final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); + final Rect newActivityBounds = new Rect(mActivity.getBounds()); assertTrue(displayBounds.width() < displayBounds.height()); // App should be in size compat. @@ -647,10 +647,10 @@ public class SizeCompatTests extends WindowTestsBase { mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app without max aspect. - prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); - Rect displayBounds = mActivity.mDisplayContent.getBounds(); - Rect activityBounds = mActivity.getBounds(); + Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); + Rect activityBounds = new Rect(mActivity.getBounds()); // App should launch in fullscreen. assertFalse(mTask.isTaskLetterboxed()); @@ -660,8 +660,8 @@ public class SizeCompatTests extends WindowTestsBase { // Rotate display to landscape. rotateDisplay(mActivity.mDisplayContent, ROTATION_90); - displayBounds = mActivity.mDisplayContent.getBounds(); - activityBounds = mActivity.getBounds(); + displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); + activityBounds = new Rect(mActivity.getBounds()); assertTrue(displayBounds.width() > displayBounds.height()); // App should be in size compat. @@ -682,7 +682,7 @@ public class SizeCompatTests extends WindowTestsBase { display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app without max aspect. - prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); assertTrue(mTask.isTaskLetterboxed()); assertFalse(mActivity.inSizeCompatMode()); @@ -701,9 +701,9 @@ public class SizeCompatTests extends WindowTestsBase { verify(mTask).onDescendantOrientationChanged(same(newActivity)); verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt()); - final Rect displayBounds = display.getBounds(); - final Rect taskBounds = mTask.getBounds(); - final Rect newActivityBounds = newActivity.getBounds(); + final Rect displayBounds = new Rect(display.getBounds()); + final Rect taskBounds = new Rect(mTask.getBounds()); + final Rect newActivityBounds = new Rect(newActivity.getBounds()); // Task and app bounds should be 700x1400 with the ratio as the display. assertTrue(mTask.isTaskLetterboxed()); @@ -722,7 +722,7 @@ public class SizeCompatTests extends WindowTestsBase { display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app without max aspect. - prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); assertTrue(mTask.isTaskLetterboxed()); assertFalse(mActivity.inSizeCompatMode()); @@ -742,9 +742,9 @@ public class SizeCompatTests extends WindowTestsBase { verify(mTask).onDescendantOrientationChanged(same(newActivity)); verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt()); - final Rect displayBounds = display.getBounds(); - final Rect taskBounds = mTask.getBounds(); - final Rect newActivityBounds = newActivity.getBounds(); + final Rect displayBounds = new Rect(display.getBounds()); + final Rect taskBounds = new Rect(mTask.getBounds()); + final Rect newActivityBounds = new Rect(newActivity.getBounds()); // Task bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio. assertTrue(mTask.isTaskLetterboxed()); @@ -765,7 +765,7 @@ public class SizeCompatTests extends WindowTestsBase { display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app. - prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT); + prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); clearInvocations(mActivity); assertTrue(mTask.isTaskLetterboxed()); @@ -829,26 +829,31 @@ public class SizeCompatTests extends WindowTestsBase { displayContent.getConfiguration().uiMode); } + static void prepareUnresizable(ActivityRecord activity, int screenOrientation) { + prepareUnresizable(activity, -1 /* maxAspect */, screenOrientation); + } + /** - * Setup {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or + * Setups {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or * orientation. */ - private void prepareUnresizable(float maxAspect, int screenOrientation) { - mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; - mActivity.mVisibleRequested = true; + static void prepareUnresizable(ActivityRecord activity, float maxAspect, + int screenOrientation) { + activity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; + activity.mVisibleRequested = true; if (maxAspect >= 0) { - mActivity.info.maxAspectRatio = maxAspect; + activity.info.maxAspectRatio = maxAspect; } if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { - mActivity.info.screenOrientation = screenOrientation; - mActivity.setRequestedOrientation(screenOrientation); + activity.info.screenOrientation = screenOrientation; + activity.setRequestedOrientation(screenOrientation); } // Make sure to use the provided configuration to construct the size compat fields. - mActivity.clearSizeCompatMode(); - mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); + activity.clearSizeCompatMode(); + activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); // Make sure the display configuration reflects the change of activity. - if (mActivity.mDisplayContent.updateOrientation()) { - mActivity.mDisplayContent.sendNewConfiguration(); + if (activity.mDisplayContent.updateOrientation()) { + activity.mDisplayContent.sendNewConfiguration(); } } @@ -869,7 +874,7 @@ public class SizeCompatTests extends WindowTestsBase { assertFalse(mActivity.hasSizeCompatBounds()); } - private static Configuration rotateDisplay(DisplayContent display, int rotation) { + static Configuration rotateDisplay(DisplayContent display, int rotation) { final Configuration c = new Configuration(); display.getDisplayRotation().setRotation(rotation); display.computeScreenConfiguration(c); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java index e95efe785e8c..b1065914a925 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -37,7 +37,8 @@ import android.view.DisplayInfo; class TestDisplayContent extends DisplayContent { - private TestDisplayContent(RootWindowContainer rootWindowContainer, Display display) { + /** Please use the {@link Builder} to create, visible for use in test builder overrides only. */ + TestDisplayContent(RootWindowContainer rootWindowContainer, Display display) { super(display, rootWindowContainer); // Normally this comes from display-properties as exposed by WM. Without that, just // hard-code to FULLSCREEN for tests. @@ -72,7 +73,7 @@ class TestDisplayContent extends DisplayContent { private boolean mCanRotate = true; private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; private int mPosition = POSITION_BOTTOM; - private final ActivityTaskManagerService mService; + protected final ActivityTaskManagerService mService; private boolean mSystemDecorations = false; Builder(ActivityTaskManagerService service, int width, int height) { @@ -125,14 +126,16 @@ class TestDisplayContent extends DisplayContent { mInfo.logicalDensityDpi = dpi; return this; } + TestDisplayContent createInternal(Display display) { + return new TestDisplayContent(mService.mRootWindowContainer, display); + } TestDisplayContent build() { SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock); final int displayId = SystemServicesTestRule.sNextDisplayId++; final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, mInfo, DEFAULT_DISPLAY_ADJUSTMENTS); - final TestDisplayContent newDisplay = - new TestDisplayContent(mService.mRootWindowContainer, display); + final TestDisplayContent newDisplay = createInternal(display); // disable the normal system decorations final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy(); spyOn(displayPolicy); |