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

Commit 56c4d530 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Do not apply transparent policy if orientation is respected

On device with config_letterboxIsEnabledForTranslucentActivities=true,
the translucent activity will inherit the configuration of opaque
activity in the same task.

But if the orientation of activity can affect display, i.e.
ignore-orientation is not set (such as outer screen of foldable device),
then ideally the behavior should be similar to regular phone.

This change makes that it is possible to switch between inherit and
non-inherit at runtime. The TransparentPolicy is still initialized
if AppCompatConfiguration#isTranslucentLetterboxingEnabled is true.
But its configuration override policy will be no-op if the translucent
activity can affect display orientation. And once the display becomes
ignoring requested orientation, the policy can still apply the override
from the existed info.

That allows the scenario:
On folded screen, a task contains a top portrait translucent activity.
And the bottom activity is visible with fixed landscape orientation.
After switching to unfold display, the translucent activity will
follow the bottom activity's bounds and orientation.

Bug: 278097747
Flag: com.android.window.flags.respect_non_top_visible_fixed_orientation
Test: atest TransparentPolicyTest# \
      testNotRunStrategyToTranslucentActivitiesIfRespectOrientation

Change-Id: Id9861c908420961efb945e36fb50a13ea4de7e8f
parent aa960910
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -1804,9 +1804,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            return;
        }
        final int displayRotation = getRotation();
        final int rotation = ar.isVisible()
                ? ar.getWindowConfiguration().getDisplayRotation()
                : mDisplayRotation.rotationForOrientation(orientation, displayRotation);
        final int rotation = mDisplayRotation.rotationForOrientation(orientation, displayRotation);
        if (rotation == displayRotation) {
            return;
        }
@@ -6710,6 +6708,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        final boolean rotationChanged = super.setIgnoreOrientationRequest(ignoreOrientationRequest);
        mWmService.mDisplayWindowSettings.setIgnoreOrientationRequest(
                this, mSetIgnoreOrientationRequest);
        if (ignoreOrientationRequest && mWmService.mFlags.mRespectNonTopVisibleFixedOrientation) {
            forAllActivities(r -> {
                r.finishFixedRotationTransform();
            });
        }
        return rotationChanged;
    }

+0 −1
Original line number Diff line number Diff line
@@ -1239,7 +1239,6 @@ public class DisplayRotation {
     * @param lastRotation The most recently used rotation.
     * @return The surface rotation to use.
     */
    @VisibleForTesting
    @Surface.Rotation
    int rotationForOrientation(@ScreenOrientation int orientation,
            @Surface.Rotation int lastRotation) {
+19 −2
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ class TransparentPolicy {
        if (parent == null) {
            return;
        }
        final boolean wasStarted = mTransparentPolicyState.isRunning();
        mTransparentPolicyState.reset();
        // In case mActivityRecord.hasCompatDisplayInsetsWithoutOverride() we don't apply the
        // opaque activity constraints because we're expecting the activity is already letterboxed.
@@ -102,6 +103,9 @@ class TransparentPolicy {
        // We check if we need for some reason to skip the policy gievn the specific first
        // opaque activity
        if (shouldSkipTransparentPolicy(firstOpaqueActivity)) {
            if (wasStarted) {
                mActivityRecord.recomputeConfiguration();
            }
            return;
        }
        mTransparentPolicyState.start(firstOpaqueActivity);
@@ -190,7 +194,6 @@ class TransparentPolicy {
            // We skip letterboxing if the translucent activity doesn't have any
            // opaque activities beneath or the activity below is embedded which
            // never has letterbox.
            mActivityRecord.recomputeConfiguration();
            return true;
        }
        if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent()
@@ -260,6 +263,10 @@ class TransparentPolicy {
            mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation(
                    mActivityRecord, mFirstOpaqueActivity,
                    (opaqueConfig, transparentOverrideConfig) -> {
                        if (!isPolicyEnabled()) {
                            transparentOverrideConfig.unset();
                            return transparentOverrideConfig;
                        }
                        resetTranslucentOverrideConfig(transparentOverrideConfig);
                        final Rect parentBounds = parent.getWindowConfiguration().getBounds();
                        final Rect bounds = transparentOverrideConfig
@@ -313,7 +320,17 @@ class TransparentPolicy {
        }

        private boolean isRunning() {
            return mLetterboxConfigListener != null;
            return mLetterboxConfigListener != null && isPolicyEnabled();
        }

        private boolean isPolicyEnabled() {
            if (!mActivityRecord.mWmService.mFlags.mRespectNonTopVisibleFixedOrientation) {
                return true;
            }
            // Do not enable the policy if the activity can affect display orientation.
            final int orientation = mActivityRecord.getOverrideOrientation();
            return orientation == SCREEN_ORIENTATION_UNSPECIFIED
                    || !mActivityRecord.handlesOrientationChangeFromDescendant(orientation);
        }

        private void clearInheritedCompatDisplayInsets() {
+4 −0
Original line number Diff line number Diff line
@@ -62,6 +62,10 @@ class AppCompatTransparentActivityRobot {
        consumer.accept(mActivityRobot);
    }

    void setDisplayContentBounds(int left, int top, int right, int bottom) {
        mActivityRobot.displayContent().setBounds(left, top, right, bottom);
    }

    void launchTransparentActivity() {
        mActivityRobot.launchActivity(/*minAspectRatio */ -1, /* maxAspectRatio */ -1,
                SCREEN_ORIENTATION_PORTRAIT, /* transparent */ true,
+20 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.view.Surface.ROTATION_90;

import static org.mockito.Mockito.clearInvocations;

import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;

import androidx.annotation.NonNull;
@@ -207,6 +208,25 @@ public class TransparentPolicyTest extends WindowTestsBase {
        });
    }

    @EnableFlags(com.android.window.flags.Flags.FLAG_RESPECT_NON_TOP_VISIBLE_FIXED_ORIENTATION)
    @Test
    public void testNotRunStrategyToTranslucentActivitiesIfRespectOrientation() {
        runTestScenario(robot -> robot.transparentActivity(ta -> ta.applyOnActivity((a) -> {
            a.configureTopActivityIgnoreOrientationRequest(false);
            // The translucent activity is SCREEN_ORIENTATION_PORTRAIT.
            ta.launchTransparentActivityInTask();
            // Though TransparentPolicyState will be started, it won't be considered as running.
            ta.checkTopActivityTransparentPolicyStateIsRunning(/* running */ false);

            // If the display changes to ignore orientation request, e.g. unfold, the policy should
            // take effect.
            a.configureTopActivityIgnoreOrientationRequest(true);
            ta.checkTopActivityTransparentPolicyStateIsRunning(/* running */ true);
            ta.setDisplayContentBounds(0, 0, 900, 1800);
            ta.checkTopActivityHasInheritedBoundsFrom(/* fromTop */ 1);
        })), /* displayWidth */ 500,  /* displayHeight */ 1000);
    }

    @Test
    public void testTranslucentActivitiesDontGoInSizeCompatMode() {
        runTestScenario((robot) -> {