Loading core/java/android/app/TaskInfo.java +13 −1 Original line number Diff line number Diff line Loading @@ -194,6 +194,14 @@ public class TaskInfo { @Nullable public Rect letterboxActivityBounds; /** * Activity insets if this task or its top activity is presented in letterbox mode and * {@code null} otherwise. * @hide */ @Nullable public Rect letterboxActivityInsets; /** * Relative position of the task's top left corner in the parent container. * @hide Loading Loading @@ -328,7 +336,8 @@ public class TaskInfo { && Objects.equals( getConfiguration().windowConfiguration.getMaxBounds(), that.getConfiguration().windowConfiguration.getMaxBounds()) && Objects.equals(parentBounds, that.parentBounds); && Objects.equals(parentBounds, that.parentBounds) && Objects.equals(letterboxActivityInsets, that.letterboxActivityInsets); } /** Loading Loading @@ -365,6 +374,7 @@ public class TaskInfo { parentBounds = source.readTypedObject(Rect.CREATOR); isFocused = source.readBoolean(); isVisible = source.readBoolean(); letterboxActivityInsets = source.readTypedObject(Rect.CREATOR); } /** Loading Loading @@ -402,6 +412,7 @@ public class TaskInfo { dest.writeTypedObject(parentBounds, flags); dest.writeBoolean(isFocused); dest.writeBoolean(isVisible); dest.writeTypedObject(letterboxActivityInsets, flags); } @Override Loading @@ -428,6 +439,7 @@ public class TaskInfo { + " parentBounds=" + parentBounds + " isFocused=" + isFocused + " isVisible=" + isVisible + " letterboxActivityInsets=" + letterboxActivityInsets + "}"; } } libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java +47 −4 Original line number Diff line number Diff line Loading @@ -164,8 +164,6 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener { switch (gravity) { case Gravity.TOP: positionInParent.y += taskBoundsWithInsets.top - activityBoundsWithInsets.top; // Showing status bar decor view. crop.top -= activityBoundsWithInsets.top - activityBounds.top; break; case Gravity.CENTER: positionInParent.y += Loading @@ -187,8 +185,6 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener { final int gravity = mLetterboxConfigController.getLandscapeGravity(); // Align activity to the top. positionInParent.y += taskBoundsWithInsets.top - activityBoundsWithInsets.top; // Showing status bar decor view. crop.top -= activityBoundsWithInsets.top - activityBounds.top; switch (gravity) { case Gravity.LEFT: positionInParent.x += taskBoundsWithInsets.left - activityBoundsWithInsets.left; Loading @@ -209,6 +205,53 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener { + " for task: #" + taskInfo.taskId); } } // New bounds of the activity after it's repositioned with required gravity. Rect newActivityBounds = new Rect(activityBounds); // Task's surfce will be repositioned to positionInParent together with the activity // inside it so the new activity bounds are the original activity bounds offset by // the task's offset. newActivityBounds.offset( positionInParent.x - taskBounds.left, positionInParent.y - taskBounds.top); Rect newActivityBoundsWithInsets = new Rect(newActivityBounds); newActivityBoundsWithInsets.intersect(displayBoundsWithInsets); // Activity handles insets on its own (e.g. under status bar or navigation bar). // crop that is calculated above crops all insets from an activity and below insets that // can be shown are added back to the crop bounds (e.g. if activity is still shown at the // top of the display then the top inset won't be cropped). // After task's surface is repositioned, intersection between an activity and insets can // change but if it doesn't, the activity should be shown under insets to maximize visible // area. // Also, an activity can use area under insets and insets shouldn't be cropped in this case // regardless of a position on the screen. final Rect activityInsetsFromCore = taskInfo.letterboxActivityInsets; if (newActivityBounds.top - newActivityBoundsWithInsets.top == activityBounds.top - activityBoundsWithInsets.top // Check whether an activity is shown under inset. If it is, then the inset from // WM Core and the inset computed here will be different because local insets // doesn't take into account visibility of insets requested by the activity. || activityBoundsWithInsets.top - activityBounds.top != activityInsetsFromCore.top) { crop.top -= activityBoundsWithInsets.top - activityBounds.top; } if (newActivityBounds.bottom - newActivityBoundsWithInsets.bottom == activityBounds.bottom - activityBoundsWithInsets.bottom || activityBounds.bottom - activityBoundsWithInsets.bottom != activityInsetsFromCore.bottom) { crop.bottom += activityBounds.bottom - activityBoundsWithInsets.bottom; } if (newActivityBounds.left - newActivityBoundsWithInsets.left == activityBounds.left - activityBoundsWithInsets.left || activityBoundsWithInsets.left - activityBounds.left != activityInsetsFromCore.left) { crop.left -= activityBoundsWithInsets.left - activityBounds.left; } if (newActivityBounds.right - newActivityBoundsWithInsets.right == activityBounds.right - activityBoundsWithInsets.right || activityBounds.right - activityBoundsWithInsets.right != activityInsetsFromCore.right) { crop.right += activityBounds.right - activityBoundsWithInsets.right; } } private Insets getInsets() { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java +50 −15 Original line number Diff line number Diff line Loading @@ -99,7 +99,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 100), /* activityBounds */ new Rect(75, 0, 125, 75), /* taskBounds */ new Rect(50, 0, 125, 100)), /* taskBounds */ new Rect(50, 0, 125, 100), /* activityInsets */ new Rect(0, 0, 0, 0)), mLeash); // Task doesn't need to repositioned Loading @@ -114,7 +115,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* parentBounds */ new Rect(0, 0, 200, 100), // Activity is offset by 25 to the left /* activityBounds */ new Rect(50, 0, 100, 75), /* taskBounds */ new Rect(50, 0, 125, 100))); /* taskBounds */ new Rect(50, 0, 125, 100), /* activityInsets */ new Rect(0, 0, 0, 0))); // Task needs to be repositioned by 25 to the left verifySetPosition(75, 0); Loading @@ -135,7 +137,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 100), /* activityBounds */ new Rect(150, 0, 200, 75), /* taskBounds */ new Rect(125, 0, 200, 100)), /* taskBounds */ new Rect(125, 0, 200, 100), /* activityInsets */ new Rect(0, 10, 10, 0)), mLeash); verifySetPosition(-15, 0); Loading @@ -156,7 +159,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 100), /* activityBounds */ new Rect(150, 0, 200, 75), /* taskBounds */ new Rect(125, 0, 200, 100)), /* taskBounds */ new Rect(125, 0, 200, 100), /* activityInsets */ new Rect(0, 10, 10, 0)), mLeash); verifySetPosition(55, 0); Loading @@ -177,7 +181,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 100), /* activityBounds */ new Rect(50, 0, 100, 75), /* taskBounds */ new Rect(25, 0, 100, 100)), /* taskBounds */ new Rect(25, 0, 100, 100), /* activityInsets */ new Rect(0, 10, 10, 0)), mLeash); verifySetPosition(115, 0); Loading @@ -198,7 +203,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 100, 150), /* activityBounds */ new Rect(0, 75, 50, 125), /* taskBounds */ new Rect(0, 50, 100, 125)), /* taskBounds */ new Rect(0, 50, 100, 125), /* activityInsets */ new Rect(10, 0, 0, 0)), mLeash); verifySetPosition(20, -15); Loading @@ -219,7 +225,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 100, 150), /* activityBounds */ new Rect(0, 75, 50, 125), /* taskBounds */ new Rect(0, 50, 100, 125)), /* taskBounds */ new Rect(0, 50, 100, 125), /* activityInsets */ new Rect(10, 0, 0, 0)), mLeash); verifySetPosition(20, 20); Loading @@ -227,6 +234,29 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { verifySetWindowCrop(new Rect(10, 25, 50, 75)); } @Test public void testOnTaskInfoAppeared_portraitWithCenterGravity_visibleLeftInset() { mLetterboxConfigController.setPortraitGravity(Gravity.CENTER); setWindowBoundsAndInsets( /* windowBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 20)); mLetterboxTaskListener.onTaskAppeared( createTaskInfo( /* taskId */ 1, /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 100, 150), /* activityBounds */ new Rect(0, 75, 50, 125), /* taskBounds */ new Rect(0, 50, 100, 125), // Activity is drawn under the left inset. /* activityInsets */ new Rect(0, 0, 0, 0)), mLeash); verifySetPosition(20, 20); // Should return activity coordinates offset by task coordinates verifySetWindowCrop(new Rect(0, 25, 50, 75)); } @Test public void testOnTaskInfoAppeared_portraitWithBottomGravity() { mLetterboxConfigController.setPortraitGravity(Gravity.BOTTOM); Loading @@ -240,7 +270,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 100, 150), /* activityBounds */ new Rect(0, 75, 50, 125), /* taskBounds */ new Rect(0, 50, 100, 125)), /* taskBounds */ new Rect(0, 50, 100, 125), /* activityInsets */ new Rect(10, 0, 0, 0)), mLeash); verifySetPosition(20, 55); Loading @@ -261,14 +292,14 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 125), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 125), /* activityBounds */ new Rect(15, 0, 175, 120), /* taskBounds */ new Rect(0, 0, 100, 125)), // equal to parent bounds /* taskBounds */ new Rect(0, 0, 200, 125), /* activityInsets */ new Rect(10, 25, 10, 10)), // equal to parent bounds mLeash); // Activity fully covers parent bounds with insets so doesn't need to be moved. verifySetPosition(0, 0); // Should return activity coordinates offset by task coordinates minus all insets // except top one (keep status bar decor visible). verifySetWindowCrop(new Rect(25, 0, 165, 110)); // Should return activity coordinates offset by task coordinates verifySetWindowCrop(new Rect(15, 0, 175, 120)); } @Test Loading @@ -284,7 +315,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 100, 150), /* parentBounds */ new Rect(0, 75, 100, 225), /* activityBounds */ new Rect(25, 75, 75, 125), /* taskBounds */ new Rect(0, 75, 100, 125)), /* taskBounds */ new Rect(0, 75, 100, 125), /* activityInsets */ new Rect(10, 0, 0, 0)), mLeash); verifySetPosition(0, 0); Loading @@ -295,7 +327,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { public void testOnTaskAppeared_calledSecondTimeWithSameTaskId_throwsException() { setWindowBoundsAndInsets(new Rect(), Insets.NONE); RunningTaskInfo taskInfo = createTaskInfo(/* taskId */ 1, new Rect(), new Rect(), new Rect(), new Rect()); createTaskInfo(/* taskId */ 1, new Rect(), new Rect(), new Rect(), new Rect(), new Rect()); mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash); mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash); } Loading @@ -319,13 +352,15 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { final Rect maxBounds, final Rect parentBounds, final Rect activityBounds, final Rect taskBounds) { final Rect taskBounds, final Rect activityInsets) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; taskInfo.configuration.windowConfiguration.setMaxBounds(maxBounds); taskInfo.parentBounds = parentBounds; taskInfo.configuration.windowConfiguration.setBounds(taskBounds); taskInfo.letterboxActivityBounds = Rect.copyOrNull(activityBounds); taskInfo.letterboxActivityInsets = Rect.copyOrNull(activityInsets); return taskInfo; } Loading services/core/java/com/android/server/wm/ActivityRecord.java +13 −7 Original line number Diff line number Diff line Loading @@ -1366,7 +1366,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else if (mLetterbox != null) { mLetterbox.hide(); } task.maybeUpdateLetterboxBounds(this, getLetterboxParams(w)); maybeUpdateLetterboxInTaskOrganizer(w); } private void maybeUpdateLetterboxInTaskOrganizer(WindowState w) { boolean isLetterboxed = w.isLetterboxedAppWindow() && fillsParent(); if (!isLetterboxed) { task.maybeUpdateLetterboxInTaskOrganizer( this, /* activityBounds= */ null, /* activityInsets= */ null); return; } final Rect insets = w.getInsetsStateWithVisibilityOverride().calculateInsets( getBounds(), Type.systemBars(), false /* ignoreVisibility */); task.maybeUpdateLetterboxInTaskOrganizer(this, getBounds(), insets); } void updateLetterboxSurface(WindowState winHint) { Loading @@ -1380,12 +1392,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } @Nullable private Rect getLetterboxParams(WindowState w) { boolean isLetterboxed = w.isLetterboxedAppWindow() && fillsParent(); return isLetterboxed ? getBounds() : null; } Rect getLetterboxInsets() { if (mLetterbox != null) { return mLetterbox.getInsets(); Loading services/core/java/com/android/server/wm/Task.java +14 −6 Original line number Diff line number Diff line Loading @@ -519,6 +519,11 @@ class Task extends WindowContainer<WindowContainer> { @Nullable private Rect mLetterboxActivityBounds; // Activity insets if this task or its top activity is presented in letterbox mode and // {@code null} otherwise. @Nullable private Rect mLetterboxActivityInsets; // Whether the task is currently being drag-resized private boolean mDragResizing; private int mDragResizeMode; Loading Loading @@ -4083,6 +4088,7 @@ class Task extends WindowContainer<WindowContainer> { // bounds, e.g. fullscreen bounds instead of letterboxed bounds. To work around this, // assigning bounds from ActivityRecord#layoutLetterbox when they are ready. info.letterboxActivityBounds = Rect.copyOrNull(mLetterboxActivityBounds); info.letterboxActivityInsets = Rect.copyOrNull(mLetterboxActivityInsets); info.positionInParent = getRelativePosition(); info.parentBounds = getParentBounds(); Loading Loading @@ -4110,15 +4116,17 @@ class Task extends WindowContainer<WindowContainer> { ? null : new PictureInPictureParams(rootActivity.pictureInPictureArgs); } void maybeUpdateLetterboxBounds( ActivityRecord activityRecord, @Nullable Rect letterboxActivityBounds) { void maybeUpdateLetterboxInTaskOrganizer( ActivityRecord activityRecord, @Nullable Rect activityBounds, @Nullable Rect activityInsets) { if (isOrganized() && mReuseActivitiesReport.top == activityRecord // Want to force update only if letterbox bounds have changed. && !Objects.equals( mLetterboxActivityBounds, letterboxActivityBounds)) { mLetterboxActivityBounds = Rect.copyOrNull(letterboxActivityBounds); && (!Objects.equals(mLetterboxActivityBounds, activityBounds) || !Objects.equals(mLetterboxActivityInsets, activityInsets))) { mLetterboxActivityBounds = Rect.copyOrNull(activityBounds); mLetterboxActivityInsets = Rect.copyOrNull(activityInsets); // Forcing update to reduce visual jank during the transition. dispatchTaskInfoChangedIfNeeded(true /* force */); } Loading Loading
core/java/android/app/TaskInfo.java +13 −1 Original line number Diff line number Diff line Loading @@ -194,6 +194,14 @@ public class TaskInfo { @Nullable public Rect letterboxActivityBounds; /** * Activity insets if this task or its top activity is presented in letterbox mode and * {@code null} otherwise. * @hide */ @Nullable public Rect letterboxActivityInsets; /** * Relative position of the task's top left corner in the parent container. * @hide Loading Loading @@ -328,7 +336,8 @@ public class TaskInfo { && Objects.equals( getConfiguration().windowConfiguration.getMaxBounds(), that.getConfiguration().windowConfiguration.getMaxBounds()) && Objects.equals(parentBounds, that.parentBounds); && Objects.equals(parentBounds, that.parentBounds) && Objects.equals(letterboxActivityInsets, that.letterboxActivityInsets); } /** Loading Loading @@ -365,6 +374,7 @@ public class TaskInfo { parentBounds = source.readTypedObject(Rect.CREATOR); isFocused = source.readBoolean(); isVisible = source.readBoolean(); letterboxActivityInsets = source.readTypedObject(Rect.CREATOR); } /** Loading Loading @@ -402,6 +412,7 @@ public class TaskInfo { dest.writeTypedObject(parentBounds, flags); dest.writeBoolean(isFocused); dest.writeBoolean(isVisible); dest.writeTypedObject(letterboxActivityInsets, flags); } @Override Loading @@ -428,6 +439,7 @@ public class TaskInfo { + " parentBounds=" + parentBounds + " isFocused=" + isFocused + " isVisible=" + isVisible + " letterboxActivityInsets=" + letterboxActivityInsets + "}"; } }
libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java +47 −4 Original line number Diff line number Diff line Loading @@ -164,8 +164,6 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener { switch (gravity) { case Gravity.TOP: positionInParent.y += taskBoundsWithInsets.top - activityBoundsWithInsets.top; // Showing status bar decor view. crop.top -= activityBoundsWithInsets.top - activityBounds.top; break; case Gravity.CENTER: positionInParent.y += Loading @@ -187,8 +185,6 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener { final int gravity = mLetterboxConfigController.getLandscapeGravity(); // Align activity to the top. positionInParent.y += taskBoundsWithInsets.top - activityBoundsWithInsets.top; // Showing status bar decor view. crop.top -= activityBoundsWithInsets.top - activityBounds.top; switch (gravity) { case Gravity.LEFT: positionInParent.x += taskBoundsWithInsets.left - activityBoundsWithInsets.left; Loading @@ -209,6 +205,53 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener { + " for task: #" + taskInfo.taskId); } } // New bounds of the activity after it's repositioned with required gravity. Rect newActivityBounds = new Rect(activityBounds); // Task's surfce will be repositioned to positionInParent together with the activity // inside it so the new activity bounds are the original activity bounds offset by // the task's offset. newActivityBounds.offset( positionInParent.x - taskBounds.left, positionInParent.y - taskBounds.top); Rect newActivityBoundsWithInsets = new Rect(newActivityBounds); newActivityBoundsWithInsets.intersect(displayBoundsWithInsets); // Activity handles insets on its own (e.g. under status bar or navigation bar). // crop that is calculated above crops all insets from an activity and below insets that // can be shown are added back to the crop bounds (e.g. if activity is still shown at the // top of the display then the top inset won't be cropped). // After task's surface is repositioned, intersection between an activity and insets can // change but if it doesn't, the activity should be shown under insets to maximize visible // area. // Also, an activity can use area under insets and insets shouldn't be cropped in this case // regardless of a position on the screen. final Rect activityInsetsFromCore = taskInfo.letterboxActivityInsets; if (newActivityBounds.top - newActivityBoundsWithInsets.top == activityBounds.top - activityBoundsWithInsets.top // Check whether an activity is shown under inset. If it is, then the inset from // WM Core and the inset computed here will be different because local insets // doesn't take into account visibility of insets requested by the activity. || activityBoundsWithInsets.top - activityBounds.top != activityInsetsFromCore.top) { crop.top -= activityBoundsWithInsets.top - activityBounds.top; } if (newActivityBounds.bottom - newActivityBoundsWithInsets.bottom == activityBounds.bottom - activityBoundsWithInsets.bottom || activityBounds.bottom - activityBoundsWithInsets.bottom != activityInsetsFromCore.bottom) { crop.bottom += activityBounds.bottom - activityBoundsWithInsets.bottom; } if (newActivityBounds.left - newActivityBoundsWithInsets.left == activityBounds.left - activityBoundsWithInsets.left || activityBoundsWithInsets.left - activityBounds.left != activityInsetsFromCore.left) { crop.left -= activityBoundsWithInsets.left - activityBounds.left; } if (newActivityBounds.right - newActivityBoundsWithInsets.right == activityBounds.right - activityBoundsWithInsets.right || activityBounds.right - activityBoundsWithInsets.right != activityInsetsFromCore.right) { crop.right += activityBounds.right - activityBoundsWithInsets.right; } } private Insets getInsets() { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java +50 −15 Original line number Diff line number Diff line Loading @@ -99,7 +99,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 100), /* activityBounds */ new Rect(75, 0, 125, 75), /* taskBounds */ new Rect(50, 0, 125, 100)), /* taskBounds */ new Rect(50, 0, 125, 100), /* activityInsets */ new Rect(0, 0, 0, 0)), mLeash); // Task doesn't need to repositioned Loading @@ -114,7 +115,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* parentBounds */ new Rect(0, 0, 200, 100), // Activity is offset by 25 to the left /* activityBounds */ new Rect(50, 0, 100, 75), /* taskBounds */ new Rect(50, 0, 125, 100))); /* taskBounds */ new Rect(50, 0, 125, 100), /* activityInsets */ new Rect(0, 0, 0, 0))); // Task needs to be repositioned by 25 to the left verifySetPosition(75, 0); Loading @@ -135,7 +137,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 100), /* activityBounds */ new Rect(150, 0, 200, 75), /* taskBounds */ new Rect(125, 0, 200, 100)), /* taskBounds */ new Rect(125, 0, 200, 100), /* activityInsets */ new Rect(0, 10, 10, 0)), mLeash); verifySetPosition(-15, 0); Loading @@ -156,7 +159,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 100), /* activityBounds */ new Rect(150, 0, 200, 75), /* taskBounds */ new Rect(125, 0, 200, 100)), /* taskBounds */ new Rect(125, 0, 200, 100), /* activityInsets */ new Rect(0, 10, 10, 0)), mLeash); verifySetPosition(55, 0); Loading @@ -177,7 +181,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 100), /* activityBounds */ new Rect(50, 0, 100, 75), /* taskBounds */ new Rect(25, 0, 100, 100)), /* taskBounds */ new Rect(25, 0, 100, 100), /* activityInsets */ new Rect(0, 10, 10, 0)), mLeash); verifySetPosition(115, 0); Loading @@ -198,7 +203,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 100, 150), /* activityBounds */ new Rect(0, 75, 50, 125), /* taskBounds */ new Rect(0, 50, 100, 125)), /* taskBounds */ new Rect(0, 50, 100, 125), /* activityInsets */ new Rect(10, 0, 0, 0)), mLeash); verifySetPosition(20, -15); Loading @@ -219,7 +225,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 100, 150), /* activityBounds */ new Rect(0, 75, 50, 125), /* taskBounds */ new Rect(0, 50, 100, 125)), /* taskBounds */ new Rect(0, 50, 100, 125), /* activityInsets */ new Rect(10, 0, 0, 0)), mLeash); verifySetPosition(20, 20); Loading @@ -227,6 +234,29 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { verifySetWindowCrop(new Rect(10, 25, 50, 75)); } @Test public void testOnTaskInfoAppeared_portraitWithCenterGravity_visibleLeftInset() { mLetterboxConfigController.setPortraitGravity(Gravity.CENTER); setWindowBoundsAndInsets( /* windowBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 20)); mLetterboxTaskListener.onTaskAppeared( createTaskInfo( /* taskId */ 1, /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 100, 150), /* activityBounds */ new Rect(0, 75, 50, 125), /* taskBounds */ new Rect(0, 50, 100, 125), // Activity is drawn under the left inset. /* activityInsets */ new Rect(0, 0, 0, 0)), mLeash); verifySetPosition(20, 20); // Should return activity coordinates offset by task coordinates verifySetWindowCrop(new Rect(0, 25, 50, 75)); } @Test public void testOnTaskInfoAppeared_portraitWithBottomGravity() { mLetterboxConfigController.setPortraitGravity(Gravity.BOTTOM); Loading @@ -240,7 +270,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 100, 150), /* activityBounds */ new Rect(0, 75, 50, 125), /* taskBounds */ new Rect(0, 50, 100, 125)), /* taskBounds */ new Rect(0, 50, 100, 125), /* activityInsets */ new Rect(10, 0, 0, 0)), mLeash); verifySetPosition(20, 55); Loading @@ -261,14 +292,14 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 200, 125), // equal to parent bounds /* parentBounds */ new Rect(0, 0, 200, 125), /* activityBounds */ new Rect(15, 0, 175, 120), /* taskBounds */ new Rect(0, 0, 100, 125)), // equal to parent bounds /* taskBounds */ new Rect(0, 0, 200, 125), /* activityInsets */ new Rect(10, 25, 10, 10)), // equal to parent bounds mLeash); // Activity fully covers parent bounds with insets so doesn't need to be moved. verifySetPosition(0, 0); // Should return activity coordinates offset by task coordinates minus all insets // except top one (keep status bar decor visible). verifySetWindowCrop(new Rect(25, 0, 165, 110)); // Should return activity coordinates offset by task coordinates verifySetWindowCrop(new Rect(15, 0, 175, 120)); } @Test Loading @@ -284,7 +315,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { /* maxBounds= */ new Rect(0, 0, 100, 150), /* parentBounds */ new Rect(0, 75, 100, 225), /* activityBounds */ new Rect(25, 75, 75, 125), /* taskBounds */ new Rect(0, 75, 100, 125)), /* taskBounds */ new Rect(0, 75, 100, 125), /* activityInsets */ new Rect(10, 0, 0, 0)), mLeash); verifySetPosition(0, 0); Loading @@ -295,7 +327,8 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { public void testOnTaskAppeared_calledSecondTimeWithSameTaskId_throwsException() { setWindowBoundsAndInsets(new Rect(), Insets.NONE); RunningTaskInfo taskInfo = createTaskInfo(/* taskId */ 1, new Rect(), new Rect(), new Rect(), new Rect()); createTaskInfo(/* taskId */ 1, new Rect(), new Rect(), new Rect(), new Rect(), new Rect()); mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash); mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash); } Loading @@ -319,13 +352,15 @@ public final class LetterboxTaskListenerTest extends ShellTestCase { final Rect maxBounds, final Rect parentBounds, final Rect activityBounds, final Rect taskBounds) { final Rect taskBounds, final Rect activityInsets) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; taskInfo.configuration.windowConfiguration.setMaxBounds(maxBounds); taskInfo.parentBounds = parentBounds; taskInfo.configuration.windowConfiguration.setBounds(taskBounds); taskInfo.letterboxActivityBounds = Rect.copyOrNull(activityBounds); taskInfo.letterboxActivityInsets = Rect.copyOrNull(activityInsets); return taskInfo; } Loading
services/core/java/com/android/server/wm/ActivityRecord.java +13 −7 Original line number Diff line number Diff line Loading @@ -1366,7 +1366,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else if (mLetterbox != null) { mLetterbox.hide(); } task.maybeUpdateLetterboxBounds(this, getLetterboxParams(w)); maybeUpdateLetterboxInTaskOrganizer(w); } private void maybeUpdateLetterboxInTaskOrganizer(WindowState w) { boolean isLetterboxed = w.isLetterboxedAppWindow() && fillsParent(); if (!isLetterboxed) { task.maybeUpdateLetterboxInTaskOrganizer( this, /* activityBounds= */ null, /* activityInsets= */ null); return; } final Rect insets = w.getInsetsStateWithVisibilityOverride().calculateInsets( getBounds(), Type.systemBars(), false /* ignoreVisibility */); task.maybeUpdateLetterboxInTaskOrganizer(this, getBounds(), insets); } void updateLetterboxSurface(WindowState winHint) { Loading @@ -1380,12 +1392,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } @Nullable private Rect getLetterboxParams(WindowState w) { boolean isLetterboxed = w.isLetterboxedAppWindow() && fillsParent(); return isLetterboxed ? getBounds() : null; } Rect getLetterboxInsets() { if (mLetterbox != null) { return mLetterbox.getInsets(); Loading
services/core/java/com/android/server/wm/Task.java +14 −6 Original line number Diff line number Diff line Loading @@ -519,6 +519,11 @@ class Task extends WindowContainer<WindowContainer> { @Nullable private Rect mLetterboxActivityBounds; // Activity insets if this task or its top activity is presented in letterbox mode and // {@code null} otherwise. @Nullable private Rect mLetterboxActivityInsets; // Whether the task is currently being drag-resized private boolean mDragResizing; private int mDragResizeMode; Loading Loading @@ -4083,6 +4088,7 @@ class Task extends WindowContainer<WindowContainer> { // bounds, e.g. fullscreen bounds instead of letterboxed bounds. To work around this, // assigning bounds from ActivityRecord#layoutLetterbox when they are ready. info.letterboxActivityBounds = Rect.copyOrNull(mLetterboxActivityBounds); info.letterboxActivityInsets = Rect.copyOrNull(mLetterboxActivityInsets); info.positionInParent = getRelativePosition(); info.parentBounds = getParentBounds(); Loading Loading @@ -4110,15 +4116,17 @@ class Task extends WindowContainer<WindowContainer> { ? null : new PictureInPictureParams(rootActivity.pictureInPictureArgs); } void maybeUpdateLetterboxBounds( ActivityRecord activityRecord, @Nullable Rect letterboxActivityBounds) { void maybeUpdateLetterboxInTaskOrganizer( ActivityRecord activityRecord, @Nullable Rect activityBounds, @Nullable Rect activityInsets) { if (isOrganized() && mReuseActivitiesReport.top == activityRecord // Want to force update only if letterbox bounds have changed. && !Objects.equals( mLetterboxActivityBounds, letterboxActivityBounds)) { mLetterboxActivityBounds = Rect.copyOrNull(letterboxActivityBounds); && (!Objects.equals(mLetterboxActivityBounds, activityBounds) || !Objects.equals(mLetterboxActivityInsets, activityInsets))) { mLetterboxActivityBounds = Rect.copyOrNull(activityBounds); mLetterboxActivityInsets = Rect.copyOrNull(activityInsets); // Forcing update to reduce visual jank during the transition. dispatchTaskInfoChangedIfNeeded(true /* force */); } Loading