Loading services/core/java/com/android/server/wm/LetterboxUiController.java +24 −166 Original line number Diff line number Diff line Loading @@ -40,7 +40,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER; import static android.content.pm.ActivityInfo.isFixedOrientation; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; Loading @@ -54,10 +53,6 @@ import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN; import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; Loading @@ -80,7 +75,6 @@ import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANG import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__RIGHT; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__TOP; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__UNKNOWN_POSITION; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__BOTTOM_TO_CENTER; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_BOTTOM; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_LEFT; Loading Loading @@ -135,12 +129,9 @@ import com.android.server.wm.utils.OptPropFactory.OptProp; import com.android.window.flags.Flags; 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; import java.util.function.Predicate; /** Controls behaviour of the letterbox UI for {@link mActivityRecord}. */ // TODO(b/185262487): Improve test coverage of this class. Parts of it are tested in Loading @@ -150,13 +141,8 @@ import java.util.function.Predicate; // TODO(b/263021211): Consider renaming to more generic CompatUIController. final class LetterboxUiController { private static final Predicate<ActivityRecord> FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE = ActivityRecord::occludesParent; private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxUiController" : TAG_ATM; private static final float UNDEFINED_ASPECT_RATIO = 0f; // Minimum value of mSetOrientationRequestCounter before qualifying as orientation request loop @VisibleForTesting static final int MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP = 2; Loading Loading @@ -188,10 +174,6 @@ final class LetterboxUiController { // Corresponds to OVERRIDE_RESPECT_REQUESTED_ORIENTATION private final boolean mIsOverrideRespectRequestedOrientationEnabled; // The list of observers for the destroy event of candidate opaque activities // when dealing with translucent activities. private final List<LetterboxUiController> mDestroyListeners = new ArrayList<>(); @NonNull private final OptProp mAllowOrientationOverrideOptProp; @NonNull Loading @@ -206,34 +188,11 @@ final class LetterboxUiController { @NonNull private final OptProp mAllowUserAspectRatioFullscreenOverrideOptProp; /* * WindowContainerListener responsible to make translucent activities inherit * constraints from the first opaque activity beneath them. It's null for not * translucent activities. */ @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 // first opaque activity beneath. private float mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; private float mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; // Updated when ActivityRecord#setRequestedOrientation is called private long mTimeMsLastSetOrientationRequest = 0; @Configuration.Orientation private int mInheritedOrientation = ORIENTATION_UNDEFINED; // The app compat state for the opaque activity if any private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; // Counter for ActivityRecord#setRequestedOrientation private int mSetOrientationRequestCounter = 0; Loading @@ -242,9 +201,6 @@ final class LetterboxUiController { @PackageManager.UserMinAspectRatio private int mUserAspectRatio = USER_MIN_ASPECT_RATIO_UNSET; // The CompatDisplayInsets of the opaque activity beneath the translucent one. private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets; @Nullable private Letterbox mLetterbox; Loading @@ -271,6 +227,10 @@ final class LetterboxUiController { @NonNull private final OptProp mFakeFocusOptProp; // TODO(b/336807329) Eventually eemove this dependency when refactoring Reachability. @NonNull private final TransparentPolicy mTransparentPolicy; private boolean mIsRelaunchingAfterRequestedOrientationChanged; private boolean mLastShouldShowLetterboxUi; Loading @@ -284,6 +244,7 @@ final class LetterboxUiController { // to use it after since controller is only used in ActivityRecord. mActivityRecord = activityRecord; mTransparentPolicy = new TransparentPolicy(activityRecord, mLetterboxConfiguration); PackageManager packageManager = wmService.mContext.getPackageManager(); final OptPropFactory optPropBuilder = new OptPropFactory(packageManager, Loading Loading @@ -361,14 +322,7 @@ 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; } mTransparentPolicy.destroy(); } void onMovedToDisplay(int displayId) { Loading @@ -377,6 +331,11 @@ final class LetterboxUiController { } } @NonNull TransparentPolicy getTransparentPolicy() { return mTransparentPolicy; } /** * Whether should ignore app requested orientation in response to an app * calling {@link android.app.Activity#setRequestedOrientation}. Loading Loading @@ -1344,7 +1303,7 @@ final class LetterboxUiController { // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() ? mFirstOpaqueActivityBeneath.getScreenResolvedBounds() ? getTransparentPolicy().mFirstOpaqueActivityBeneath.getScreenResolvedBounds() : mActivityRecord.getScreenResolvedBounds(); return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled() && parentConfiguration.windowConfiguration.getWindowingMode() Loading Loading @@ -1382,7 +1341,7 @@ final class LetterboxUiController { // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() ? mFirstOpaqueActivityBeneath.getScreenResolvedBounds() ? getTransparentPolicy().mFirstOpaqueActivityBeneath.getScreenResolvedBounds() : mActivityRecord.getScreenResolvedBounds(); return mLetterboxConfiguration.getIsVerticalReachabilityEnabled() && parentConfiguration.windowConfiguration.getWindowingMode() Loading Loading @@ -1797,56 +1756,9 @@ final class LetterboxUiController { /** * Handles translucent activities letterboxing inheriting constraints from the * first opaque activity beneath. * @param parent The parent container. */ void updateInheritedLetterbox() { final WindowContainer<?> parent = mActivityRecord.getParent(); if (parent == null) { return; } if (!mLetterboxConfiguration.isTranslucentLetterboxingEnabled()) { return; } if (mLetterboxConfigListener != null) { mLetterboxConfigListener.onRemoved(); clearInheritedConfig(); } // 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; } mFirstOpaqueActivityBeneath.mLetterboxUiController.mDestroyListeners.add(this); inheritConfiguration(mFirstOpaqueActivityBeneath); mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation( mActivityRecord, mFirstOpaqueActivityBeneath, (opaqueConfig, transparentOverrideConfig) -> { resetTranslucentOverrideConfig(transparentOverrideConfig); final Rect parentBounds = parent.getWindowConfiguration().getBounds(); final Rect bounds = transparentOverrideConfig.windowConfiguration.getBounds(); final Rect letterboxBounds = opaqueConfig.windowConfiguration.getBounds(); // We cannot use letterboxBounds directly here because the position relies on // letterboxing. Using letterboxBounds directly, would produce a double offset. bounds.set(parentBounds.left, parentBounds.top, parentBounds.left + letterboxBounds.width(), parentBounds.top + letterboxBounds.height()); // 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(mFirstOpaqueActivityBeneath); return transparentOverrideConfig; }); mTransparentPolicy.updateInheritedLetterbox(); } /** Loading @@ -1855,7 +1767,7 @@ final class LetterboxUiController { * the first opaque activity beneath. */ boolean hasInheritedLetterboxBehavior() { return mLetterboxConfigListener != null; return mTransparentPolicy.hasInheritedLetterboxBehavior(); } /** Loading @@ -1863,39 +1775,32 @@ final class LetterboxUiController { * beneath and needs to inherit its orientation. */ boolean hasInheritedOrientation() { // To force a different orientation, the transparent one needs to have an explicit one // otherwise the existing one is fine and the actual orientation will depend on the // bounds. // To avoid wrong behaviour, we're not forcing orientation for activities with not // fixed orientation (e.g. permission dialogs). return hasInheritedLetterboxBehavior() && mActivityRecord.getOverrideOrientation() != SCREEN_ORIENTATION_UNSPECIFIED; return mTransparentPolicy.hasInheritedOrientation(); } float getInheritedMinAspectRatio() { return mInheritedMinAspectRatio; return mTransparentPolicy.getInheritedMinAspectRatio(); } float getInheritedMaxAspectRatio() { return mInheritedMaxAspectRatio; return mTransparentPolicy.getInheritedMaxAspectRatio(); } int getInheritedAppCompatState() { return mInheritedAppCompatState; return mTransparentPolicy.getInheritedAppCompatState(); } @Configuration.Orientation int getInheritedOrientation() { return mInheritedOrientation; return mTransparentPolicy.getInheritedOrientation(); } ActivityRecord.CompatDisplayInsets getInheritedCompatDisplayInsets() { return mInheritedCompatDisplayInsets; return mTransparentPolicy.getInheritedCompatDisplayInsets(); } void clearInheritedCompatDisplayInsets() { mInheritedCompatDisplayInsets = null; mTransparentPolicy.clearInheritedCompatDisplayInsets(); } /** Loading @@ -1903,11 +1808,7 @@ final class LetterboxUiController { * 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 mTransparentPolicy.applyOnOpaqueActivityBelow(consumer); } /** Loading @@ -1915,50 +1816,7 @@ final class LetterboxUiController { * if it exists and the strategy is enabled. */ Optional<ActivityRecord> findOpaqueNotFinishingActivityBelow() { if (!hasInheritedLetterboxBehavior() || mActivityRecord.getTask() == null) { return Optional.empty(); } return Optional.ofNullable(mFirstOpaqueActivityBeneath); } /** Resets the screen size related fields so they can be resolved by requested bounds later. */ private static void resetTranslucentOverrideConfig(Configuration config) { // The values for the following properties will be defined during the configuration // resolution in {@link ActivityRecord#resolveOverrideConfiguration} using the // properties inherited from the first not finishing opaque activity beneath. config.orientation = ORIENTATION_UNDEFINED; config.screenWidthDp = config.compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; config.screenHeightDp = config.compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; config.smallestScreenWidthDp = config.compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; } private void inheritConfiguration(ActivityRecord firstOpaque) { // To avoid wrong behaviour, we're not forcing a specific aspect ratio to activities // which are not already providing one (e.g. permission dialogs) and presumably also // not resizable. if (mActivityRecord.getMinAspectRatio() != UNDEFINED_ASPECT_RATIO) { mInheritedMinAspectRatio = firstOpaque.getMinAspectRatio(); } if (mActivityRecord.getMaxAspectRatio() != UNDEFINED_ASPECT_RATIO) { mInheritedMaxAspectRatio = firstOpaque.getMaxAspectRatio(); } mInheritedOrientation = firstOpaque.getRequestedConfigurationOrientation(); mInheritedAppCompatState = firstOpaque.getAppCompatState(); mInheritedCompatDisplayInsets = firstOpaque.getCompatDisplayInsets(); } private void clearInheritedConfig() { if (mFirstOpaqueActivityBeneath != null) { mFirstOpaqueActivityBeneath.mLetterboxUiController.mDestroyListeners.remove(this); } mFirstOpaqueActivityBeneath = null; mLetterboxConfigListener = null; mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; mInheritedOrientation = ORIENTATION_UNDEFINED; mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; mInheritedCompatDisplayInsets = null; return mTransparentPolicy.findOpaqueNotFinishingActivityBelow(); } @NonNull Loading services/core/java/com/android/server/wm/TransparentPolicy.java 0 → 100644 +276 −0 File added.Preview size limit exceeded, changes collapsed. Show changes services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +13 −9 Original line number Diff line number Diff line Loading @@ -388,15 +388,16 @@ public class SizeCompatTests extends WindowTestsBase { // Transparent strategy applied assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); spyOn(translucentActivity.mLetterboxUiController); clearInvocations(translucentActivity.mLetterboxUiController); spyOn(translucentActivity.mLetterboxUiController.getTransparentPolicy()); clearInvocations(translucentActivity.mLetterboxUiController.getTransparentPolicy()); // We destroy the first opaque activity opaqueActivity.setState(DESTROYED, "testing"); opaqueActivity.removeImmediately(); // Check that updateInheritedLetterbox() is invoked again verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); verify(translucentActivity.mLetterboxUiController.getTransparentPolicy()) .updateInheritedLetterbox(); } // TODO(b/333663877): Enable test after fix Loading Loading @@ -465,17 +466,20 @@ public class SizeCompatTests extends WindowTestsBase { mTask.addChild(translucentActivity); // Transparent strategy applied assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); assertNotNull(translucentActivity.mLetterboxUiController.mFirstOpaqueActivityBeneath); assertNotNull(translucentActivity.mLetterboxUiController .getTransparentPolicy().mFirstOpaqueActivityBeneath); spyOn(translucentActivity.mLetterboxUiController); clearInvocations(translucentActivity.mLetterboxUiController); spyOn(translucentActivity.mLetterboxUiController.getTransparentPolicy()); clearInvocations(translucentActivity.mLetterboxUiController.getTransparentPolicy()); // We destroy the first opaque activity mActivity.removeImmediately(); // Check that updateInheritedLetterbox() is invoked again verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); assertNull(translucentActivity.mLetterboxUiController.mFirstOpaqueActivityBeneath); // Check that updateInheritedLetterbox() is invoked again on the TransparentPolicy verify(translucentActivity.mLetterboxUiController.getTransparentPolicy()) .updateInheritedLetterbox(); assertNull(translucentActivity.mLetterboxUiController .getTransparentPolicy().mFirstOpaqueActivityBeneath); } @Test Loading Loading
services/core/java/com/android/server/wm/LetterboxUiController.java +24 −166 Original line number Diff line number Diff line Loading @@ -40,7 +40,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER; import static android.content.pm.ActivityInfo.isFixedOrientation; import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; Loading @@ -54,10 +53,6 @@ import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCREEN; import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; Loading @@ -80,7 +75,6 @@ import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANG import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__RIGHT; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__TOP; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__UNKNOWN_POSITION; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__BOTTOM_TO_CENTER; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_BOTTOM; import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_LEFT; Loading Loading @@ -135,12 +129,9 @@ import com.android.server.wm.utils.OptPropFactory.OptProp; import com.android.window.flags.Flags; 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; import java.util.function.Predicate; /** Controls behaviour of the letterbox UI for {@link mActivityRecord}. */ // TODO(b/185262487): Improve test coverage of this class. Parts of it are tested in Loading @@ -150,13 +141,8 @@ import java.util.function.Predicate; // TODO(b/263021211): Consider renaming to more generic CompatUIController. final class LetterboxUiController { private static final Predicate<ActivityRecord> FIRST_OPAQUE_NOT_FINISHING_ACTIVITY_PREDICATE = ActivityRecord::occludesParent; private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxUiController" : TAG_ATM; private static final float UNDEFINED_ASPECT_RATIO = 0f; // Minimum value of mSetOrientationRequestCounter before qualifying as orientation request loop @VisibleForTesting static final int MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP = 2; Loading Loading @@ -188,10 +174,6 @@ final class LetterboxUiController { // Corresponds to OVERRIDE_RESPECT_REQUESTED_ORIENTATION private final boolean mIsOverrideRespectRequestedOrientationEnabled; // The list of observers for the destroy event of candidate opaque activities // when dealing with translucent activities. private final List<LetterboxUiController> mDestroyListeners = new ArrayList<>(); @NonNull private final OptProp mAllowOrientationOverrideOptProp; @NonNull Loading @@ -206,34 +188,11 @@ final class LetterboxUiController { @NonNull private final OptProp mAllowUserAspectRatioFullscreenOverrideOptProp; /* * WindowContainerListener responsible to make translucent activities inherit * constraints from the first opaque activity beneath them. It's null for not * translucent activities. */ @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 // first opaque activity beneath. private float mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; private float mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; // Updated when ActivityRecord#setRequestedOrientation is called private long mTimeMsLastSetOrientationRequest = 0; @Configuration.Orientation private int mInheritedOrientation = ORIENTATION_UNDEFINED; // The app compat state for the opaque activity if any private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; // Counter for ActivityRecord#setRequestedOrientation private int mSetOrientationRequestCounter = 0; Loading @@ -242,9 +201,6 @@ final class LetterboxUiController { @PackageManager.UserMinAspectRatio private int mUserAspectRatio = USER_MIN_ASPECT_RATIO_UNSET; // The CompatDisplayInsets of the opaque activity beneath the translucent one. private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets; @Nullable private Letterbox mLetterbox; Loading @@ -271,6 +227,10 @@ final class LetterboxUiController { @NonNull private final OptProp mFakeFocusOptProp; // TODO(b/336807329) Eventually eemove this dependency when refactoring Reachability. @NonNull private final TransparentPolicy mTransparentPolicy; private boolean mIsRelaunchingAfterRequestedOrientationChanged; private boolean mLastShouldShowLetterboxUi; Loading @@ -284,6 +244,7 @@ final class LetterboxUiController { // to use it after since controller is only used in ActivityRecord. mActivityRecord = activityRecord; mTransparentPolicy = new TransparentPolicy(activityRecord, mLetterboxConfiguration); PackageManager packageManager = wmService.mContext.getPackageManager(); final OptPropFactory optPropBuilder = new OptPropFactory(packageManager, Loading Loading @@ -361,14 +322,7 @@ 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; } mTransparentPolicy.destroy(); } void onMovedToDisplay(int displayId) { Loading @@ -377,6 +331,11 @@ final class LetterboxUiController { } } @NonNull TransparentPolicy getTransparentPolicy() { return mTransparentPolicy; } /** * Whether should ignore app requested orientation in response to an app * calling {@link android.app.Activity#setRequestedOrientation}. Loading Loading @@ -1344,7 +1303,7 @@ final class LetterboxUiController { // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() ? mFirstOpaqueActivityBeneath.getScreenResolvedBounds() ? getTransparentPolicy().mFirstOpaqueActivityBeneath.getScreenResolvedBounds() : mActivityRecord.getScreenResolvedBounds(); return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled() && parentConfiguration.windowConfiguration.getWindowingMode() Loading Loading @@ -1382,7 +1341,7 @@ final class LetterboxUiController { // Use screen resolved bounds which uses resolved bounds or size compat bounds // as activity bounds can sometimes be empty final Rect opaqueActivityBounds = hasInheritedLetterboxBehavior() ? mFirstOpaqueActivityBeneath.getScreenResolvedBounds() ? getTransparentPolicy().mFirstOpaqueActivityBeneath.getScreenResolvedBounds() : mActivityRecord.getScreenResolvedBounds(); return mLetterboxConfiguration.getIsVerticalReachabilityEnabled() && parentConfiguration.windowConfiguration.getWindowingMode() Loading Loading @@ -1797,56 +1756,9 @@ final class LetterboxUiController { /** * Handles translucent activities letterboxing inheriting constraints from the * first opaque activity beneath. * @param parent The parent container. */ void updateInheritedLetterbox() { final WindowContainer<?> parent = mActivityRecord.getParent(); if (parent == null) { return; } if (!mLetterboxConfiguration.isTranslucentLetterboxingEnabled()) { return; } if (mLetterboxConfigListener != null) { mLetterboxConfigListener.onRemoved(); clearInheritedConfig(); } // 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; } mFirstOpaqueActivityBeneath.mLetterboxUiController.mDestroyListeners.add(this); inheritConfiguration(mFirstOpaqueActivityBeneath); mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation( mActivityRecord, mFirstOpaqueActivityBeneath, (opaqueConfig, transparentOverrideConfig) -> { resetTranslucentOverrideConfig(transparentOverrideConfig); final Rect parentBounds = parent.getWindowConfiguration().getBounds(); final Rect bounds = transparentOverrideConfig.windowConfiguration.getBounds(); final Rect letterboxBounds = opaqueConfig.windowConfiguration.getBounds(); // We cannot use letterboxBounds directly here because the position relies on // letterboxing. Using letterboxBounds directly, would produce a double offset. bounds.set(parentBounds.left, parentBounds.top, parentBounds.left + letterboxBounds.width(), parentBounds.top + letterboxBounds.height()); // 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(mFirstOpaqueActivityBeneath); return transparentOverrideConfig; }); mTransparentPolicy.updateInheritedLetterbox(); } /** Loading @@ -1855,7 +1767,7 @@ final class LetterboxUiController { * the first opaque activity beneath. */ boolean hasInheritedLetterboxBehavior() { return mLetterboxConfigListener != null; return mTransparentPolicy.hasInheritedLetterboxBehavior(); } /** Loading @@ -1863,39 +1775,32 @@ final class LetterboxUiController { * beneath and needs to inherit its orientation. */ boolean hasInheritedOrientation() { // To force a different orientation, the transparent one needs to have an explicit one // otherwise the existing one is fine and the actual orientation will depend on the // bounds. // To avoid wrong behaviour, we're not forcing orientation for activities with not // fixed orientation (e.g. permission dialogs). return hasInheritedLetterboxBehavior() && mActivityRecord.getOverrideOrientation() != SCREEN_ORIENTATION_UNSPECIFIED; return mTransparentPolicy.hasInheritedOrientation(); } float getInheritedMinAspectRatio() { return mInheritedMinAspectRatio; return mTransparentPolicy.getInheritedMinAspectRatio(); } float getInheritedMaxAspectRatio() { return mInheritedMaxAspectRatio; return mTransparentPolicy.getInheritedMaxAspectRatio(); } int getInheritedAppCompatState() { return mInheritedAppCompatState; return mTransparentPolicy.getInheritedAppCompatState(); } @Configuration.Orientation int getInheritedOrientation() { return mInheritedOrientation; return mTransparentPolicy.getInheritedOrientation(); } ActivityRecord.CompatDisplayInsets getInheritedCompatDisplayInsets() { return mInheritedCompatDisplayInsets; return mTransparentPolicy.getInheritedCompatDisplayInsets(); } void clearInheritedCompatDisplayInsets() { mInheritedCompatDisplayInsets = null; mTransparentPolicy.clearInheritedCompatDisplayInsets(); } /** Loading @@ -1903,11 +1808,7 @@ final class LetterboxUiController { * 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 mTransparentPolicy.applyOnOpaqueActivityBelow(consumer); } /** Loading @@ -1915,50 +1816,7 @@ final class LetterboxUiController { * if it exists and the strategy is enabled. */ Optional<ActivityRecord> findOpaqueNotFinishingActivityBelow() { if (!hasInheritedLetterboxBehavior() || mActivityRecord.getTask() == null) { return Optional.empty(); } return Optional.ofNullable(mFirstOpaqueActivityBeneath); } /** Resets the screen size related fields so they can be resolved by requested bounds later. */ private static void resetTranslucentOverrideConfig(Configuration config) { // The values for the following properties will be defined during the configuration // resolution in {@link ActivityRecord#resolveOverrideConfiguration} using the // properties inherited from the first not finishing opaque activity beneath. config.orientation = ORIENTATION_UNDEFINED; config.screenWidthDp = config.compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; config.screenHeightDp = config.compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; config.smallestScreenWidthDp = config.compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; } private void inheritConfiguration(ActivityRecord firstOpaque) { // To avoid wrong behaviour, we're not forcing a specific aspect ratio to activities // which are not already providing one (e.g. permission dialogs) and presumably also // not resizable. if (mActivityRecord.getMinAspectRatio() != UNDEFINED_ASPECT_RATIO) { mInheritedMinAspectRatio = firstOpaque.getMinAspectRatio(); } if (mActivityRecord.getMaxAspectRatio() != UNDEFINED_ASPECT_RATIO) { mInheritedMaxAspectRatio = firstOpaque.getMaxAspectRatio(); } mInheritedOrientation = firstOpaque.getRequestedConfigurationOrientation(); mInheritedAppCompatState = firstOpaque.getAppCompatState(); mInheritedCompatDisplayInsets = firstOpaque.getCompatDisplayInsets(); } private void clearInheritedConfig() { if (mFirstOpaqueActivityBeneath != null) { mFirstOpaqueActivityBeneath.mLetterboxUiController.mDestroyListeners.remove(this); } mFirstOpaqueActivityBeneath = null; mLetterboxConfigListener = null; mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; mInheritedOrientation = ORIENTATION_UNDEFINED; mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; mInheritedCompatDisplayInsets = null; return mTransparentPolicy.findOpaqueNotFinishingActivityBelow(); } @NonNull Loading
services/core/java/com/android/server/wm/TransparentPolicy.java 0 → 100644 +276 −0 File added.Preview size limit exceeded, changes collapsed. Show changes
services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +13 −9 Original line number Diff line number Diff line Loading @@ -388,15 +388,16 @@ public class SizeCompatTests extends WindowTestsBase { // Transparent strategy applied assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); spyOn(translucentActivity.mLetterboxUiController); clearInvocations(translucentActivity.mLetterboxUiController); spyOn(translucentActivity.mLetterboxUiController.getTransparentPolicy()); clearInvocations(translucentActivity.mLetterboxUiController.getTransparentPolicy()); // We destroy the first opaque activity opaqueActivity.setState(DESTROYED, "testing"); opaqueActivity.removeImmediately(); // Check that updateInheritedLetterbox() is invoked again verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); verify(translucentActivity.mLetterboxUiController.getTransparentPolicy()) .updateInheritedLetterbox(); } // TODO(b/333663877): Enable test after fix Loading Loading @@ -465,17 +466,20 @@ public class SizeCompatTests extends WindowTestsBase { mTask.addChild(translucentActivity); // Transparent strategy applied assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); assertNotNull(translucentActivity.mLetterboxUiController.mFirstOpaqueActivityBeneath); assertNotNull(translucentActivity.mLetterboxUiController .getTransparentPolicy().mFirstOpaqueActivityBeneath); spyOn(translucentActivity.mLetterboxUiController); clearInvocations(translucentActivity.mLetterboxUiController); spyOn(translucentActivity.mLetterboxUiController.getTransparentPolicy()); clearInvocations(translucentActivity.mLetterboxUiController.getTransparentPolicy()); // We destroy the first opaque activity mActivity.removeImmediately(); // Check that updateInheritedLetterbox() is invoked again verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); assertNull(translucentActivity.mLetterboxUiController.mFirstOpaqueActivityBeneath); // Check that updateInheritedLetterbox() is invoked again on the TransparentPolicy verify(translucentActivity.mLetterboxUiController.getTransparentPolicy()) .updateInheritedLetterbox(); assertNull(translucentActivity.mLetterboxUiController .getTransparentPolicy().mFirstOpaqueActivityBeneath); } @Test Loading