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

Commit 888711ae authored by Chris Li's avatar Chris Li
Browse files

Fix letterbox and orientation request on DisplayAreaGroup

Before, with a multi displayarea policy setting, fixed-orientation app
may have incorrect bounds.

1. CompatDisplayInsets: use RootDisplayArea bounds as the mWidth and
   mHeight
2. onDescendantOrientationChanged: stop calling super method if ignore,
   otherwise it can return true from DC even though DAG is ignored. We
   want it to be hanled by Task in such case.
3. DAG should adjust the configuration orientation based on its
   dimensions, so a width > height DAG is considered landscape.
4. getRequestedConfigurationOrientation() should only reverse the
   orientation at DC level, so that Task and ActivityRecord can handle
   the bounds based on the request correctly.
5. Compare app bounds with RootDisplayArea bounds to check whether it
   is letterboxed.

Bug: 155431879
Test: manual: test with a dual displayarea policy
Test: atest WmTests:SizeCompatTests
Test: atest WmTests:DisplayAreaTest
Test: atest WmTests:DisplayAreaGroupTest
Change-Id: I16277cb9984c87ed4bcd50b91e0d12c2c6bbd5b1
parent b4e9dc0a
Loading
Loading
Loading
Loading
+29 −7
Original line number Diff line number Diff line
@@ -7774,15 +7774,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                return;
            }

            if (container.getTask().isTaskLetterboxed()) {
            final Task task = container.getTask();
            if (task != null && task.isTaskLetterboxed()) {
                // For apps in Task letterbox, it should fill the task bounds.
                final Rect taskBounds = container.getTask().getBounds();
                mWidth = taskBounds.width();
                mHeight = taskBounds.height();
                final Point dimensions = getRotationZeroDimensions(task);
                mWidth = dimensions.x;
                mHeight = dimensions.y;
            } else {
                // If the activity is not floating nor letterboxed, assume it fills the display.
                // If the activity is not floating nor letterboxed, assume it fills the root.
                final RootDisplayArea root = container.getRootDisplayArea();
                if (root == null || root == display) {
                    mWidth = display.mBaseDisplayWidth;
                    mHeight = display.mBaseDisplayHeight;
                } else {
                    final Point dimensions = getRotationZeroDimensions(root);
                    mWidth = dimensions.x;
                    mHeight = dimensions.y;
                }
            }
            final DisplayPolicy policy = display.getDisplayPolicy();
            for (int rotation = 0; rotation < 4; rotation++) {
@@ -7799,6 +7807,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            }
        }

        /**
         * Gets the width and height of the {@code container} when it is not rotated, so that after
         * the display is rotated, we can calculate the bounds by rotating the dimensions.
         * @see #getBoundsByRotation
         */
        private static Point getRotationZeroDimensions(WindowContainer container) {
            final Rect bounds = container.getBounds();
            final int rotation = container.getConfiguration().windowConfiguration.getRotation();
            final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
            final int width = bounds.width();
            final int height = bounds.height();
            return rotated ? new Point(height, width) : new Point(width, height);
        }

        void getBoundsByRotation(Rect outBounds, int rotation) {
            final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
            final int dw = rotated ? mHeight : mWidth;
+10 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
import android.window.DisplayAreaInfo;
import android.window.IDisplayAreaOrganizer;
@@ -149,6 +150,15 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
        return !mIgnoreOrientationRequest && super.handlesOrientationChangeFromDescendant();
    }

    @Override
    boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
            WindowContainer requestingContainer) {
        // If this is set to ignore the orientation request, we don't propagate descendant
        // orientation request.
        return !mIgnoreOrientationRequest
                && super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
    }

    /**
     * Sets whether this {@link DisplayArea} should ignore fixed-orientation request from apps and
     * windows below it.
+42 −2
Original line number Diff line number Diff line
@@ -17,8 +17,12 @@
package com.android.server.wm;

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;

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

/** The root of a partition of the logical display. */
@@ -30,13 +34,19 @@ class DisplayAreaGroup extends RootDisplayArea {

    @Override
    boolean isOrientationDifferentFromDisplay() {
        return isOrientationDifferentFromDisplay(getBounds());
    }

    /**
     * Whether the orientation should be different from the {@link DisplayContent}.
     * @param bounds the bounds of this DAG.
     */
    private boolean isOrientationDifferentFromDisplay(Rect bounds) {
        if (mDisplayContent == null) {
            return false;
        }

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

        return (bounds.width() < bounds.height())
                != (displayBounds.width() < displayBounds.height());
    }
@@ -54,4 +64,34 @@ class DisplayAreaGroup extends RootDisplayArea {
        // display to be portrait, so that the DAG and the app will be in landscape.
        return isOrientationDifferentFromDisplay() ? reverseOrientation(orientation) : orientation;
    }

    @Override
    void resolveOverrideConfiguration(Configuration newParentConfiguration) {
        super.resolveOverrideConfiguration(newParentConfiguration);
        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
        if (resolvedConfig.orientation != ORIENTATION_UNDEFINED) {
            // Don't change the orientation if it is requested on this window.
            return;
        }

        // Use the override bounds because getBounds() may not be merged yet.
        Rect overrideBounds = resolvedConfig.windowConfiguration.getBounds();
        // It should fill parent if there is no override bounds.
        overrideBounds = overrideBounds.isEmpty()
                ? newParentConfiguration.windowConfiguration.getBounds()
                : overrideBounds;
        // Resolve the DAG orientation:
        // If the orientation of this DAG should always be different from the display based on their
        // dimensions, we need to reverse the config orientation.
        // For example, if the display is 1200x900 (landscape), and this DAG is 600x900 (portrait).
        // The orientation from the Display will be landscape, but we want to reverse it to be
        // portrait for the DAG and its children.
        if (isOrientationDifferentFromDisplay(overrideBounds)) {
            if (newParentConfiguration.orientation == ORIENTATION_PORTRAIT) {
                resolvedConfig.orientation = ORIENTATION_LANDSCAPE;
            } else if (newParentConfiguration.orientation == ORIENTATION_LANDSCAPE) {
                resolvedConfig.orientation = ORIENTATION_PORTRAIT;
            }
        }
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -1430,8 +1430,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
            return ROTATION_UNDEFINED;
        }
        if (r.inMultiWindowMode()
                || r.getRequestedConfigurationOrientation() == getConfiguration().orientation) {
        if (r.inMultiWindowMode() || r.getRequestedConfigurationOrientation(true /* forDisplay */)
                == getConfiguration().orientation) {
            return ROTATION_UNDEFINED;
        }
        final int currentRotation = getRotation();
@@ -5496,7 +5496,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
         */
        boolean isTopFixedOrientationRecentsAnimating() {
            return mAnimatingRecents != null
                    && mAnimatingRecents.getRequestedConfigurationOrientation()
                    && mAnimatingRecents.getRequestedConfigurationOrientation(true /* forDisplay */)
                    != ORIENTATION_UNDEFINED && !hasTopFixedRotationLaunchingApp();
        }

+19 −2
Original line number Diff line number Diff line
@@ -1169,7 +1169,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
    }

    /**
     * Get the configuration orientation by the requested screen orientation
     * Gets the configuration orientation by the requested screen orientation
     * ({@link ActivityInfo.ScreenOrientation}) of this activity.
     *
     * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
@@ -1177,9 +1177,26 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
     *         {@link Configuration#ORIENTATION_UNDEFINED}).
     */
    int getRequestedConfigurationOrientation() {
        return getRequestedConfigurationOrientation(false /* forDisplay */);
    }

    /**
     * Gets the configuration orientation by the requested screen orientation
     * ({@link ActivityInfo.ScreenOrientation}) of this activity.
     *
     * @param forDisplay whether it is the requested config orientation for display.
     *                   If {@code true}, we may reverse the requested orientation if the 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.
     * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
     *         {@link Configuration#ORIENTATION_PORTRAIT},
     *         {@link Configuration#ORIENTATION_UNDEFINED}).
     */
    int getRequestedConfigurationOrientation(boolean forDisplay) {
        int requestedOrientation = mOrientation;
        final RootDisplayArea root = getRootDisplayArea();
        if (root != null && root.isOrientationDifferentFromDisplay()) {
        if (forDisplay && 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.
Loading