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

Commit ccf45834 authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge "Reverse the requested orientation on DisplayAreaGroup"

parents e6e5c08f 2d560e69
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -1108,6 +1108,34 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
                || orientation == SCREEN_ORIENTATION_USER_PORTRAIT;
    }

    /**
     * Returns the reversed orientation.
     * @hide
     */
    @ActivityInfo.ScreenOrientation
    public static int reverseOrientation(@ActivityInfo.ScreenOrientation int orientation) {
        switch (orientation) {
            case SCREEN_ORIENTATION_LANDSCAPE:
                return SCREEN_ORIENTATION_PORTRAIT;
            case SCREEN_ORIENTATION_PORTRAIT:
                return SCREEN_ORIENTATION_LANDSCAPE;
            case SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
                return SCREEN_ORIENTATION_SENSOR_PORTRAIT;
            case SCREEN_ORIENTATION_SENSOR_PORTRAIT:
                return SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
            case SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
                return SCREEN_ORIENTATION_REVERSE_PORTRAIT;
            case SCREEN_ORIENTATION_REVERSE_PORTRAIT:
                return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
            case SCREEN_ORIENTATION_USER_LANDSCAPE:
                return SCREEN_ORIENTATION_USER_PORTRAIT;
            case SCREEN_ORIENTATION_USER_PORTRAIT:
                return SCREEN_ORIENTATION_USER_LANDSCAPE;
            default:
                return orientation;
        }
    }

    /**
     * Returns true if the activity supports picture-in-picture.
     * @hide
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import static android.content.pm.ActivityInfo.reverseOrientation;

import android.content.pm.ActivityInfo;
import android.graphics.Rect;

/** The root of a partition of the logical display. */
class DisplayAreaGroup extends RootDisplayArea {

    DisplayAreaGroup(WindowManagerService wms, String name, int featureId) {
        super(wms, name, featureId);
    }

    @Override
    boolean isOrientationDifferentFromDisplay() {
        if (mDisplayContent == null) {
            return false;
        }

        final Rect bounds = getBounds();
        final Rect displayBounds = mDisplayContent.getBounds();

        return (bounds.width() < bounds.height())
                != (displayBounds.width() < displayBounds.height());
    }

    @ActivityInfo.ScreenOrientation
    @Override
    int getOrientation(int candidate) {
        int orientation = super.getOrientation(candidate);

        // Reverse the requested orientation if the orientation of this DAG is different from the
        // display, so that when the display rotates to the reversed orientation, this DAG will be
        // in the requested orientation, so as the requested app.
        // For example, if the display is 1200x900 (landscape), and this DAG is 600x900 (portrait).
        // When an app below this DAG is requesting landscape, it should actually request the
        // display to be portrait, so that the DAG and the app will be in landscape.
        return isOrientationDifferentFromDisplay() ? reverseOrientation(orientation) : orientation;
    }
}
+12 −1
Original line number Diff line number Diff line
@@ -27,7 +27,8 @@ import java.util.Map;

/**
 * Root of a {@link DisplayArea} hierarchy. It can be either the {@link DisplayContent} as the root
 * of the whole logical display, or the root of a {@link DisplayArea} group.
 * of the whole logical display, or a {@link DisplayAreaGroup} as the root of a partition of the
 * logical display.
 */
class RootDisplayArea extends DisplayArea<DisplayArea> {

@@ -50,6 +51,16 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
        super(wms, Type.ANY, name, featureId);
    }

    @Override
    RootDisplayArea getRootDisplayArea() {
        return this;
    }

    /** Whether the orientation (based on dimensions) of this root is different from the Display. */
    boolean isOrientationDifferentFromDisplay() {
        return false;
    }

    /** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
    DisplayArea.Tokens findAreaForToken(WindowToken token) {
        int windowLayerFromType = token.getWindowLayerFromType();
+25 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
import static android.content.pm.ActivityInfo.reverseOrientation;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
@@ -809,6 +810,13 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        return parent != null ? parent.getDisplayArea() : null;
    }

    /** Get the first node of type {@link RootDisplayArea} above or at this node. */
    @Nullable
    RootDisplayArea getRootDisplayArea() {
        WindowContainer parent = getParent();
        return parent != null ? parent.getRootDisplayArea() : null;
    }

    boolean isAttached() {
        return getDisplayArea() != null;
    }
@@ -1154,17 +1162,30 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     *         {@link Configuration#ORIENTATION_UNDEFINED}).
     */
    int getRequestedConfigurationOrientation() {
        if (mOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
        int requestedOrientation = mOrientation;
        final RootDisplayArea root = getRootDisplayArea();
        if (root != null && root.isOrientationDifferentFromDisplay()) {
            // Reverse the requested orientation if the orientation of its root is different from
            // the display, so that when the display rotates to the reversed orientation, the
            // requested app will be in the requested orientation.
            // For example, if the display is 1200x900 (landscape), and the DAG is 600x900
            // (portrait).
            // When an app below the DAG is requesting landscape, it should actually request the
            // display to be portrait, so that the DAG and the app will be in landscape.
            requestedOrientation = reverseOrientation(mOrientation);
        }

        if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
            // NOSENSOR means the display's "natural" orientation, so return that.
            if (mDisplayContent != null) {
                return mDisplayContent.getNaturalOrientation();
            }
        } else if (mOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
        } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
            // LOCKED means the activity's orientation remains unchanged, so return existing value.
            return getConfiguration().orientation;
        } else if (isFixedOrientationLandscape(mOrientation)) {
        } else if (isFixedOrientationLandscape(requestedOrientation)) {
            return ORIENTATION_LANDSCAPE;
        } else if (isFixedOrientationPortrait(mOrientation)) {
        } else if (isFixedOrientationPortrait(requestedOrientation)) {
            return ORIENTATION_PORTRAIT;
        }
        return ORIENTATION_UNDEFINED;
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;

import static com.android.server.wm.WindowContainer.POSITION_TOP;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;

import android.platform.test.annotations.Presubmit;

import androidx.test.filters.SmallTest;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Tests for the {@link DisplayAreaGroup} container.
 *
 * Build/Install/Run:
 *  atest WmTests:DisplayAreaGroupTest
 */
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
public class DisplayAreaGroupTest extends WindowTestsBase {

    private DisplayAreaGroup mDisplayAreaGroup;
    private TaskDisplayArea mTaskDisplayArea;
    private Task mStack;
    private ActivityRecord mActivity;

    @Before
    public void setUp() {
        mDisplayAreaGroup = new DisplayAreaGroup(
                mWm, "DisplayAreaGroup", FEATURE_VENDOR_FIRST);
        final TaskDisplayArea defaultTda = mDisplayContent.getDefaultTaskDisplayArea();
        final WindowContainer parentDA = defaultTda.getParent();
        parentDA.addChild(mDisplayAreaGroup, parentDA.mChildren.indexOf(defaultTda) + 1);
        mTaskDisplayArea = new TaskDisplayArea(
                mDisplayContent, mWm, "TDA1", FEATURE_VENDOR_FIRST + 1);
        mDisplayAreaGroup.addChild(mTaskDisplayArea, POSITION_TOP);
        mStack = mTaskDisplayArea.createStack(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
        mActivity = new ActivityBuilder(mAtm).setCreateTask(true).setStack(mStack).build();
        mDisplayContent.setLastFocusedTaskDisplayArea(mTaskDisplayArea);
    }

    @Test
    public void testIsOrientationDifferentFromDisplay() {
        // Display is portrait, DisplayAreaGroup inherits that
        mDisplayContent.setBounds(0, 0, 600, 900);

        assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isFalse();

        // DisplayAreaGroup is landscape, different Display
        mDisplayAreaGroup.setBounds(0, 0, 600, 450);

        assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isTrue();

        // DisplayAreaGroup is portrait, same as Display
        mDisplayAreaGroup.setBounds(0, 0, 300, 900);

        assertThat(mDisplayAreaGroup.isOrientationDifferentFromDisplay()).isFalse();
    }

    @Test
    public void testGetOrientation() {
        doReturn(true).when(mDisplayContent).onDescendantOrientationChanged(any(), any());
        mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);

        // Display is portrait, DisplayAreaGroup inherits that
        mDisplayContent.setBounds(0, 0, 600, 900);

        assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
        assertThat(mActivity.getRequestedConfigurationOrientation())
                .isEqualTo(ORIENTATION_PORTRAIT);

        // DisplayAreaGroup is landscape, different from Display
        mDisplayAreaGroup.setBounds(0, 0, 600, 450);

        assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
        assertThat(mActivity.getRequestedConfigurationOrientation())
                .isEqualTo(ORIENTATION_LANDSCAPE);

        // DisplayAreaGroup is portrait, same as Display
        mDisplayAreaGroup.setBounds(0, 0, 300, 900);

        assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
        assertThat(mActivity.getRequestedConfigurationOrientation())
                .isEqualTo(ORIENTATION_PORTRAIT);
    }
}