diff options
3 files changed, 135 insertions, 61 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 78c066bdc212..4ddd7b8c3c8a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1637,7 +1637,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) { diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 6ef6fa7db740..fc99f4c9eef7 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -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; diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index de943d240084..06bcbf34e042 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -179,44 +179,6 @@ public class SizeCompatTests extends WindowTestsBase { } @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); setUpDisplaySizeWithApp(2000, 1000); @@ -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); @@ -389,13 +349,110 @@ public class SizeCompatTests extends WindowTestsBase { } @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); setUpDisplaySizeWithApp(2000, 1000); 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); |