Fix letterbox in fixed rotation transform
- Use rotated bounds as outer frames of letterbox.
- Make sure app bounds related configuration is always
computed by resolved bounds, so the app bounds won't
keep a intermediate result while the parent hasn't
rotated yet.
- Fix freeform size compat activity cannot move outside
of display left side.
Fix: 151134392
Test: SizeCompatTests#testLaunchWithFixedRotationTransform
testKeepBoundsWhenChangingFromFreeformToFullscreen
Change-Id: I0615aa4629eefcb1f666482258f6032fe3e89def
This commit is contained in:
@@ -1351,11 +1351,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
mLetterbox.attachInput(w);
|
||||
}
|
||||
getPosition(mTmpPoint);
|
||||
// Get the bounds of the "space-to-fill". In multi-window mode, the task-level
|
||||
// represents this. In fullscreen-mode, the stack does (since the orientation letterbox
|
||||
// is also applied to the task).
|
||||
Rect spaceToFill = (inMultiWindowMode() || getStack() == null)
|
||||
? task.getDisplayedBounds() : getStack().getDisplayedBounds();
|
||||
// Get the bounds of the "space-to-fill". The transformed bounds have the highest
|
||||
// priority because the activity is launched in a rotated environment. In multi-window
|
||||
// mode, the task-level represents this. In fullscreen-mode, the task container does
|
||||
// (since the orientation letterbox is also applied to the task).
|
||||
final Rect transformedBounds = getFixedRotationTransformDisplayBounds();
|
||||
final Rect spaceToFill = transformedBounds != null
|
||||
? transformedBounds
|
||||
: inMultiWindowMode()
|
||||
? task.getDisplayedBounds()
|
||||
: getRootTask().getParent().getDisplayedBounds();
|
||||
mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
|
||||
} else if (mLetterbox != null) {
|
||||
mLetterbox.hide();
|
||||
@@ -6362,33 +6367,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
if (mCompatDisplayInsets != null) {
|
||||
resolveSizeCompatModeConfiguration(newParentConfiguration);
|
||||
} else {
|
||||
// We ignore activities' requested orientation in multi-window modes. Task level may
|
||||
// take them into consideration when calculating bounds.
|
||||
if (inMultiWindowMode()) {
|
||||
// We ignore activities' requested orientation in multi-window modes. Task level may
|
||||
// take them into consideration when calculating bounds.
|
||||
resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED;
|
||||
}
|
||||
final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
|
||||
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
|
||||
// Use tmp bounds to calculate aspect ratio so we can know whether the activity should
|
||||
// use restricted size (resolvedBounds may be the requested override bounds).
|
||||
mTmpBounds.setEmpty();
|
||||
applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
|
||||
// If the out bounds is not empty, it means the activity cannot fill parent's app
|
||||
// bounds, then the relative configuration (e.g. screen size, layout) needs to be
|
||||
// resolved according to the bounds.
|
||||
if (!mTmpBounds.isEmpty()) {
|
||||
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
|
||||
resolvedBounds.set(mTmpBounds);
|
||||
// Exclude the horizontal decor area because the activity will be centered
|
||||
// horizontally in parent's app bounds to balance the visual appearance.
|
||||
resolvedBounds.left = parentAppBounds.left;
|
||||
task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
|
||||
getFixedRotationTransformDisplayInfo());
|
||||
final int offsetX = getHorizontalCenterOffset(
|
||||
parentAppBounds.width(), resolvedBounds.width());
|
||||
if (offsetX > 0) {
|
||||
offsetBounds(resolvedConfig, offsetX - resolvedBounds.left, 0 /* offsetY */);
|
||||
// If the activity has requested override bounds, the configuration needs to be
|
||||
// computed accordingly.
|
||||
if (!matchParentBounds()) {
|
||||
task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
|
||||
}
|
||||
} else {
|
||||
resolveFullscreenConfiguration(newParentConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6399,6 +6388,43 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
getResolvedOverrideConfiguration().seq = mConfigurationSeq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the configuration of activity in fullscreen mode. If the bounds are restricted by
|
||||
* aspect ratio, the position will be centered horizontally in parent's app bounds to balance
|
||||
* the visual appearance. The policy of aspect ratio has higher priority than the requested
|
||||
* override bounds.
|
||||
*/
|
||||
private void resolveFullscreenConfiguration(Configuration newParentConfiguration) {
|
||||
final Configuration resolvedConfig = getResolvedOverrideConfiguration();
|
||||
final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
|
||||
final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
|
||||
final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
|
||||
// Use tmp bounds to calculate aspect ratio so we can know whether the activity should use
|
||||
// restricted size (resolved bounds may be the requested override bounds).
|
||||
mTmpBounds.setEmpty();
|
||||
applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds);
|
||||
// If the out bounds is not empty, it means the activity cannot fill parent's app bounds,
|
||||
// then there is space to be centered.
|
||||
final boolean needToBeCentered = !mTmpBounds.isEmpty();
|
||||
if (needToBeCentered) {
|
||||
resolvedBounds.set(mTmpBounds);
|
||||
// Exclude the horizontal decor area.
|
||||
resolvedBounds.left = parentAppBounds.left;
|
||||
}
|
||||
if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
|
||||
// Compute the configuration based on the resolved bounds. If aspect ratio doesn't
|
||||
// restrict, the bounds should be the requested override bounds.
|
||||
task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
|
||||
getFixedRotationTransformDisplayInfo());
|
||||
}
|
||||
if (needToBeCentered) {
|
||||
// Offset to center relative to parent's app bounds.
|
||||
final int offsetX = getHorizontalCenterOffset(
|
||||
parentAppBounds.width(), resolvedBounds.width());
|
||||
offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves consistent screen configuration for orientation and rotation changes without
|
||||
* inheriting the parent bounds.
|
||||
@@ -6507,7 +6533,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
|
||||
final int screenPosX = parentAppBounds.left + offsetX;
|
||||
final int screenPosY = parentBounds.top;
|
||||
if (screenPosX > 0 || screenPosY > 0) {
|
||||
if (screenPosX != 0 || screenPosY != 0) {
|
||||
if (mSizeCompatBounds != null) {
|
||||
mSizeCompatBounds.offset(screenPosX, screenPosY);
|
||||
}
|
||||
|
||||
@@ -2127,14 +2127,26 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the app bounds related configuration can be computed by
|
||||
* {@link #computeConfigResourceOverrides(Configuration, Configuration, DisplayInfo,
|
||||
* ActivityRecord.CompatDisplayInsets)}.
|
||||
*/
|
||||
private static void invalidateAppBoundsConfig(@NonNull Configuration inOutConfig) {
|
||||
final Rect appBounds = inOutConfig.windowConfiguration.getAppBounds();
|
||||
if (appBounds != null) {
|
||||
appBounds.setEmpty();
|
||||
}
|
||||
inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
|
||||
inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
|
||||
}
|
||||
|
||||
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
|
||||
@NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
|
||||
if (overrideDisplayInfo != null) {
|
||||
// Make sure the screen related configs can be computed by the provided display info.
|
||||
inOutConfig.windowConfiguration.setAppBounds(null);
|
||||
inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
|
||||
inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
|
||||
inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
|
||||
invalidateAppBoundsConfig(inOutConfig);
|
||||
}
|
||||
computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
|
||||
null /* compatInsets */);
|
||||
@@ -2149,6 +2161,10 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
|
||||
@NonNull Configuration parentConfig,
|
||||
@Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
|
||||
if (compatInsets != null) {
|
||||
// Make sure the app bounds can be computed by the compat insets.
|
||||
invalidateAppBoundsConfig(inOutConfig);
|
||||
}
|
||||
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
|
||||
compatInsets);
|
||||
}
|
||||
|
||||
@@ -107,10 +107,16 @@ public class SizeCompatTests extends ActivityTestsBase {
|
||||
setUpApp(display);
|
||||
|
||||
// Put app window into freeform and then make it a compat app.
|
||||
mTask.setBounds(100, 100, 400, 600);
|
||||
final Rect bounds = new Rect(100, 100, 400, 600);
|
||||
mTask.setBounds(bounds);
|
||||
prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
|
||||
assertEquals(bounds, mActivity.getBounds());
|
||||
|
||||
// The activity should be able to accept negative x position [-150, 100 - 150, 600].
|
||||
final int dx = bounds.left + bounds.width() / 2;
|
||||
mTask.setBounds(bounds.left - dx, bounds.top, bounds.right - dx, bounds.bottom);
|
||||
assertEquals(mTask.getBounds(), mActivity.getBounds());
|
||||
|
||||
final Rect bounds = new Rect(mActivity.getBounds());
|
||||
final int density = mActivity.getConfiguration().densityDpi;
|
||||
|
||||
// change display configuration to fullscreen
|
||||
@@ -231,11 +237,7 @@ public class SizeCompatTests extends ActivityTestsBase {
|
||||
// The position should be horizontal centered.
|
||||
assertEquals((displayWidth - bounds.width()) / 2, bounds.left);
|
||||
|
||||
final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
|
||||
mService.mWindowManager, mock(Session.class), new TestIWindow(),
|
||||
new WindowManager.LayoutParams(), mActivity);
|
||||
mActivity.addWindow(w);
|
||||
mActivity.mDisplayContent.mInputMethodTarget = w;
|
||||
mActivity.mDisplayContent.mInputMethodTarget = addWindowToActivity(mActivity);
|
||||
// Make sure IME cannot attach to the app, otherwise IME window will also be shifted.
|
||||
assertFalse(mActivity.mDisplayContent.isImeAttachedToApp());
|
||||
}
|
||||
@@ -475,6 +477,25 @@ public class SizeCompatTests extends ActivityTestsBase {
|
||||
assertEquals((int) (dw * maxAspect), mActivity.getBounds().width());
|
||||
// The bounds should be horizontal centered: (2500-1900)/2=350.
|
||||
assertEquals((dh - mActivity.getBounds().width()) / 2, mActivity.getBounds().left);
|
||||
|
||||
// The letterbox needs a main window to layout.
|
||||
addWindowToActivity(mActivity);
|
||||
// Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}.
|
||||
mActivity.mRootWindowContainer.performSurfacePlacement(false /* recoveringMemory */);
|
||||
// The letterbox insets should be [350, 0 - 350, 0].
|
||||
assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0),
|
||||
mActivity.getLetterboxInsets());
|
||||
}
|
||||
|
||||
private WindowState addWindowToActivity(ActivityRecord activity) {
|
||||
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
|
||||
params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
|
||||
mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
|
||||
WindowTestsBase.makeWindowVisible(w);
|
||||
w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
|
||||
mActivity.addWindow(w);
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user