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

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

Merge "Letterbox positioning (1/4): Consolidate activity and task letterboxing" into sc-dev

parents 5b4c4fea 31d25e9e
Loading
Loading
Loading
Loading
+262 −118

File changed.

Preview size limit exceeded, changes collapsed.

+2 −127
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -148,7 +147,6 @@ import static com.android.server.wm.WindowContainerChildProto.TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.WindowManagerService.dipToPixel;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;

@@ -597,10 +595,6 @@ class Task extends WindowContainer<WindowContainer> {
    @Nullable
    private ActivityRecord mResumedActivity = null;

    /** Last activity that is used to compute the Task bounds. */
    @Nullable
    private ActivityRecord mLastTaskBoundsComputeActivity;

    private boolean mForceShowForAllUsers;

    /** When set, will force the task to report as invisible. */
@@ -1496,11 +1490,6 @@ class Task extends WindowContainer<WindowContainer> {
    }

    void cleanUpActivityReferences(ActivityRecord r) {
        // mLastTaskBoundsComputeActivity is set at leaf Task
        if (mLastTaskBoundsComputeActivity == r) {
            mLastTaskBoundsComputeActivity = null;
        }

        // mPausingActivity is set at leaf task
        if (mPausingActivity != null && mPausingActivity == r) {
            mPausingActivity = null;
@@ -2863,7 +2852,6 @@ class Task extends WindowContainer<WindowContainer> {

    private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
            Rect previousBounds) {
        mLastTaskBoundsComputeActivity = getTopNonFinishingActivity(false /* includeOverlays */);

        int windowingMode =
                getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
@@ -2877,7 +2865,8 @@ class Task extends WindowContainer<WindowContainer> {
                getResolvedOverrideConfiguration().windowConfiguration.getBounds();

        if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
            computeFullscreenBounds(outOverrideBounds, newParentConfig);
            // Use empty bounds to indicate "fill parent".
            outOverrideBounds.setEmpty();
            // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
            // the parent or display is smaller than the size, the content may be cropped.
            return;
@@ -2888,21 +2877,6 @@ class Task extends WindowContainer<WindowContainer> {
            computeFreeformBounds(outOverrideBounds, newParentConfig);
            return;
        }

        if (isSplitScreenWindowingMode(windowingMode)
                || windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
            // This is to compute whether the task should be letterboxed to handle non-resizable app
            // in multi window. There is no split screen only logic.
            computeLetterboxBounds(outOverrideBounds, newParentConfig);
        }
    }

    /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}. */
    @VisibleForTesting
    void computeFullscreenBounds(@NonNull Rect outBounds, @NonNull Configuration newParentConfig) {
        // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
        outBounds.setEmpty();
        computeLetterboxBounds(outBounds, newParentConfig);
    }

    /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */
@@ -2934,94 +2908,6 @@ class Task extends WindowContainer<WindowContainer> {
        }
    }

    /**
     * Computes bounds (letterbox or pillarbox) when the parent doesn't handle the orientation
     * change and the requested orientation is different from the parent.
     */
    private void computeLetterboxBounds(@NonNull Rect outBounds,
            @NonNull Configuration newParentConfig) {
        if (handlesOrientationChangeFromDescendant()) {
            // No need to letterbox at task level. Display will handle fixed-orientation requests.
            return;
        }

        final int parentOrientation = newParentConfig.orientation;
        // Use the top activity as the reference of orientation. Don't include overlays because
        // it is usually not the actual content or just temporarily shown.
        // E.g. ForcedResizableInfoActivity.
        final ActivityRecord refActivity = getTopNonFinishingActivity(false /* includeOverlays */);

        // If the task or the reference activity requires a different orientation (either by
        // override or activityInfo), make it fit the available bounds by scaling down its bounds.
        final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
        final int forcedOrientation =
                (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
                        ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
        if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
            return;
        }

        final ActivityRecord.CompatDisplayInsets compatDisplayInsets =
                refActivity == null ? null : refActivity.getCompatDisplayInsets();
        if (compatDisplayInsets != null && !compatDisplayInsets.mIsTaskLetterboxed) {
            // App prefers to keep its original size.
            // If the size compat is from previous task letterboxing, we may want to have task
            // letterbox again, otherwise it will show the size compat restart button even if the
            // restart bounds will be the same.
            return;
        }

        final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
        final int parentWidth = parentBounds.width();
        final int parentHeight = parentBounds.height();
        float aspect = Math.max(parentWidth, parentHeight)
                / (float) Math.min(parentWidth, parentHeight);

        // Adjust the Task letterbox bounds to fit the app request aspect ratio in order to use the
        // extra available space.
        if (refActivity != null) {
            final float maxAspectRatio = refActivity.info.maxAspectRatio;
            final float minAspectRatio = refActivity.info.minAspectRatio;
            if (aspect > maxAspectRatio && maxAspectRatio != 0) {
                aspect = maxAspectRatio;
            } else if (aspect < minAspectRatio) {
                aspect = minAspectRatio;
            }
        }

        // Override from config_letterboxAspectRatio or via ADB with set-letterbox-aspect-ratio.
        final float letterboxAspectRatioOverride = mWmService.getTaskLetterboxAspectRatio();
        // Activity min/max aspect ratio restrictions will be respected by the activity-level
        // letterboxing (size-compat mode). Therefore this override can control the maximum screen
        // area that can be occupied by the app in the letterbox mode.
        aspect = letterboxAspectRatioOverride > MIN_TASK_LETTERBOX_ASPECT_RATIO
                ? letterboxAspectRatioOverride : aspect;

        // Store the current bounds to be able to revert to size compat mode values below if needed.
        mTmpFullBounds.set(outBounds);
        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
            final int height = (int) Math.rint(parentWidth / aspect);
            final int top = parentBounds.centerY() - height / 2;
            outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
        } else {
            final int width = (int) Math.rint(parentHeight / aspect);
            final int left = parentBounds.centerX() - width / 2;
            outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
        }

        if (compatDisplayInsets != null) {
            compatDisplayInsets.getBoundsByRotation(
                    mTmpBounds, newParentConfig.windowConfiguration.getRotation());
            if (outBounds.width() != mTmpBounds.width()
                    || outBounds.height() != mTmpBounds.height()) {
                // The app shouldn't be resized, we only do task letterboxing if the compat bounds
                // is also from the same task letterbox. Otherwise, clear the task bounds to show
                // app in size compat mode.
                outBounds.set(mTmpFullBounds);
            }
        }
    }

    Rect updateOverrideConfigurationFromLaunchBounds() {
        // If the task is controlled by another organized task, do not set override
        // configurations and let its parent (organized task) to control it;
@@ -3036,11 +2922,6 @@ class Task extends WindowContainer<WindowContainer> {
        return bounds;
    }

    @Nullable
    ActivityRecord getLastTaskBoundsComputeActivity() {
        return mLastTaskBoundsComputeActivity;
    }

    /** Updates the task's bounds and override configuration to match what is expected for the
     * input root task. */
    void updateOverrideConfigurationForRootTask(Task inRootTask) {
@@ -3939,12 +3820,6 @@ class Task extends WindowContainer<WindowContainer> {
                || activityType == ACTIVITY_TYPE_ASSISTANT;
    }

    boolean isTaskLetterboxed() {
        // No letterbox for multi window root task
        return !matchParentBounds()
                && (getWindowingMode() == WINDOWING_MODE_FULLSCREEN || !isRootTask());
    }

    @Override
    boolean fillsParent() {
        // From the perspective of policy, we still want to report that this task fills parent
+15 −7
Original line number Diff line number Diff line
@@ -3827,13 +3827,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    /** @return true when the window should be letterboxed. */
    boolean isLetterboxedAppWindow() {
        // Fullscreen mode but doesn't fill display area.
        return (!inMultiWindowMode() && !matchesDisplayAreaBounds())
        if (!inMultiWindowMode() && !matchesDisplayAreaBounds()) {
            return true;
        }
        if (mActivityRecord != null) {
            // Activity in size compat.
                || (mActivityRecord != null && mActivityRecord.inSizeCompatMode())
                // Task letterboxed.
                || (getTask() != null && getTask().isTaskLetterboxed())
            if (mActivityRecord.inSizeCompatMode()) {
                return true;
            }
            // Letterbox for fixed orientation.
            if (mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio()) {
                return true;
            }
        }
        // Letterboxed for display cutout.
                || isLetterboxedForDisplayCutout();
        return isLetterboxedForDisplayCutout();
    }

    /** Returns {@code true} if the window is letterboxed for the display cutout. */
+3 −2
Original line number Diff line number Diff line
@@ -555,9 +555,10 @@ public class ActivityRecordTests extends WindowTestsBase {
        activity.setRequestedOrientation(
                isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);

        // Asserts it has orientation derived from bounds.
        assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
        // Asserts it has orientation derived requested orientation (fixed orientation letterbox).
        assertEquals(isScreenPortrait ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE,
                activity.getConfiguration().orientation);
        assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
    }

    @Test
+17 −17
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
        final Rect activityBounds = new Rect(mFirstActivity.getBounds());

        // DAG is portrait (860x1200), so Task and Activity fill DAG.
        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
        assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
        assertThat(taskBounds).isEqualTo(dagBounds);
        assertThat(activityBounds).isEqualTo(taskBounds);
@@ -194,8 +194,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
        final Rect activityConfigBounds =
                new Rect(mFirstActivity.getConfiguration().windowConfiguration.getBounds());

        // DAG is landscape (1200x860), Task fills parent
        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
        // DAG is landscape (1200x860), no fixed orientation letterbox
        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
        assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
        assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
        assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
@@ -211,7 +211,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
    }

    @Test
    public void testLaunchLandscapeApp_taskIsLetterboxInDisplayAreaGroup() {
    public void testLaunchLandscapeApp_activityIsLetterboxForFixedOrientationInDisplayAreaGroup() {
        mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
@@ -221,17 +221,18 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
        final Rect taskBounds = new Rect(mFirstTask.getBounds());
        final Rect activityBounds = new Rect(mFirstActivity.getBounds());

        // DAG is portrait (860x1200), so Task is letterbox (860x[860x860/1200=616])
        assertThat(mFirstTask.isTaskLetterboxed()).isTrue();
        // DAG is portrait (860x1200), and activity is letterboxed for fixed orientation
        // (860x[860x860/1200=616]). Task fills DAG.
        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
        assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
        assertThat(taskBounds.width()).isEqualTo(dagBounds.width());
        assertThat(taskBounds.height())
        assertThat(taskBounds).isEqualTo(dagBounds);
        assertThat(activityBounds.width()).isEqualTo(dagBounds.width());
        assertThat(activityBounds.height())
                .isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height());
        assertThat(activityBounds).isEqualTo(taskBounds);
    }

    @Test
    public void testLaunchLandscapeApp_taskLetterboxBecomesActivityLetterboxAfterRotation() {
    public void testLaunchLandscapeApp_fixedOrientationLetterboxBecomesSizeCompatAfterRotation() {
        mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
@@ -245,9 +246,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
        final Rect newTaskBounds = new Rect(mFirstTask.getBounds());
        final Rect newActivityBounds = new Rect(mFirstActivity.getBounds());

        // DAG is landscape (1200x860), Task fills parent
        // Task letterbox size
        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
        // DAG is landscape (1200x860), no fixed orientation letterbox
        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
        assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
        assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
        assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
@@ -311,7 +311,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
    }

    @Test
    public void testResizableFixedOrientationApp_taskLevelLetterboxing() {
    public void testResizableFixedOrientationApp_fixedOrientationLetterboxing() {
        mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
        mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);

@@ -324,7 +324,7 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
        assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
        assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
        assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
        assertThat(mFirstActivity.inSizeCompatMode()).isFalse();

        // Launch portrait on second DAG
@@ -336,13 +336,13 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
        assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
        assertThat(mSecondRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
        assertThat(mSecondActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
        assertThat(mSecondTask.isTaskLetterboxed()).isFalse();
        assertThat(mSecondActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isFalse();
        assertThat(mSecondActivity.inSizeCompatMode()).isFalse();

        // First activity is letterboxed in portrait as requested.
        assertThat(mFirstRoot.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
        assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
        assertThat(mFirstTask.isTaskLetterboxed()).isTrue();
        assertThat(mFirstActivity.isLetterboxedForFixedOrientationAndAspectRatio()).isTrue();
        assertThat(mFirstActivity.inSizeCompatMode()).isFalse();

    }
Loading