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

Commit 52b46fe5 authored by Massimo Carli's avatar Massimo Carli Committed by Automerger Merge Worker
Browse files

Merge "Improve first opaque activity candidate detection" into udc-dev am: 3d8f1668

parents 2d59c00d 3d8f1668
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1640,7 +1640,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            if (isState(RESUMED)) {
                newParent.setResumedActivity(this, "onParentChanged");
            }
            mLetterboxUiController.onActivityParentChanged(newParent);
            mLetterboxUiController.updateInheritedLetterbox();
        }

        if (rootTask != null && rootTask.topRunningActivity() == this) {
+36 −16
Original line number Diff line number Diff line
@@ -113,6 +113,8 @@ import com.android.internal.statusbar.LetterboxDetails;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
@@ -127,8 +129,7 @@ import java.util.function.Predicate;
final class LetterboxUiController {

    private static final Predicate<ActivityRecord> FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE =
            activityRecord -> activityRecord.fillsParent() && !activityRecord.isFinishing()
                    && activityRecord.nowVisible;
            activityRecord -> activityRecord.fillsParent() && !activityRecord.isFinishing();

    private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxUiController" : TAG_ATM;

@@ -180,6 +181,10 @@ final class LetterboxUiController {
    // Corresponds to OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS
    private final boolean mIsOverrideEnableCompatFakeFocusEnabled;

    // The list of observers for the destroy event of candidate opaque activities
    // when dealing with translucent activities.
    private final List<LetterboxUiController> mDestroyListeners = new ArrayList<>();

    @Nullable
    private final Boolean mBooleanPropertyAllowOrientationOverride;
    @Nullable
@@ -193,6 +198,10 @@ final class LetterboxUiController {
    @Nullable
    private WindowContainerListener mLetterboxConfigListener;

    @Nullable
    @VisibleForTesting
    ActivityRecord mFirstOpaqueActivityBeneath;

    private boolean mShowWallpaperForLetterboxBackground;

    // In case of transparent activities we might need to access the aspectRatio of the
@@ -353,6 +362,10 @@ final class LetterboxUiController {
            mLetterbox.destroy();
            mLetterbox = null;
        }
        for (int i = mDestroyListeners.size() - 1; i >= 0; i--) {
            mDestroyListeners.get(i).updateInheritedLetterbox();
        }
        mDestroyListeners.clear();
        if (mLetterboxConfigListener != null) {
            mLetterboxConfigListener.onRemoved();
            mLetterboxConfigListener = null;
@@ -1571,7 +1584,11 @@ final class LetterboxUiController {
     * first opaque activity beneath.
     * @param parent The parent container.
     */
    void onActivityParentChanged(WindowContainer<?> parent) {
    void updateInheritedLetterbox() {
        final WindowContainer<?> parent = mActivityRecord.getParent();
        if (parent == null) {
            return;
        }
        if (!mLetterboxConfiguration.isTranslucentLetterboxingEnabled()) {
            return;
        }
@@ -1581,22 +1598,24 @@ final class LetterboxUiController {
        }
        // In case mActivityRecord.hasCompatDisplayInsetsWithoutOverride() we don't apply the
        // opaque activity constraints because we're expecting the activity is already letterboxed.
        if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent()
                || mActivityRecord.hasCompatDisplayInsetsWithoutInheritance()) {
            return;
        }
        final ActivityRecord firstOpaqueActivityBeneath = mActivityRecord.getTask().getActivity(
        mFirstOpaqueActivityBeneath = mActivityRecord.getTask().getActivity(
                FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE /* callback */,
                mActivityRecord /* boundary */, false /* includeBoundary */,
                true /* traverseTopToBottom */);
        if (firstOpaqueActivityBeneath == null || firstOpaqueActivityBeneath.isEmbedded()) {
        if (mFirstOpaqueActivityBeneath == null || mFirstOpaqueActivityBeneath.isEmbedded()) {
            // 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;
        }
        inheritConfiguration(firstOpaqueActivityBeneath);
        if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent()
                || mActivityRecord.hasCompatDisplayInsetsWithoutInheritance()) {
            return;
        }
        mFirstOpaqueActivityBeneath.mLetterboxUiController.mDestroyListeners.add(this);
        inheritConfiguration(mFirstOpaqueActivityBeneath);
        mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation(
                mActivityRecord, firstOpaqueActivityBeneath,
                mActivityRecord, mFirstOpaqueActivityBeneath,
                (opaqueConfig, transparentOverrideConfig) -> {
                    resetTranslucentOverrideConfig(transparentOverrideConfig);
                    final Rect parentBounds = parent.getWindowConfiguration().getBounds();
@@ -1610,7 +1629,7 @@ final class LetterboxUiController {
                    // We need to initialize appBounds to avoid NPE. The actual value will
                    // be set ahead when resolving the Configuration for the activity.
                    transparentOverrideConfig.windowConfiguration.setAppBounds(new Rect());
                    inheritConfiguration(firstOpaqueActivityBeneath);
                    inheritConfiguration(mFirstOpaqueActivityBeneath);
                    return transparentOverrideConfig;
                });
    }
@@ -1684,10 +1703,7 @@ final class LetterboxUiController {
        if (!hasInheritedLetterboxBehavior() || mActivityRecord.getTask() == null) {
            return Optional.empty();
        }
        return Optional.ofNullable(mActivityRecord.getTask().getActivity(
                FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE /* callback */,
                mActivityRecord /* boundary */, false /* includeBoundary */,
                true /* traverseTopToBottom */));
        return Optional.ofNullable(mFirstOpaqueActivityBeneath);
    }

    /** Resets the screen size related fields so they can be resolved by requested bounds later. */
@@ -1718,6 +1734,10 @@ final class LetterboxUiController {
    }

    private void clearInheritedConfig() {
        if (mFirstOpaqueActivityBeneath != null) {
            mFirstOpaqueActivityBeneath.mLetterboxUiController.mDestroyListeners.remove(this);
        }
        mFirstOpaqueActivityBeneath = null;
        mLetterboxConfigListener = null;
        mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO;
        mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO;
+98 −44
Original line number Diff line number Diff line
@@ -178,44 +178,6 @@ public class SizeCompatTests extends WindowTestsBase {
        setUpApp(builder.build());
    }

    @Test
    public void testActivityInHistoryAndNotVisibleIsNotUsedAsOpaqueForTranslucentActivities() {
        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
        setUpDisplaySizeWithApp(2000, 1000);
        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mActivity.nowVisible = false;
        // Translucent Activity
        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .build();
        doReturn(false).when(translucentActivity).fillsParent();

        mTask.addChild(translucentActivity);

        assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
    }

    @Test
    public void testActivityInHistoryAndVisibleIsUsedAsOpaqueForTranslucentActivities() {
        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
        setUpDisplaySizeWithApp(2000, 1000);
        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mActivity.nowVisible = true;
        // Translucent Activity
        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .build();
        doReturn(false).when(translucentActivity).fillsParent();

        mTask.addChild(translucentActivity);

        assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
    }

    @Test
    public void testCleanLetterboxConfigListenerWhenTranslucentIsDestroyed() {
        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
@@ -240,7 +202,6 @@ public class SizeCompatTests extends WindowTestsBase {
    public void testHorizontalReachabilityEnabledForTranslucentActivities() {
        setUpDisplaySizeWithApp(2500, 1000);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mActivity.nowVisible = true;
        final LetterboxConfiguration config = mWm.mLetterboxConfiguration;
        config.setTranslucentLetterboxingOverrideEnabled(true);
        config.setLetterboxHorizontalPositionMultiplier(0.5f);
@@ -316,7 +277,6 @@ public class SizeCompatTests extends WindowTestsBase {
    public void testVerticalReachabilityEnabledForTranslucentActivities() {
        setUpDisplaySizeWithApp(1000, 2500);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mActivity.nowVisible = true;
        final LetterboxConfiguration config = mWm.mLetterboxConfiguration;
        config.setTranslucentLetterboxingOverrideEnabled(true);
        config.setLetterboxVerticalPositionMultiplier(0.5f);
@@ -388,6 +348,104 @@ public class SizeCompatTests extends WindowTestsBase {
        checkIsCentered.run();
    }

    @Test
    public void testApplyStrategyAgainWhenOpaqueIsDestroyed() {
        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
        setUpDisplaySizeWithApp(2000, 1000);
        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        // Launch another opaque activity
        final ActivityRecord opaqueActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .build();
        mTask.addChild(opaqueActivity);
        // Transparent activity strategy not applied
        assertFalse(opaqueActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());

        // Launch translucent Activity
        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .build();
        doReturn(false).when(translucentActivity).fillsParent();
        mTask.addChild(translucentActivity);
        // Transparent strategy applied
        assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());

        spyOn(translucentActivity.mLetterboxUiController);
        clearInvocations(translucentActivity.mLetterboxUiController);

        // We destroy the first opaque activity
        opaqueActivity.setState(DESTROYED, "testing");
        opaqueActivity.removeImmediately();

        // Check that updateInheritedLetterbox() is invoked again
        verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox();
    }

    @Test
    public void testResetOpaqueReferenceWhenOpaqueIsDestroyed() {
        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
        setUpDisplaySizeWithApp(2000, 1000);
        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);

        // Launch translucent Activity
        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .build();
        doReturn(false).when(translucentActivity).fillsParent();
        mTask.addChild(translucentActivity);
        // Transparent strategy applied
        assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());
        assertNotNull(translucentActivity.mLetterboxUiController.mFirstOpaqueActivityBeneath);

        spyOn(translucentActivity.mLetterboxUiController);
        clearInvocations(translucentActivity.mLetterboxUiController);

        // We destroy the first opaque activity
        mActivity.setState(DESTROYED, "testing");
        mActivity.removeImmediately();

        // Check that updateInheritedLetterbox() is invoked again
        verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox();
        assertNull(translucentActivity.mLetterboxUiController.mFirstOpaqueActivityBeneath);
    }

    @Test
    public void testNotApplyStrategyAgainWhenOpaqueIsNotDestroyed() {
        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
        setUpDisplaySizeWithApp(2000, 1000);
        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        // Launch another opaque activity
        final ActivityRecord opaqueActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .build();
        mTask.addChild(opaqueActivity);
        // Transparent activity strategy not applied
        assertFalse(opaqueActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());

        // Launch translucent Activity
        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .build();
        doReturn(false).when(translucentActivity).fillsParent();
        mTask.addChild(translucentActivity);
        // Transparent strategy applied
        assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior());

        spyOn(translucentActivity.mLetterboxUiController);
        clearInvocations(translucentActivity.mLetterboxUiController);

        // Check that updateInheritedLetterbox() is invoked again
        verify(translucentActivity.mLetterboxUiController, never()).updateInheritedLetterbox();
    }

    @Test
    public void testApplyStrategyToTranslucentActivities() {
        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
@@ -395,7 +453,6 @@ public class SizeCompatTests extends WindowTestsBase {
        prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
        mActivity.info.setMinAspectRatio(1.2f);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mActivity.nowVisible = true;
        // Translucent Activity
        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
@@ -456,7 +513,6 @@ public class SizeCompatTests extends WindowTestsBase {
        prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
        mActivity.info.setMinAspectRatio(1.2f);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mActivity.nowVisible = true;
        // Translucent Activity
        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
                .setLaunchedFromUid(mActivity.getUid())
@@ -550,7 +606,6 @@ public class SizeCompatTests extends WindowTestsBase {
                true /* ignoreOrientationRequest */);
        mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(
                1.0f /*letterboxVerticalPositionMultiplier*/);
        mActivity.nowVisible = true;
        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
        // We launch a transparent activity
        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm)
@@ -583,7 +638,6 @@ public class SizeCompatTests extends WindowTestsBase {
        mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true);
        setUpDisplaySizeWithApp(2800, 1400);
        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
        mActivity.nowVisible = true;
        prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
        // Rotate to put activity in size compat mode.
        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);