Merge "Improve first opaque activity candidate detection" into udc-dev
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1717d24..cb7c7ae 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1640,7 +1640,7 @@
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 6ef6fa7..fc99f4c 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.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 @@
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 @@
// 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 @@
@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 @@
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 @@
* 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 @@
}
// In case mActivityRecord.hasCompatDisplayInsetsWithoutOverride() we don't apply the
// opaque activity constraints because we're expecting the activity is already letterboxed.
+ mFirstOpaqueActivityBeneath = mActivityRecord.getTask().getActivity(
+ FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE /* callback */,
+ mActivityRecord /* boundary */, false /* includeBoundary */,
+ true /* traverseTopToBottom */);
+ 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;
+ }
if (mActivityRecord.getTask() == null || mActivityRecord.fillsParent()
|| mActivityRecord.hasCompatDisplayInsetsWithoutInheritance()) {
return;
}
- final ActivityRecord firstOpaqueActivityBeneath = mActivityRecord.getTask().getActivity(
- FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE /* callback */,
- mActivityRecord /* boundary */, false /* includeBoundary */,
- true /* traverseTopToBottom */);
- if (firstOpaqueActivityBeneath == null || firstOpaqueActivityBeneath.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.
- return;
- }
- inheritConfiguration(firstOpaqueActivityBeneath);
+ 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 @@
// 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 @@
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 @@
}
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 de943d2..06bcbf3 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 @@
}
@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 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 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 @@
}
@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 @@
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 @@
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 @@
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);