Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e714b038 authored by Mariia Sandrikova's avatar Mariia Sandrikova Committed by Android (Google) Code Review
Browse files

Merge "Letterbox: show activity under insets when possible or needed"

parents e386b0a3 41eff682
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -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
@@ -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);
    }

    /**
@@ -365,6 +374,7 @@ public class TaskInfo {
        parentBounds = source.readTypedObject(Rect.CREATOR);
        isFocused = source.readBoolean();
        isVisible = source.readBoolean();
        letterboxActivityInsets = source.readTypedObject(Rect.CREATOR);
    }

    /**
@@ -402,6 +412,7 @@ public class TaskInfo {
        dest.writeTypedObject(parentBounds, flags);
        dest.writeBoolean(isFocused);
        dest.writeBoolean(isVisible);
        dest.writeTypedObject(letterboxActivityInsets, flags);
    }

    @Override
@@ -428,6 +439,7 @@ public class TaskInfo {
                + " parentBounds=" + parentBounds
                + " isFocused=" + isFocused
                + " isVisible=" + isVisible
                + " letterboxActivityInsets=" + letterboxActivityInsets
                + "}";
    }
}
+47 −4
Original line number Diff line number Diff line
@@ -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 +=
@@ -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;
@@ -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() {
+50 −15
Original line number Diff line number Diff line
@@ -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
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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
@@ -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);
@@ -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);
    }
@@ -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;
    }
+13 −7
Original line number Diff line number Diff line
@@ -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) {
@@ -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();
+14 −6
Original line number Diff line number Diff line
@@ -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;
@@ -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();

@@ -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 */);
        }