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

Commit 3e4f8e1a authored by Chris Li's avatar Chris Li
Browse files

Task letterbox for resizable fixed-orientation app in dual DisplayAreas

Before, when both DisplayAreaGroups set ignoreOrientationRequest to
false, launching two resizable apps with different orientations will
end up with two apps in the same orientations. One app is in the
orientation different from its request.

This is because Task only letterboxes when ignoreOrientationRequest is
true, but it should also letterbox when the TaskDisplayArea can't
specify orientation (happens when it doesn't have focus).

Bug: 176566401
Test: atest WmTests:DualDisplayAreaGroupPolicyTest
Change-Id: I6f093f3c2631970fcc2fa839e5b394106e5acc29
parent 81eb4424
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -3329,6 +3329,14 @@ class Task extends WindowContainer<WindowContainer> {
        return false;
    }

    @Override
    boolean handlesOrientationChangeFromDescendant() {
        return super.handlesOrientationChangeFromDescendant()
                // Display won't rotate for the orientation request if the TaskDisplayArea can't
                // specify orientation.
                && getDisplayArea().canSpecifyOrientation();
    }

    void resize(boolean relayout, boolean forced) {
        if (setBounds(getRequestedOverrideBounds(), forced) != BOUNDS_CHANGE_NONE && relayout) {
            getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+0 −1
Original line number Diff line number Diff line
@@ -1902,7 +1902,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
    }

    /** Whether this task display area can request orientation. */
    @VisibleForTesting
    boolean canSpecifyOrientation() {
        // Only allow to specify orientation if this TDA is not set to ignore orientation request,
        // and it is the last focused one on this logical display that can request orientation
+38 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.SizeCompatTests.prepareLimitedBounds;
import static com.android.server.wm.SizeCompatTests.prepareUnresizable;
import static com.android.server.wm.SizeCompatTests.rotateDisplay;

@@ -309,6 +310,43 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
        assertThat(mSecondRoot.findAreaForToken(imeToken)).isEqualTo(imeContainer);
    }

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

        // Launch portrait on first DAG
        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
        prepareLimitedBounds(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT,
                false /* isUnresizable */);

        // Display in landscape (as opposite to DAG), first DAG and activity in portrait
        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.inSizeCompatMode()).isFalse();

        // Launch portrait on second DAG
        mDisplay.onLastFocusedTaskDisplayAreaChanged(mSecondTda);
        prepareLimitedBounds(mSecondActivity, SCREEN_ORIENTATION_LANDSCAPE,
                false /* isUnresizable */);

        // Display in portrait (as opposite to DAG), first DAG and activity in landscape
        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.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.inSizeCompatMode()).isFalse();

    }

    private void setupImeWindow() {
        final WindowState imeWindow = createWindow(null /* parent */,
                TYPE_INPUT_METHOD, mDisplay, "mImeWindow");
+21 −8
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
@@ -505,7 +506,7 @@ public class SizeCompatTests extends WindowTestsBase {

        compatTokens.clear();
        // Make the activity resizable again by restarting it
        activity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
        activity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
        activity.mVisibleRequested = true;
        activity.restartProcessIfVisible();
        // The full lifecycle isn't hooked up so manually set state to resumed
@@ -522,7 +523,7 @@ public class SizeCompatTests extends WindowTestsBase {
        setUpDisplaySizeWithApp(1000, 2500);

        // Make the task root resizable.
        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
        mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;

        // Create a size compat activity on the same task.
        final ActivityRecord activity = new ActivityBuilder(mAtm)
@@ -550,7 +551,7 @@ public class SizeCompatTests extends WindowTestsBase {
        setUpDisplaySizeWithApp(1000, 2500);

        // Make the task root resizable.
        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
        mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;

        // Create a size compat activity on the same task.
        final ActivityRecord activity = new ActivityBuilder(mAtm)
@@ -946,13 +947,25 @@ public class SizeCompatTests extends WindowTestsBase {
        prepareUnresizable(activity, -1 /* maxAspect */, screenOrientation);
    }

    /**
     * Setups {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or
     * orientation.
     */
    static void prepareUnresizable(ActivityRecord activity, float maxAspect,
            int screenOrientation) {
        activity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
        prepareLimitedBounds(activity, maxAspect, screenOrientation, true /* isUnresizable */);
    }

    static void prepareLimitedBounds(ActivityRecord activity, int screenOrientation,
            boolean isUnresizable) {
        prepareLimitedBounds(activity, -1 /* maxAspect */, screenOrientation, isUnresizable);
    }

    /**
     * Setups {@link #mActivity} with restriction on its bounds, such as maxAspect, fixed
     * orientation, and/or whether it is resizable.
     */
    static void prepareLimitedBounds(ActivityRecord activity, float maxAspect,
            int screenOrientation, boolean isUnresizable) {
        activity.info.resizeMode = isUnresizable
                ? RESIZE_MODE_UNRESIZEABLE
                : RESIZE_MODE_RESIZEABLE;
        activity.mVisibleRequested = true;
        if (maxAspect >= 0) {
            activity.info.maxAspectRatio = maxAspect;