Loading core/java/android/content/pm/ActivityInfo.java +9 −1 Original line number Diff line number Diff line Loading @@ -1028,11 +1028,19 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { } } /** * Returns true if the activity has maximum or minimum aspect ratio. * @hide */ public boolean hasFixedAspectRatio() { return maxAspectRatio != 0 || minAspectRatio != 0; } /** * Returns true if the activity's orientation is fixed. * @hide */ boolean isFixedOrientation() { public boolean isFixedOrientation() { return isFixedOrientationLandscape() || isFixedOrientationPortrait() || screenOrientation == SCREEN_ORIENTATION_LOCKED; } Loading services/core/java/com/android/server/wm/ActivityRecord.java +160 −33 Original line number Diff line number Diff line Loading @@ -75,12 +75,12 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; import static android.content.res.Configuration.EMPTY; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET; import static android.os.Build.VERSION_CODES.HONEYCOMB; Loading Loading @@ -2610,10 +2610,6 @@ final class ActivityRecord extends ConfigurationContainer { } } int getRequestedOrientation() { return getOrientation(); } void setRequestedOrientation(int requestedOrientation) { setOrientation(requestedOrientation, mayFreezeScreenLocked(app)); mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( Loading Loading @@ -2641,7 +2637,7 @@ final class ActivityRecord extends ConfigurationContainer { int getOrientation() { if (mAppWindowToken == null) { return SCREEN_ORIENTATION_UNSPECIFIED; return info.screenOrientation; } return mAppWindowToken.getOrientationIgnoreVisibility(); Loading Loading @@ -2677,25 +2673,92 @@ final class ActivityRecord extends ConfigurationContainer { mLastReportedConfiguration.setConfiguration(global, override); } /** * Get the configuration orientation by the requested screen orientation * ({@link ActivityInfo.ScreenOrientation}) of this activity. * * @return orientation in ({@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}, * {@link #ORIENTATION_UNDEFINED}). */ int getRequestedConfigurationOrientation() { final int screenOrientation = getOrientation(); if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { // NOSENSOR means the display's "natural" orientation, so return that. final ActivityDisplay display = getDisplay(); if (display != null && display.mDisplayContent != null) { return display.mDisplayContent.getNaturalOrientation(); } } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { // LOCKED means the activity's orientation remains unchanged, so return existing value. return getConfiguration().orientation; } else if (isFixedOrientationLandscape(screenOrientation)) { return ORIENTATION_LANDSCAPE; } else if (isFixedOrientationPortrait(screenOrientation)) { return ORIENTATION_PORTRAIT; } return ORIENTATION_UNDEFINED; } /** * Indicates the activity will keep the bounds and screen configuration when it was first * launched, no matter how its parent changes. * * @return {@code true} if this activity is declared as non-resizable and fixed orientation or * aspect ratio. */ private boolean inSizeCompatMode() { return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio()) // The configuration of non-standard type should be enforced by system. && isActivityTypeStandard() && !mAtmService.mForceResizableActivities; } // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. private void updateOverrideConfiguration() { final boolean inSizeCompatMode = inSizeCompatMode(); if (inSizeCompatMode) { if (!matchParentBounds()) { // The override configuration is set only once in size compatible mode. return; } if (!hasProcess() && !isConfigurationCompatible(task.getConfiguration())) { // Don't compute when launching in fullscreen and the fixed orientation is not the // current orientation. It is more accurately to compute the override bounds from // the updated configuration after the fixed orientation is applied. return; } } computeBounds(mTmpBounds); if (inSizeCompatMode && mTmpBounds.isEmpty()) { mTmpBounds.set(task.getWindowConfiguration().getBounds()); } if (mTmpBounds.equals(getRequestedOverrideBounds())) { // The bounds is not changed or the activity is resizable (both the 2 bounds are empty). return; } setBounds(mTmpBounds); // Bounds changed...update configuration to match. if (!matchParentBounds()) { mTmpConfig.setTo(getRequestedOverrideConfiguration()); task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration()); } else { mTmpConfig.unset(); final Configuration overrideConfig = mTmpConfig; overrideConfig.unset(); if (!mTmpBounds.isEmpty()) { overrideConfig.windowConfiguration.setBounds(mTmpBounds); if (inSizeCompatMode) { // Ensure the screen related fields are set. It is used to prevent activity relaunch // when moving between displays. For screenWidthDp and screenWidthDp, because they // are relative to bounds and density, they will be calculated in // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be // relatively fixed. final Configuration srcConfig = task.getConfiguration(); overrideConfig.colorMode = srcConfig.colorMode; overrideConfig.densityDpi = srcConfig.densityDpi; overrideConfig.screenLayout = srcConfig.screenLayout; // The smallest screen width is the short side of screen bounds. Because the bounds // and density won't be changed, smallestScreenWidthDp is also fixed. overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp; } onRequestedOverrideConfigurationChanged(mTmpConfig); } onRequestedOverrideConfigurationChanged(overrideConfig); } @Override Loading @@ -2707,6 +2770,86 @@ final class ActivityRecord extends ConfigurationContainer { // layout traversals. mConfigurationSeq = Math.max(++mConfigurationSeq, 1); getResolvedOverrideConfiguration().seq = mConfigurationSeq; if (matchParentBounds()) { return; } final Configuration resolvedConfig = getResolvedOverrideConfiguration(); if (!inSizeCompatMode()) { computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, ORIENTATION_UNDEFINED, true /* insideParentBounds */); return; } final Configuration displayConfig = getDisplay().getConfiguration(); int orientation = getConfiguration().orientation; if (orientation != displayConfig.orientation && isConfigurationCompatible(displayConfig)) { // The activity is compatible to apply the orientation change or it requests different // fixed orientation. orientation = displayConfig.orientation; } else { if (resolvedConfig.windowConfiguration.getAppBounds() != null) { // Keep the computed resolved override configuration. return; } final int requestedOrientation = getRequestedConfigurationOrientation(); if (requestedOrientation != ORIENTATION_UNDEFINED) { orientation = requestedOrientation; } } // Adjust the bounds to match the current orientation. if (orientation != ORIENTATION_UNDEFINED) { final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); final int longSide = Math.max(resolvedBounds.height(), resolvedBounds.width()); final int shortSide = Math.min(resolvedBounds.height(), resolvedBounds.width()); final boolean toBeLandscape = orientation == ORIENTATION_LANDSCAPE; final int width = toBeLandscape ? longSide : shortSide; final int height = toBeLandscape ? shortSide : longSide; // Assume the bounds is always started from zero because the size may be bigger than its // parent (task ~ display). The actual letterboxing will be done by surface offset. resolvedBounds.set(0, 0, width, height); } // In size compatible mode, activity is allowed to have larger bounds than its parent. computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, orientation, false /* insideParentBounds */); } private void computeConfigResourceOverrides(Configuration inOutConfig, Configuration parentConfig, int orientation, boolean insideParentBounds) { // Set the real orientation or undefined value to ensure the output orientation won't be the // old value. Also reset app bounds so it will be updated according to bounds. inOutConfig.orientation = orientation; final Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); if (outAppBounds != null) { outAppBounds.setEmpty(); } // TODO(b/112288258): Remove below calculation because the position information in bounds // will be replaced by the offset of surface. final Rect appBounds = parentConfig.windowConfiguration.getAppBounds(); if (appBounds != null) { final Rect outBounds = inOutConfig.windowConfiguration.getBounds(); final int activityWidth = outBounds.width(); final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId()); if (navBarPosition == NAV_BAR_LEFT) { // Position the activity frame on the opposite side of the nav bar. outBounds.left = appBounds.right - activityWidth; outBounds.right = appBounds.right; } else if (navBarPosition == NAV_BAR_RIGHT) { // Position the activity frame on the opposite side of the nav bar. outBounds.left = 0; outBounds.right = activityWidth + appBounds.left; } else if (appBounds.width() > activityWidth) { // Horizontally center the frame. outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2; outBounds.right = outBounds.left + activityWidth; } } task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds); } @Override Loading Loading @@ -2739,8 +2882,7 @@ final class ActivityRecord extends ConfigurationContainer { /** Returns true if the configuration is compatible with this activity. */ boolean isConfigurationCompatible(Configuration config) { final int orientation = mAppWindowToken != null ? getOrientation() : info.screenOrientation; final int orientation = getOrientation(); if (isFixedOrientationPortrait(orientation) && config.orientation != ORIENTATION_PORTRAIT) { return false; Loading Loading @@ -2822,21 +2964,6 @@ final class ActivityRecord extends ConfigurationContainer { // away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app // bounds would end up too small. outBounds.set(0, 0, activityWidth + appBounds.left, activityHeight + appBounds.top); final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId()); if (navBarPosition == NAV_BAR_LEFT) { // Position the activity frame on the opposite side of the nav bar. outBounds.left = appBounds.right - activityWidth; outBounds.right = appBounds.right; } else if (navBarPosition == NAV_BAR_RIGHT) { // Position the activity frame on the opposite side of the nav bar. outBounds.left = 0; outBounds.right = activityWidth + appBounds.left; } else { // Horizontally center the frame. outBounds.left = appBounds.left + (containingAppWidth - activityWidth) / 2; outBounds.right = outBounds.left + activityWidth; } } /** Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -1720,7 +1720,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (r == null) { return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } return r.getRequestedOrientation(); return r.getOrientation(); } } Loading services/core/java/com/android/server/wm/TaskRecord.java +18 −24 Original line number Diff line number Diff line Loading @@ -1289,22 +1289,7 @@ class TaskRecord extends ConfigurationContainer { || top == null) { return getRequestedOverrideConfiguration().orientation; } int screenOrientation = top.getOrientation(); if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { // NOSENSOR means the display's "natural" orientation, so return that. ActivityDisplay display = mStack != null ? mStack.getDisplay() : null; if (display != null && display.mDisplayContent != null) { return mStack.getDisplay().mDisplayContent.getNaturalOrientation(); } } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { // LOCKED means the activity's orientation remains unchanged, so return existing value. return top.getConfiguration().orientation; } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { return ORIENTATION_LANDSCAPE; } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { return ORIENTATION_PORTRAIT; } return ORIENTATION_UNDEFINED; return top.getRequestedConfigurationOrientation(); } /** Loading Loading @@ -2085,6 +2070,11 @@ class TaskRecord extends ConfigurationContainer { return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; } void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Configuration parentConfig) { computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */); } /** * Calculates configuration values used by the client to get resources. This should be run * using app-facing bounds (bounds unmodified by animations or transient interactions). Loading @@ -2094,7 +2084,7 @@ class TaskRecord extends ConfigurationContainer { * just be inherited from the parent configuration. **/ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Configuration parentConfig) { @NonNull Configuration parentConfig, boolean insideParentBounds) { int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); if (windowingMode == WINDOWING_MODE_UNDEFINED) { windowingMode = parentConfig.windowConfiguration.getWindowingMode(); Loading @@ -2112,7 +2102,7 @@ class TaskRecord extends ConfigurationContainer { inOutConfig.windowConfiguration.setAppBounds(bounds); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); } if (windowingMode != WINDOWING_MODE_FREEFORM) { if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) { final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); if (parentAppBounds != null && !parentAppBounds.isEmpty()) { outAppBounds.intersect(parentAppBounds); Loading @@ -2121,7 +2111,7 @@ class TaskRecord extends ConfigurationContainer { if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { if (mStack != null) { if (insideParentBounds && mStack != null) { final DisplayInfo di = new DisplayInfo(); mStack.getDisplay().mDisplay.getDisplayInfo(di); Loading @@ -2136,12 +2126,16 @@ class TaskRecord extends ConfigurationContainer { } if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { inOutConfig.screenWidthDp = Math.min((int) (mTmpStableBounds.width() / density), parentConfig.screenWidthDp); final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density); inOutConfig.screenWidthDp = insideParentBounds ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp) : overrideScreenWidthDp; } if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { inOutConfig.screenHeightDp = Math.min((int) (mTmpStableBounds.height() / density), parentConfig.screenHeightDp); final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density); inOutConfig.screenHeightDp = insideParentBounds ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp) : overrideScreenHeightDp; } if (inOutConfig.smallestScreenWidthDp Loading @@ -2163,7 +2157,7 @@ class TaskRecord extends ConfigurationContainer { if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; } if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) { // For calculating screen layout, we need to use the non-decor inset screen area for the Loading services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +50 −5 Original line number Diff line number Diff line Loading @@ -183,11 +183,14 @@ public class ActivityRecordTests extends ActivityTestsBase { .thenReturn(navBarPosition); mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds); mActivity.info.maxAspectRatio = aspectRatio; mActivity.ensureActivityConfiguration( 0 /* globalChanges */, false /* preserveWindow */); ensureActivityConfiguration(); assertEquals(expectedActivityBounds, mActivity.getBounds()); } private void ensureActivityConfiguration() { mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); } @Test public void testCanBeLaunchedOnDisplay() { mService.mSupportsMultiWindow = true; Loading Loading @@ -281,7 +284,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; mActivity.ensureActivityConfiguration(0, false, false); ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE, mActivity.mRelaunchReason); Loading @@ -305,7 +308,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; mActivity.ensureActivityConfiguration(0, false, false); ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE, mActivity.mRelaunchReason); Loading @@ -327,7 +330,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; mActivity.ensureActivityConfiguration(0, false, false); ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE, mActivity.mRelaunchReason); Loading Loading @@ -433,4 +436,46 @@ public class ActivityRecordTests extends ActivityTestsBase { stack.getDisplay().removeChild(stack); } } @Test public void testFixedScreenConfigurationWhenMovingToDisplay() { // Initialize different bounds on a new display. final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); newDisplay.setBounds(0, 0, 1000, 2000); newDisplay.getConfiguration().densityDpi = 300; mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); mTask.getConfiguration().densityDpi = 200; when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; mActivity.info.maxAspectRatio = 1.5f; ensureActivityConfiguration(); final Rect originalBounds = new Rect(mActivity.getBounds()); final int originalDpi = mActivity.getConfiguration().densityDpi; // Move the non-resizable activity to the new display. mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */); ensureActivityConfiguration(); assertEquals(originalBounds, mActivity.getBounds()); assertEquals(originalDpi, mActivity.getConfiguration().densityDpi); } @Test public void testFixedScreenBoundsWhenDisplaySizeChanged() { when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; ensureActivityConfiguration(); final Rect originalBounds = new Rect(mActivity.getBounds()); // Change the size of current display. mStack.getDisplay().setBounds(0, 0, 1000, 2000); ensureActivityConfiguration(); assertEquals(originalBounds, mActivity.getBounds()); } } Loading
core/java/android/content/pm/ActivityInfo.java +9 −1 Original line number Diff line number Diff line Loading @@ -1028,11 +1028,19 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { } } /** * Returns true if the activity has maximum or minimum aspect ratio. * @hide */ public boolean hasFixedAspectRatio() { return maxAspectRatio != 0 || minAspectRatio != 0; } /** * Returns true if the activity's orientation is fixed. * @hide */ boolean isFixedOrientation() { public boolean isFixedOrientation() { return isFixedOrientationLandscape() || isFixedOrientationPortrait() || screenOrientation == SCREEN_ORIENTATION_LOCKED; } Loading
services/core/java/com/android/server/wm/ActivityRecord.java +160 −33 Original line number Diff line number Diff line Loading @@ -75,12 +75,12 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; import static android.content.res.Configuration.EMPTY; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET; import static android.os.Build.VERSION_CODES.HONEYCOMB; Loading Loading @@ -2610,10 +2610,6 @@ final class ActivityRecord extends ConfigurationContainer { } } int getRequestedOrientation() { return getOrientation(); } void setRequestedOrientation(int requestedOrientation) { setOrientation(requestedOrientation, mayFreezeScreenLocked(app)); mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( Loading Loading @@ -2641,7 +2637,7 @@ final class ActivityRecord extends ConfigurationContainer { int getOrientation() { if (mAppWindowToken == null) { return SCREEN_ORIENTATION_UNSPECIFIED; return info.screenOrientation; } return mAppWindowToken.getOrientationIgnoreVisibility(); Loading Loading @@ -2677,25 +2673,92 @@ final class ActivityRecord extends ConfigurationContainer { mLastReportedConfiguration.setConfiguration(global, override); } /** * Get the configuration orientation by the requested screen orientation * ({@link ActivityInfo.ScreenOrientation}) of this activity. * * @return orientation in ({@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}, * {@link #ORIENTATION_UNDEFINED}). */ int getRequestedConfigurationOrientation() { final int screenOrientation = getOrientation(); if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { // NOSENSOR means the display's "natural" orientation, so return that. final ActivityDisplay display = getDisplay(); if (display != null && display.mDisplayContent != null) { return display.mDisplayContent.getNaturalOrientation(); } } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { // LOCKED means the activity's orientation remains unchanged, so return existing value. return getConfiguration().orientation; } else if (isFixedOrientationLandscape(screenOrientation)) { return ORIENTATION_LANDSCAPE; } else if (isFixedOrientationPortrait(screenOrientation)) { return ORIENTATION_PORTRAIT; } return ORIENTATION_UNDEFINED; } /** * Indicates the activity will keep the bounds and screen configuration when it was first * launched, no matter how its parent changes. * * @return {@code true} if this activity is declared as non-resizable and fixed orientation or * aspect ratio. */ private boolean inSizeCompatMode() { return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio()) // The configuration of non-standard type should be enforced by system. && isActivityTypeStandard() && !mAtmService.mForceResizableActivities; } // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. private void updateOverrideConfiguration() { final boolean inSizeCompatMode = inSizeCompatMode(); if (inSizeCompatMode) { if (!matchParentBounds()) { // The override configuration is set only once in size compatible mode. return; } if (!hasProcess() && !isConfigurationCompatible(task.getConfiguration())) { // Don't compute when launching in fullscreen and the fixed orientation is not the // current orientation. It is more accurately to compute the override bounds from // the updated configuration after the fixed orientation is applied. return; } } computeBounds(mTmpBounds); if (inSizeCompatMode && mTmpBounds.isEmpty()) { mTmpBounds.set(task.getWindowConfiguration().getBounds()); } if (mTmpBounds.equals(getRequestedOverrideBounds())) { // The bounds is not changed or the activity is resizable (both the 2 bounds are empty). return; } setBounds(mTmpBounds); // Bounds changed...update configuration to match. if (!matchParentBounds()) { mTmpConfig.setTo(getRequestedOverrideConfiguration()); task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration()); } else { mTmpConfig.unset(); final Configuration overrideConfig = mTmpConfig; overrideConfig.unset(); if (!mTmpBounds.isEmpty()) { overrideConfig.windowConfiguration.setBounds(mTmpBounds); if (inSizeCompatMode) { // Ensure the screen related fields are set. It is used to prevent activity relaunch // when moving between displays. For screenWidthDp and screenWidthDp, because they // are relative to bounds and density, they will be calculated in // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be // relatively fixed. final Configuration srcConfig = task.getConfiguration(); overrideConfig.colorMode = srcConfig.colorMode; overrideConfig.densityDpi = srcConfig.densityDpi; overrideConfig.screenLayout = srcConfig.screenLayout; // The smallest screen width is the short side of screen bounds. Because the bounds // and density won't be changed, smallestScreenWidthDp is also fixed. overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp; } onRequestedOverrideConfigurationChanged(mTmpConfig); } onRequestedOverrideConfigurationChanged(overrideConfig); } @Override Loading @@ -2707,6 +2770,86 @@ final class ActivityRecord extends ConfigurationContainer { // layout traversals. mConfigurationSeq = Math.max(++mConfigurationSeq, 1); getResolvedOverrideConfiguration().seq = mConfigurationSeq; if (matchParentBounds()) { return; } final Configuration resolvedConfig = getResolvedOverrideConfiguration(); if (!inSizeCompatMode()) { computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, ORIENTATION_UNDEFINED, true /* insideParentBounds */); return; } final Configuration displayConfig = getDisplay().getConfiguration(); int orientation = getConfiguration().orientation; if (orientation != displayConfig.orientation && isConfigurationCompatible(displayConfig)) { // The activity is compatible to apply the orientation change or it requests different // fixed orientation. orientation = displayConfig.orientation; } else { if (resolvedConfig.windowConfiguration.getAppBounds() != null) { // Keep the computed resolved override configuration. return; } final int requestedOrientation = getRequestedConfigurationOrientation(); if (requestedOrientation != ORIENTATION_UNDEFINED) { orientation = requestedOrientation; } } // Adjust the bounds to match the current orientation. if (orientation != ORIENTATION_UNDEFINED) { final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); final int longSide = Math.max(resolvedBounds.height(), resolvedBounds.width()); final int shortSide = Math.min(resolvedBounds.height(), resolvedBounds.width()); final boolean toBeLandscape = orientation == ORIENTATION_LANDSCAPE; final int width = toBeLandscape ? longSide : shortSide; final int height = toBeLandscape ? shortSide : longSide; // Assume the bounds is always started from zero because the size may be bigger than its // parent (task ~ display). The actual letterboxing will be done by surface offset. resolvedBounds.set(0, 0, width, height); } // In size compatible mode, activity is allowed to have larger bounds than its parent. computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, orientation, false /* insideParentBounds */); } private void computeConfigResourceOverrides(Configuration inOutConfig, Configuration parentConfig, int orientation, boolean insideParentBounds) { // Set the real orientation or undefined value to ensure the output orientation won't be the // old value. Also reset app bounds so it will be updated according to bounds. inOutConfig.orientation = orientation; final Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); if (outAppBounds != null) { outAppBounds.setEmpty(); } // TODO(b/112288258): Remove below calculation because the position information in bounds // will be replaced by the offset of surface. final Rect appBounds = parentConfig.windowConfiguration.getAppBounds(); if (appBounds != null) { final Rect outBounds = inOutConfig.windowConfiguration.getBounds(); final int activityWidth = outBounds.width(); final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId()); if (navBarPosition == NAV_BAR_LEFT) { // Position the activity frame on the opposite side of the nav bar. outBounds.left = appBounds.right - activityWidth; outBounds.right = appBounds.right; } else if (navBarPosition == NAV_BAR_RIGHT) { // Position the activity frame on the opposite side of the nav bar. outBounds.left = 0; outBounds.right = activityWidth + appBounds.left; } else if (appBounds.width() > activityWidth) { // Horizontally center the frame. outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2; outBounds.right = outBounds.left + activityWidth; } } task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds); } @Override Loading Loading @@ -2739,8 +2882,7 @@ final class ActivityRecord extends ConfigurationContainer { /** Returns true if the configuration is compatible with this activity. */ boolean isConfigurationCompatible(Configuration config) { final int orientation = mAppWindowToken != null ? getOrientation() : info.screenOrientation; final int orientation = getOrientation(); if (isFixedOrientationPortrait(orientation) && config.orientation != ORIENTATION_PORTRAIT) { return false; Loading Loading @@ -2822,21 +2964,6 @@ final class ActivityRecord extends ConfigurationContainer { // away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app // bounds would end up too small. outBounds.set(0, 0, activityWidth + appBounds.left, activityHeight + appBounds.top); final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId()); if (navBarPosition == NAV_BAR_LEFT) { // Position the activity frame on the opposite side of the nav bar. outBounds.left = appBounds.right - activityWidth; outBounds.right = appBounds.right; } else if (navBarPosition == NAV_BAR_RIGHT) { // Position the activity frame on the opposite side of the nav bar. outBounds.left = 0; outBounds.right = activityWidth + appBounds.left; } else { // Horizontally center the frame. outBounds.left = appBounds.left + (containingAppWidth - activityWidth) / 2; outBounds.right = outBounds.left + activityWidth; } } /** Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +1 −1 Original line number Diff line number Diff line Loading @@ -1720,7 +1720,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (r == null) { return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } return r.getRequestedOrientation(); return r.getOrientation(); } } Loading
services/core/java/com/android/server/wm/TaskRecord.java +18 −24 Original line number Diff line number Diff line Loading @@ -1289,22 +1289,7 @@ class TaskRecord extends ConfigurationContainer { || top == null) { return getRequestedOverrideConfiguration().orientation; } int screenOrientation = top.getOrientation(); if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { // NOSENSOR means the display's "natural" orientation, so return that. ActivityDisplay display = mStack != null ? mStack.getDisplay() : null; if (display != null && display.mDisplayContent != null) { return mStack.getDisplay().mDisplayContent.getNaturalOrientation(); } } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { // LOCKED means the activity's orientation remains unchanged, so return existing value. return top.getConfiguration().orientation; } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { return ORIENTATION_LANDSCAPE; } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { return ORIENTATION_PORTRAIT; } return ORIENTATION_UNDEFINED; return top.getRequestedConfigurationOrientation(); } /** Loading Loading @@ -2085,6 +2070,11 @@ class TaskRecord extends ConfigurationContainer { return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; } void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Configuration parentConfig) { computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */); } /** * Calculates configuration values used by the client to get resources. This should be run * using app-facing bounds (bounds unmodified by animations or transient interactions). Loading @@ -2094,7 +2084,7 @@ class TaskRecord extends ConfigurationContainer { * just be inherited from the parent configuration. **/ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Configuration parentConfig) { @NonNull Configuration parentConfig, boolean insideParentBounds) { int windowingMode = inOutConfig.windowConfiguration.getWindowingMode(); if (windowingMode == WINDOWING_MODE_UNDEFINED) { windowingMode = parentConfig.windowConfiguration.getWindowingMode(); Loading @@ -2112,7 +2102,7 @@ class TaskRecord extends ConfigurationContainer { inOutConfig.windowConfiguration.setAppBounds(bounds); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); } if (windowingMode != WINDOWING_MODE_FREEFORM) { if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) { final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); if (parentAppBounds != null && !parentAppBounds.isEmpty()) { outAppBounds.intersect(parentAppBounds); Loading @@ -2121,7 +2111,7 @@ class TaskRecord extends ConfigurationContainer { if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { if (mStack != null) { if (insideParentBounds && mStack != null) { final DisplayInfo di = new DisplayInfo(); mStack.getDisplay().mDisplay.getDisplayInfo(di); Loading @@ -2136,12 +2126,16 @@ class TaskRecord extends ConfigurationContainer { } if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { inOutConfig.screenWidthDp = Math.min((int) (mTmpStableBounds.width() / density), parentConfig.screenWidthDp); final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density); inOutConfig.screenWidthDp = insideParentBounds ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp) : overrideScreenWidthDp; } if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { inOutConfig.screenHeightDp = Math.min((int) (mTmpStableBounds.height() / density), parentConfig.screenHeightDp); final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density); inOutConfig.screenHeightDp = insideParentBounds ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp) : overrideScreenHeightDp; } if (inOutConfig.smallestScreenWidthDp Loading @@ -2163,7 +2157,7 @@ class TaskRecord extends ConfigurationContainer { if (inOutConfig.orientation == ORIENTATION_UNDEFINED) { inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp) ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; } if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) { // For calculating screen layout, we need to use the non-decor inset screen area for the Loading
services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +50 −5 Original line number Diff line number Diff line Loading @@ -183,11 +183,14 @@ public class ActivityRecordTests extends ActivityTestsBase { .thenReturn(navBarPosition); mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds); mActivity.info.maxAspectRatio = aspectRatio; mActivity.ensureActivityConfiguration( 0 /* globalChanges */, false /* preserveWindow */); ensureActivityConfiguration(); assertEquals(expectedActivityBounds, mActivity.getBounds()); } private void ensureActivityConfiguration() { mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); } @Test public void testCanBeLaunchedOnDisplay() { mService.mSupportsMultiWindow = true; Loading Loading @@ -281,7 +284,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; mActivity.ensureActivityConfiguration(0, false, false); ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE, mActivity.mRelaunchReason); Loading @@ -305,7 +308,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; mActivity.ensureActivityConfiguration(0, false, false); ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE, mActivity.mRelaunchReason); Loading @@ -327,7 +330,7 @@ public class ActivityRecordTests extends ActivityTestsBase { mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; mActivity.ensureActivityConfiguration(0, false, false); ensureActivityConfiguration(); assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE, mActivity.mRelaunchReason); Loading Loading @@ -433,4 +436,46 @@ public class ActivityRecordTests extends ActivityTestsBase { stack.getDisplay().removeChild(stack); } } @Test public void testFixedScreenConfigurationWhenMovingToDisplay() { // Initialize different bounds on a new display. final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); newDisplay.setBounds(0, 0, 1000, 2000); newDisplay.getConfiguration().densityDpi = 300; mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); mTask.getConfiguration().densityDpi = 200; when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; mActivity.info.maxAspectRatio = 1.5f; ensureActivityConfiguration(); final Rect originalBounds = new Rect(mActivity.getBounds()); final int originalDpi = mActivity.getConfiguration().densityDpi; // Move the non-resizable activity to the new display. mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */); ensureActivityConfiguration(); assertEquals(originalBounds, mActivity.getBounds()); assertEquals(originalDpi, mActivity.getConfiguration().densityDpi); } @Test public void testFixedScreenBoundsWhenDisplaySizeChanged() { when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn( ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds()); mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE; ensureActivityConfiguration(); final Rect originalBounds = new Rect(mActivity.getBounds()); // Change the size of current display. mStack.getDisplay().setBounds(0, 0, 1000, 2000); ensureActivityConfiguration(); assertEquals(originalBounds, mActivity.getBounds()); } }