Loading services/core/java/com/android/server/wm/ActivityRecord.java +7 −1 Original line number Diff line number Diff line Loading @@ -8293,8 +8293,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void recomputeConfiguration() { // We check if the current activity is transparent. In that case we need to // recomputeConfiguration of the first opaque activity beneath, to allow a // proper computation of the new bounds. if (!mLetterboxUiController.applyOnOpaqueActivityBelow( ActivityRecord::recomputeConfiguration)) { onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration()); } } boolean isInTransition() { return inTransitionSelfOrParent(); Loading services/core/java/com/android/server/wm/LetterboxUiController.java +29 −0 Original line number Diff line number Diff line Loading @@ -81,6 +81,7 @@ import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTy import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.TaskDescription; import android.content.pm.ActivityInfo.ScreenOrientation; Loading @@ -104,7 +105,9 @@ import com.android.internal.statusbar.LetterboxDetails; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; import java.io.PrintWriter; import java.util.Optional; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Predicate; /** Controls behaviour of the letterbox UI for {@link mActivityRecord}. */ Loading Loading @@ -1471,6 +1474,32 @@ final class LetterboxUiController { return mInheritedCompatDisplayInsets; } /** * In case of translucent activities, it consumes the {@link ActivityRecord} of the first opaque * activity beneath using the given consumer and returns {@code true}. */ boolean applyOnOpaqueActivityBelow(@NonNull Consumer<ActivityRecord> consumer) { return findOpaqueNotFinishingActivityBelow() .map(activityRecord -> { consumer.accept(activityRecord); return true; }).orElse(false); } /** * @return The first not finishing opaque activity beneath the current translucent activity * if it exists and the strategy is enabled. */ private Optional<ActivityRecord> findOpaqueNotFinishingActivityBelow() { 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 */)); } private void inheritConfiguration(ActivityRecord firstOpaque) { // To avoid wrong behaviour, we're not forcing a specific aspet ratio to activities // which are not already providing one (e.g. permission dialogs) and presumably also Loading services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +39 −4 Original line number Diff line number Diff line Loading @@ -270,6 +270,35 @@ public class SizeCompatTests extends WindowTestsBase { verify(mActivity).isFinishing(); } @Test public void testTranslucentActivitiesWhenUnfolding() { mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); setUpDisplaySizeWithApp(2800, 1400); mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( 1.0f /*letterboxVerticalPositionMultiplier*/); prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); // We launch a transparent activity final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) .setLaunchedFromUid(mActivity.getUid()) .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) .build(); doReturn(false).when(translucentActivity).fillsParent(); mTask.addChild(translucentActivity); mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); spyOn(mActivity); // Halffold setFoldablePosture(translucentActivity, true /* isHalfFolded */, false /* isTabletop */); verify(mActivity).recomputeConfiguration(); clearInvocations(mActivity); // Unfold setFoldablePosture(translucentActivity, false /* isHalfFolded */, false /* isTabletop */); verify(mActivity).recomputeConfiguration(); } @Test public void testRestartProcessIfVisible() { setUpDisplaySizeWithApp(1000, 2500); Loading Loading @@ -3339,14 +3368,20 @@ public class SizeCompatTests extends WindowTestsBase { } private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) { final DisplayRotation r = mActivity.mDisplayContent.getDisplayRotation(); private void setFoldablePosture(ActivityRecord activity, boolean isHalfFolded, boolean isTabletop) { final DisplayRotation r = activity.mDisplayContent.getDisplayRotation(); doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge(); doReturn(false).when(r).isDeviceInPosture(any(DeviceState.class), anyBoolean()); if (isHalfFolded) { doReturn(true).when(r).isDeviceInPosture(DeviceState.HALF_FOLDED, isTabletop); doReturn(true).when(r) .isDeviceInPosture(DeviceState.HALF_FOLDED, isTabletop); } mActivity.recomputeConfiguration(); activity.recomputeConfiguration(); } private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) { setFoldablePosture(mActivity, isHalfFolded, isTabletop); } @Test Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +7 −1 Original line number Diff line number Diff line Loading @@ -8293,8 +8293,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void recomputeConfiguration() { // We check if the current activity is transparent. In that case we need to // recomputeConfiguration of the first opaque activity beneath, to allow a // proper computation of the new bounds. if (!mLetterboxUiController.applyOnOpaqueActivityBelow( ActivityRecord::recomputeConfiguration)) { onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration()); } } boolean isInTransition() { return inTransitionSelfOrParent(); Loading
services/core/java/com/android/server/wm/LetterboxUiController.java +29 −0 Original line number Diff line number Diff line Loading @@ -81,6 +81,7 @@ import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTy import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.TaskDescription; import android.content.pm.ActivityInfo.ScreenOrientation; Loading @@ -104,7 +105,9 @@ import com.android.internal.statusbar.LetterboxDetails; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; import java.io.PrintWriter; import java.util.Optional; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Predicate; /** Controls behaviour of the letterbox UI for {@link mActivityRecord}. */ Loading Loading @@ -1471,6 +1474,32 @@ final class LetterboxUiController { return mInheritedCompatDisplayInsets; } /** * In case of translucent activities, it consumes the {@link ActivityRecord} of the first opaque * activity beneath using the given consumer and returns {@code true}. */ boolean applyOnOpaqueActivityBelow(@NonNull Consumer<ActivityRecord> consumer) { return findOpaqueNotFinishingActivityBelow() .map(activityRecord -> { consumer.accept(activityRecord); return true; }).orElse(false); } /** * @return The first not finishing opaque activity beneath the current translucent activity * if it exists and the strategy is enabled. */ private Optional<ActivityRecord> findOpaqueNotFinishingActivityBelow() { 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 */)); } private void inheritConfiguration(ActivityRecord firstOpaque) { // To avoid wrong behaviour, we're not forcing a specific aspet ratio to activities // which are not already providing one (e.g. permission dialogs) and presumably also Loading
services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +39 −4 Original line number Diff line number Diff line Loading @@ -270,6 +270,35 @@ public class SizeCompatTests extends WindowTestsBase { verify(mActivity).isFinishing(); } @Test public void testTranslucentActivitiesWhenUnfolding() { mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); setUpDisplaySizeWithApp(2800, 1400); mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( 1.0f /*letterboxVerticalPositionMultiplier*/); prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); // We launch a transparent activity final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) .setLaunchedFromUid(mActivity.getUid()) .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) .build(); doReturn(false).when(translucentActivity).fillsParent(); mTask.addChild(translucentActivity); mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); spyOn(mActivity); // Halffold setFoldablePosture(translucentActivity, true /* isHalfFolded */, false /* isTabletop */); verify(mActivity).recomputeConfiguration(); clearInvocations(mActivity); // Unfold setFoldablePosture(translucentActivity, false /* isHalfFolded */, false /* isTabletop */); verify(mActivity).recomputeConfiguration(); } @Test public void testRestartProcessIfVisible() { setUpDisplaySizeWithApp(1000, 2500); Loading Loading @@ -3339,14 +3368,20 @@ public class SizeCompatTests extends WindowTestsBase { } private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) { final DisplayRotation r = mActivity.mDisplayContent.getDisplayRotation(); private void setFoldablePosture(ActivityRecord activity, boolean isHalfFolded, boolean isTabletop) { final DisplayRotation r = activity.mDisplayContent.getDisplayRotation(); doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge(); doReturn(false).when(r).isDeviceInPosture(any(DeviceState.class), anyBoolean()); if (isHalfFolded) { doReturn(true).when(r).isDeviceInPosture(DeviceState.HALF_FOLDED, isTabletop); doReturn(true).when(r) .isDeviceInPosture(DeviceState.HALF_FOLDED, isTabletop); } mActivity.recomputeConfiguration(); activity.recomputeConfiguration(); } private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) { setFoldablePosture(mActivity, isHalfFolded, isTabletop); } @Test Loading