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

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

Add option to always ignore orientation request

(2/n Orientation on DisplayAreaGroup)

When the option is set to true, the TDA will ignore all the
fixed-orientation request from apps.

This can be used on duo display device, so that the logical display will
not be rotated when launching a fixed-orientation app on one of the
display.

Bug: 155431879
Test: manual: test with dual-display-area policy
Test: atest WmTests:TaskDisplayAreaTests
Test: atest WmTests:WindowOrganizerTests
Change-Id: I3f0ea1415523926195b51fe28744974a9b64d803
parent f747948b
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -237,6 +237,22 @@ public final class WindowContainerTransaction implements Parcelable {
        return this;
    }

    /**
     * Sets whether a container should ignore the orientation request from apps below it. It
     * currently only applies to {@link com.android.server.wm.TaskDisplayArea}. When {@code false},
     * it may rotate based on the orientation request; When {@code true}, it can never specify
     * orientation, but shows the fixed-orientation apps in the letterbox.
     * @hide
     */
    @NonNull
    public WindowContainerTransaction setIgnoreOrientationRequest(
            @NonNull WindowContainerToken container, boolean ignoreOrientationRequest) {
        Change chg = getOrCreateChange(container.asBinder());
        chg.mIgnoreOrientationRequest = ignoreOrientationRequest;
        chg.mChangeMask |= Change.CHANGE_IGNORE_ORIENTATION_REQUEST;
        return this;
    }

    /**
     * Reparents a container into another one. The effect of a {@code null} parent can vary. For
     * example, reparenting a stack to {@code null} will reparent it to its display.
@@ -341,10 +357,12 @@ public final class WindowContainerTransaction implements Parcelable {
        public static final int CHANGE_PIP_CALLBACK = 1 << 2;
        public static final int CHANGE_HIDDEN = 1 << 3;
        public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4;
        public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5;

        private final Configuration mConfiguration = new Configuration();
        private boolean mFocusable = true;
        private boolean mHidden = false;
        private boolean mIgnoreOrientationRequest = false;
        private int mChangeMask = 0;
        private @ActivityInfo.Config int mConfigSetMask = 0;
        private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
@@ -362,6 +380,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mConfiguration.readFromParcel(in);
            mFocusable = in.readBoolean();
            mHidden = in.readBoolean();
            mIgnoreOrientationRequest = in.readBoolean();
            mChangeMask = in.readInt();
            mConfigSetMask = in.readInt();
            mWindowSetMask = in.readInt();
@@ -404,6 +423,9 @@ public final class WindowContainerTransaction implements Parcelable {
            if ((other.mChangeMask & CHANGE_HIDDEN) != 0) {
                mHidden = other.mHidden;
            }
            if ((other.mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
                mIgnoreOrientationRequest = other.mIgnoreOrientationRequest;
            }
            mChangeMask |= other.mChangeMask;
            if (other.mActivityWindowingMode >= 0) {
                mActivityWindowingMode = other.mActivityWindowingMode;
@@ -445,6 +467,15 @@ public final class WindowContainerTransaction implements Parcelable {
            return mHidden;
        }

        /** Gets the requested state of whether to ignore orientation request. */
        public boolean getIgnoreOrientationRequest() {
            if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) == 0) {
                throw new RuntimeException("IgnoreOrientationRequest not set. "
                        + "Check CHANGE_IGNORE_ORIENTATION_REQUEST first");
            }
            return mIgnoreOrientationRequest;
        }

        public int getChangeMask() {
            return mChangeMask;
        }
@@ -509,6 +540,9 @@ public final class WindowContainerTransaction implements Parcelable {
            if (mBoundsChangeTransaction != null) {
                sb.append("hasBoundsTransaction,");
            }
            if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
                sb.append("ignoreOrientationRequest:" + mIgnoreOrientationRequest + ",");
            }
            sb.append("}");
            return sb.toString();
        }
@@ -518,6 +552,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mConfiguration.writeToParcel(dest, flags);
            dest.writeBoolean(mFocusable);
            dest.writeBoolean(mHidden);
            dest.writeBoolean(mIgnoreOrientationRequest);
            dest.writeInt(mChangeMask);
            dest.writeInt(mConfigSetMask);
            dest.writeInt(mWindowSetMask);
+28 −3
Original line number Diff line number Diff line
@@ -151,6 +151,12 @@ final class TaskDisplayArea extends DisplayArea<Task> {
     */
    private boolean mRemoved;

    /**
     * Whether the task display area should ignore fixed-orientation request. If {@code true}, it
     * can never specify orientation, but show the fixed-orientation apps in the letterbox;
     * otherwise, it rotates based on the fixed-orientation request when it has the focus.
     */
    private boolean mIgnoreOrientationRequest;

    /**
     * The id of a leaf task that most recently being moved to front.
@@ -641,11 +647,30 @@ final class TaskDisplayArea extends DisplayArea<Task> {
        }
    }

    /**
     * Sets whether the task display area should ignore fixed-orientation request from apps.
     * @return Whether the display orientation changed
     */
    boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) {
        if (mIgnoreOrientationRequest == ignoreOrientationRequest) {
            return false;
        }

        mIgnoreOrientationRequest = ignoreOrientationRequest;
        if (isLastFocused()) {
            // Update orientation if this TDA is the last focused, otherwise it shouldn't affect
            // the display.
            return mDisplayContent.updateOrientation();
        }

        return false;
    }

    @Override
    int getOrientation(int candidate) {
        // Only allow to specify orientation if this TDA has the focus.
        // TODO(b/155431879) Add option to never allow a TDA to specify orientation.
        if (!isLastFocused()) {
        // Only allow to specify orientation if this TDA is not set to ignore orientation request,
        // and it has the focus.
        if (mIgnoreOrientationRequest || !isLastFocused()) {
            return SCREEN_ORIENTATION_UNSET;
        }

+16 −1
Original line number Diff line number Diff line
@@ -306,6 +306,19 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
        return effects;
    }

    private int applyTaskDisplayAreaChanges(TaskDisplayArea taskDisplayArea,
            WindowContainerTransaction.Change c) {
        int effects = applyDisplayAreaChanges(taskDisplayArea, c);
        if ((c.getChangeMask()
                & WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
            if (taskDisplayArea.setIgnoreOrientationRequest(c.getIgnoreOrientationRequest())) {
                effects |= TRANSACT_EFFECTS_LIFECYCLE;
            }
        }

        return effects;
    }

    private int applyDisplayAreaChanges(WindowContainer container,
            WindowContainerTransaction.Change c) {
        final int[] effects = new int[1];
@@ -388,7 +401,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub

        int effects = applyChanges(wc, c);

        if (wc instanceof DisplayArea) {
        if (wc instanceof TaskDisplayArea) {
            effects |= applyTaskDisplayAreaChanges((TaskDisplayArea) wc, c);
        } else if (wc instanceof DisplayArea) {
            effects |= applyDisplayAreaChanges(wc, c);
        } else if (wc instanceof Task) {
            effects |= applyTaskChanges(wc.asTask(), c);
+20 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ 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.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -277,6 +279,24 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
        assertThat(secondTaskDisplayArea.isLastFocused()).isTrue();
    }

    @Test
    public void testIgnoreOrientationRequest() {
        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
        final Task stack = taskDisplayArea.createStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
                .setStack(stack).build();

        mDisplayContent.setFocusedApp(activity);
        activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);

        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);

        taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);

        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
    }

    private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask,
            boolean reuseCandidate) {
        final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
+44 −0
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -42,6 +45,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
import static com.android.server.wm.WindowContainer.POSITION_TOP;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -360,6 +365,45 @@ public class WindowOrganizerTests extends WindowTestsBase {
        assertTrue(stack.shouldBeVisible(null));
    }

    @Test
    public void testSetIgnoreOrientationRequest() {
        removeGlobalMinSizeRestriction();
        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
        final Task stack = taskDisplayArea.createStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
                .setStack(stack).build();
        taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mDisplayContent.setFocusedApp(activity);
        activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);

        // TDA returns UNSET when ignoreOrientationRequest == true
        // DC is UNSPECIFIED because it is using the previous (default) when TDA returns UNSET.
        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
        assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);

        WindowContainerTransaction t = new WindowContainerTransaction();
        t.setIgnoreOrientationRequest(
                taskDisplayArea.mRemoteToken.toWindowContainerToken(),
                false /* ignoreOrientationRequest */);
        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);

        // TDA returns app request orientation when ignoreOrientationRequest == false
        // DC uses the same as TDA returns when it is not UNSET.
        assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);

        t.setIgnoreOrientationRequest(
                taskDisplayArea.mRemoteToken.toWindowContainerToken(),
                true /* ignoreOrientationRequest */);
        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);

        // TDA returns UNSET when ignoreOrientationRequest == true
        // DC is LANDSCAPE because it is using the previous when TDA returns UNSET.
        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
        assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
    }

    @Test
    public void testOverrideConfigSize() {
        removeGlobalMinSizeRestriction();