diff options
13 files changed, 715 insertions, 462 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 4085ec90c95e..fb2bf39c0b7b 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -1612,7 +1612,8 @@ class ActivityMetricsLogger { int positionToLog = APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__NOT_LETTERBOXED_POSITION; if (isAppCompateStateChangedToLetterboxed(state)) { - positionToLog = activity.mLetterboxUiController.getLetterboxPositionForLogging(); + positionToLog = activity.mAppCompatController.getAppCompatReachabilityOverrides() + .getLetterboxPositionForLogging(); } FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPAT_STATE_CHANGED, packageUid, state, positionToLog); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 8a768c0ed84d..c5fc2d2749e6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -8633,8 +8633,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A /** * Adjusts position of resolved bounds if they don't fill the parent using gravity * requested in the config or via an ADB command. For more context see {@link - * LetterboxUiController#getHorizontalPositionMultiplier(Configuration)} and - * {@link LetterboxUiController#getVerticalPositionMultiplier(Configuration)} + * AppCompatReachabilityOverrides#getHorizontalPositionMultiplier(Configuration)} and + * {@link AppCompatReachabilityOverrides#getVerticalPositionMultiplier(Configuration)} * <p> * Note that this is the final step that can change the resolved bounds. After this method * is called, the position of the bounds will be moved to app space as sandboxing if the @@ -8663,11 +8663,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else { navBarInsets = Insets.NONE; } + final AppCompatReachabilityOverrides reachabilityOverrides = + mAppCompatController.getAppCompatReachabilityOverrides(); // Horizontal position int offsetX = 0; if (parentBounds.width() != screenResolvedBoundsWidth) { if (screenResolvedBoundsWidth <= parentAppBoundsWidth) { - float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier( + float positionMultiplier = reachabilityOverrides.getHorizontalPositionMultiplier( newParentConfiguration); // If in immersive mode, always align to right and overlap right insets (task bar) // as they are transient and hidden. This removes awkward right spacing. @@ -8688,7 +8690,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A int offsetY = 0; if (parentBoundsHeight != screenResolvedBoundsHeight) { if (screenResolvedBoundsHeight <= parentAppBoundsHeight) { - float positionMultiplier = mLetterboxUiController.getVerticalPositionMultiplier( + float positionMultiplier = reachabilityOverrides.getVerticalPositionMultiplier( newParentConfiguration); // If in immersive mode, always align to bottom and overlap bottom insets (nav bar, // task bar) as they are transient and hidden. This removes awkward bottom spacing. diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java index 25cb134a7c52..d2f3d1db16a7 100644 --- a/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioOverrides.java @@ -50,8 +50,6 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.server.wm.utils.OptPropFactory; -import java.util.function.Function; - /** * Encapsulates app compat configurations and overrides related to aspect ratio. */ @@ -76,20 +74,20 @@ class AppCompatAspectRatioOverrides { @NonNull private final OptPropFactory.OptProp mAllowOrientationOverrideOptProp; @NonNull - private final Function<Boolean, Boolean> mIsDisplayFullScreenAndInPostureProvider; + private final AppCompatDeviceStateQuery mAppCompatDeviceStateQuery; @NonNull - private final Function<Configuration, Float> mGetHorizontalPositionMultiplierProvider; + private final AppCompatReachabilityOverrides mAppCompatReachabilityOverrides; AppCompatAspectRatioOverrides(@NonNull ActivityRecord activityRecord, @NonNull AppCompatConfiguration appCompatConfiguration, @NonNull OptPropFactory optPropBuilder, - @NonNull Function<Boolean, Boolean> isDisplayFullScreenAndInPostureProvider, - @NonNull Function<Configuration, Float> getHorizontalPositionMultiplierProvider) { + @NonNull AppCompatDeviceStateQuery appCompatDeviceStateQuery, + @NonNull AppCompatReachabilityOverrides appCompatReachabilityOverrides) { mActivityRecord = activityRecord; mAppCompatConfiguration = appCompatConfiguration; + mAppCompatDeviceStateQuery = appCompatDeviceStateQuery; mUserAspectRatioState = new UserAspectRatioState(); - mIsDisplayFullScreenAndInPostureProvider = isDisplayFullScreenAndInPostureProvider; - mGetHorizontalPositionMultiplierProvider = getHorizontalPositionMultiplierProvider; + mAppCompatReachabilityOverrides = appCompatReachabilityOverrides; mAllowMinAspectRatioOverrideOptProp = optPropBuilder.create( PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE); mAllowUserAspectRatioOverrideOptProp = optPropBuilder.create( @@ -245,12 +243,13 @@ class AppCompatAspectRatioOverrides { } private boolean shouldUseSplitScreenAspectRatio(@NonNull Configuration parentConfiguration) { - final boolean isBookMode = mIsDisplayFullScreenAndInPostureProvider - .apply(/* isTabletop */false); - final boolean isNotCenteredHorizontally = mGetHorizontalPositionMultiplierProvider.apply( - parentConfiguration) != LETTERBOX_POSITION_MULTIPLIER_CENTER; - final boolean isTabletopMode = mIsDisplayFullScreenAndInPostureProvider - .apply(/* isTabletop */ true); + final boolean isBookMode = mAppCompatDeviceStateQuery + .isDisplayFullScreenAndInPosture(/* isTabletop */false); + final boolean isNotCenteredHorizontally = + mAppCompatReachabilityOverrides.getHorizontalPositionMultiplier(parentConfiguration) + != LETTERBOX_POSITION_MULTIPLIER_CENTER; + final boolean isTabletopMode = mAppCompatDeviceStateQuery + .isDisplayFullScreenAndInPosture(/* isTabletop */ true); final boolean isLandscape = isFixedOrientationLandscape( mActivityRecord.getOverrideOrientation()); final AppCompatCameraOverrides cameraOverrides = diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java index 54223b609449..d38edfc39a8a 100644 --- a/services/core/java/com/android/server/wm/AppCompatController.java +++ b/services/core/java/com/android/server/wm/AppCompatController.java @@ -35,7 +35,11 @@ class AppCompatController { @NonNull private final AppCompatAspectRatioPolicy mAppCompatAspectRatioPolicy; @NonNull + private final AppCompatReachabilityPolicy mAppCompatReachabilityPolicy; + @NonNull private final AppCompatOverrides mAppCompatOverrides; + @NonNull + private final AppCompatDeviceStateQuery mAppCompatDeviceStateQuery; AppCompatController(@NonNull WindowManagerService wmService, @NonNull ActivityRecord activityRecord) { @@ -43,13 +47,16 @@ class AppCompatController { final PackageManager packageManager = wmService.mContext.getPackageManager(); final OptPropFactory optPropBuilder = new OptPropFactory(packageManager, activityRecord.packageName); + mAppCompatDeviceStateQuery = new AppCompatDeviceStateQuery(activityRecord); mTransparentPolicy = new TransparentPolicy(activityRecord, wmService.mAppCompatConfiguration); mAppCompatOverrides = new AppCompatOverrides(activityRecord, - wmService.mAppCompatConfiguration, optPropBuilder); + wmService.mAppCompatConfiguration, optPropBuilder, mAppCompatDeviceStateQuery); mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord, mAppCompatOverrides); mAppCompatAspectRatioPolicy = new AppCompatAspectRatioPolicy(activityRecord, mTransparentPolicy, mAppCompatOverrides); + mAppCompatReachabilityPolicy = new AppCompatReachabilityPolicy(mActivityRecord, + wmService.mAppCompatConfiguration); } @NonNull @@ -101,7 +108,23 @@ class AppCompatController { } @NonNull + AppCompatReachabilityPolicy getAppCompatReachabilityPolicy() { + return mAppCompatReachabilityPolicy; + } + + @NonNull AppCompatFocusOverrides getAppCompatFocusOverrides() { return mAppCompatOverrides.getAppCompatFocusOverrides(); } + + @NonNull + AppCompatReachabilityOverrides getAppCompatReachabilityOverrides() { + return mAppCompatOverrides.getAppCompatReachabilityOverrides(); + } + + @NonNull + AppCompatDeviceStateQuery getAppCompatDeviceStateQuery() { + return mAppCompatDeviceStateQuery; + } + } diff --git a/services/core/java/com/android/server/wm/AppCompatDeviceStateQuery.java b/services/core/java/com/android/server/wm/AppCompatDeviceStateQuery.java new file mode 100644 index 000000000000..3abea24c530a --- /dev/null +++ b/services/core/java/com/android/server/wm/AppCompatDeviceStateQuery.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; + +import android.annotation.NonNull; + +/** + * Provides information about the current state of the display in relation of + * fold/unfold and other positions. + */ +class AppCompatDeviceStateQuery { + + @NonNull + final ActivityRecord mActivityRecord; + + AppCompatDeviceStateQuery(@NonNull ActivityRecord activityRecord) { + mActivityRecord = activityRecord; + } + + /** + * Check if we are in the given pose and in fullscreen mode. + * + * Note that we check the task rather than the parent as with ActivityEmbedding the parent + * might be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is + * actually fullscreen. If display is still in transition e.g. unfolding, don't return true + * for HALF_FOLDED state or app will flicker. + */ + boolean isDisplayFullScreenAndInPosture(boolean isTabletop) { + final Task task = mActivityRecord.getTask(); + final DisplayContent dc = mActivityRecord.mDisplayContent; + return dc != null && task != null && !dc.inTransition() + && dc.getDisplayRotation().isDeviceInPosture( + DeviceStateController.DeviceState.HALF_FOLDED, isTabletop) + && task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN; + } + + /** + * Note that we check the task rather than the parent as with ActivityEmbedding the parent might + * be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is + * actually fullscreen. + */ + boolean isDisplayFullScreenAndSeparatingHinge() { + final Task task = mActivityRecord.getTask(); + return mActivityRecord.mDisplayContent != null && task != null + && mActivityRecord.mDisplayContent.getDisplayRotation().isDisplaySeparatingHinge() + && task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN; + } +} diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java index 445001178d26..80bbee3dd78d 100644 --- a/services/core/java/com/android/server/wm/AppCompatOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java @@ -35,19 +35,22 @@ public class AppCompatOverrides { private final AppCompatFocusOverrides mAppCompatFocusOverrides; @NonNull private final AppCompatResizeOverrides mAppCompatResizeOverrides; + @NonNull + private final AppCompatReachabilityOverrides mAppCompatReachabilityOverrides; AppCompatOverrides(@NonNull ActivityRecord activityRecord, @NonNull AppCompatConfiguration appCompatConfiguration, - @NonNull OptPropFactory optPropBuilder) { + @NonNull OptPropFactory optPropBuilder, + @NonNull AppCompatDeviceStateQuery appCompatDeviceStateQuery) { mAppCompatCameraOverrides = new AppCompatCameraOverrides(activityRecord, appCompatConfiguration, optPropBuilder); mAppCompatOrientationOverrides = new AppCompatOrientationOverrides(activityRecord, appCompatConfiguration, optPropBuilder, mAppCompatCameraOverrides); - // TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with reachability. + mAppCompatReachabilityOverrides = new AppCompatReachabilityOverrides(activityRecord, + appCompatConfiguration, appCompatDeviceStateQuery); mAppCompatAspectRatioOverrides = new AppCompatAspectRatioOverrides(activityRecord, - appCompatConfiguration, optPropBuilder, - activityRecord.mLetterboxUiController::isDisplayFullScreenAndInPosture, - activityRecord.mLetterboxUiController::getHorizontalPositionMultiplier); + appCompatConfiguration, optPropBuilder, appCompatDeviceStateQuery, + mAppCompatReachabilityOverrides); mAppCompatFocusOverrides = new AppCompatFocusOverrides(activityRecord, appCompatConfiguration, optPropBuilder); mAppCompatResizeOverrides = new AppCompatResizeOverrides(activityRecord, optPropBuilder); @@ -77,4 +80,9 @@ public class AppCompatOverrides { AppCompatResizeOverrides getAppCompatResizeOverrides() { return mAppCompatResizeOverrides; } + + @NonNull + AppCompatReachabilityOverrides getAppCompatReachabilityOverrides() { + return mAppCompatReachabilityOverrides; + } } diff --git a/services/core/java/com/android/server/wm/AppCompatReachabilityOverrides.java b/services/core/java/com/android/server/wm/AppCompatReachabilityOverrides.java new file mode 100644 index 000000000000..b9bdc325cf98 --- /dev/null +++ b/services/core/java/com/android/server/wm/AppCompatReachabilityOverrides.java @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; + +import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM; +import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__CENTER; +import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__LEFT; +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.server.wm.AppCompatConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER; +import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT; +import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT; +import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM; +import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER; +import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP; + +import android.annotation.NonNull; +import android.content.res.Configuration; +import android.graphics.Rect; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; + +/** + * Encapsulate overrides and configurations about app compat reachability. + */ +class AppCompatReachabilityOverrides { + + @NonNull + private final ActivityRecord mActivityRecord; + @NonNull + private final AppCompatConfiguration mAppCompatConfiguration; + @NonNull + private final AppCompatDeviceStateQuery mAppCompatDeviceStateQuery; + @NonNull + private final ReachabilityState mReachabilityState; + + AppCompatReachabilityOverrides(@NonNull ActivityRecord activityRecord, + @NonNull AppCompatConfiguration appCompatConfiguration, + @NonNull AppCompatDeviceStateQuery appCompatDeviceStateQuery) { + mActivityRecord = activityRecord; + mAppCompatConfiguration = appCompatConfiguration; + mAppCompatDeviceStateQuery = appCompatDeviceStateQuery; + mReachabilityState = new ReachabilityState(); + } + + boolean isFromDoubleTap() { + return mReachabilityState.isFromDoubleTap(); + } + + boolean isDoubleTapEvent() { + return mReachabilityState.mIsDoubleTapEvent; + } + + void setDoubleTapEvent() { + mReachabilityState.mIsDoubleTapEvent = true; + } + + /** + * Provides the multiplier to use when calculating the position of a letterboxed app after + * an horizontal reachability event (double tap). The method takes the current state of the + * device (e.g. device in book mode) into account. + * </p> + * @param parentConfiguration The parent {@link Configuration}. + * @return The value to use for calculating the letterbox horizontal position. + */ + float getHorizontalPositionMultiplier(@NonNull Configuration parentConfiguration) { + // Don't check resolved configuration because it may not be updated yet during + // configuration change. + boolean bookModeEnabled = isFullScreenAndBookModeEnabled(); + return isHorizontalReachabilityEnabled(parentConfiguration) + // Using the last global dynamic position to avoid "jumps" when moving + // between apps or activities. + ? mAppCompatConfiguration.getHorizontalMultiplierForReachability(bookModeEnabled) + : mAppCompatConfiguration.getLetterboxHorizontalPositionMultiplier(bookModeEnabled); + } + + /** + * Provides the multiplier to use when calculating the position of a letterboxed app after + * a vertical reachability event (double tap). The method takes the current state of the + * device (e.g. device posture) into account. + * </p> + * @param parentConfiguration The parent {@link Configuration}. + * @return The value to use for calculating the letterbox horizontal position. + */ + float getVerticalPositionMultiplier(@NonNull Configuration parentConfiguration) { + // Don't check resolved configuration because it may not be updated yet during + // configuration change. + boolean tabletopMode = mAppCompatDeviceStateQuery + .isDisplayFullScreenAndInPosture(/* isTabletop */ true); + return isVerticalReachabilityEnabled(parentConfiguration) + // Using the last global dynamic position to avoid "jumps" when moving + // between apps or activities. + ? mAppCompatConfiguration.getVerticalMultiplierForReachability(tabletopMode) + : mAppCompatConfiguration.getLetterboxVerticalPositionMultiplier(tabletopMode); + } + + @VisibleForTesting + boolean isHorizontalReachabilityEnabled() { + return isHorizontalReachabilityEnabled(mActivityRecord.getParent().getConfiguration()); + } + + @VisibleForTesting + boolean isVerticalReachabilityEnabled() { + return isVerticalReachabilityEnabled(mActivityRecord.getParent().getConfiguration()); + } + + boolean isLetterboxDoubleTapEducationEnabled() { + return isHorizontalReachabilityEnabled() || isVerticalReachabilityEnabled(); + } + + @AppCompatConfiguration.LetterboxVerticalReachabilityPosition + int getLetterboxPositionForVerticalReachability() { + final boolean isInFullScreenTabletopMode = + mAppCompatDeviceStateQuery.isDisplayFullScreenAndSeparatingHinge(); + return mAppCompatConfiguration.getLetterboxPositionForVerticalReachability( + isInFullScreenTabletopMode); + } + + @AppCompatConfiguration.LetterboxHorizontalReachabilityPosition + int getLetterboxPositionForHorizontalReachability() { + final boolean isInFullScreenBookMode = isFullScreenAndBookModeEnabled(); + return mAppCompatConfiguration.getLetterboxPositionForHorizontalReachability( + isInFullScreenBookMode); + } + + int getLetterboxPositionForLogging() { + int positionToLog = APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__UNKNOWN_POSITION; + if (isHorizontalReachabilityEnabled()) { + int letterboxPositionForHorizontalReachability = mAppCompatConfiguration + .getLetterboxPositionForHorizontalReachability(mAppCompatDeviceStateQuery + .isDisplayFullScreenAndInPosture(/* isTabletop */ false)); + positionToLog = letterboxHorizontalReachabilityPositionToLetterboxPositionForLogging( + letterboxPositionForHorizontalReachability); + } else if (isVerticalReachabilityEnabled()) { + int letterboxPositionForVerticalReachability = mAppCompatConfiguration + .getLetterboxPositionForVerticalReachability(mAppCompatDeviceStateQuery + .isDisplayFullScreenAndInPosture(/* isTabletop */ true)); + positionToLog = letterboxVerticalReachabilityPositionToLetterboxPositionForLogging( + letterboxPositionForVerticalReachability); + } + return positionToLog; + } + + /** + * @return {@value true} if the vertical reachability should be allowed in case of + * thin letterboxing. + */ + boolean allowVerticalReachabilityForThinLetterbox() { + if (!Flags.disableThinLetterboxingPolicy()) { + return true; + } + // When the flag is enabled we allow vertical reachability only if the + // app is not thin letterboxed vertically. + return !isVerticalThinLetterboxed(); + } + + /** + * @return {@value true} if the horizontal reachability should be enabled in case of + * thin letterboxing. + */ + boolean allowHorizontalReachabilityForThinLetterbox() { + if (!Flags.disableThinLetterboxingPolicy()) { + return true; + } + // When the flag is enabled we allow horizontal reachability only if the + // app is not thin pillarboxed. + return !isHorizontalThinLetterboxed(); + } + + /** + * @return {@value true} if the resulting app is letterboxed in a way defined as thin. + */ + boolean isVerticalThinLetterboxed() { + final int thinHeight = mAppCompatConfiguration.getThinLetterboxHeightPx(); + if (thinHeight < 0) { + return false; + } + final Task task = mActivityRecord.getTask(); + if (task == null) { + return false; + } + final int padding = Math.abs( + task.getBounds().height() - mActivityRecord.getBounds().height()) / 2; + return padding <= thinHeight; + } + + /** + * @return {@value true} if the resulting app is pillarboxed in a way defined as thin. + */ + boolean isHorizontalThinLetterboxed() { + final int thinWidth = mAppCompatConfiguration.getThinLetterboxWidthPx(); + if (thinWidth < 0) { + return false; + } + final Task task = mActivityRecord.getTask(); + if (task == null) { + return false; + } + final int padding = Math.abs( + task.getBounds().width() - mActivityRecord.getBounds().width()) / 2; + return padding <= thinWidth; + } + + // Note that we check the task rather than the parent as with ActivityEmbedding the parent might + // be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is + // actually fullscreen. + private boolean isDisplayFullScreenAndSeparatingHinge() { + Task task = mActivityRecord.getTask(); + return mActivityRecord.mDisplayContent != null + && mActivityRecord.mDisplayContent.getDisplayRotation().isDisplaySeparatingHinge() + && task != null + && task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN; + } + + private int letterboxHorizontalReachabilityPositionToLetterboxPositionForLogging( + @AppCompatConfiguration.LetterboxHorizontalReachabilityPosition int position) { + switch (position) { + case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT: + return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__LEFT; + case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER: + return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__CENTER; + case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT: + return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__RIGHT; + default: + throw new AssertionError( + "Unexpected letterbox horizontal reachability position type: " + + position); + } + } + + private int letterboxVerticalReachabilityPositionToLetterboxPositionForLogging( + @AppCompatConfiguration.LetterboxVerticalReachabilityPosition int position) { + switch (position) { + case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP: + return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__TOP; + case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER: + return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__CENTER; + case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM: + return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM; + default: + throw new AssertionError( + "Unexpected letterbox vertical reachability position type: " + + position); + } + } + + private boolean isFullScreenAndBookModeEnabled() { + return mAppCompatDeviceStateQuery.isDisplayFullScreenAndInPosture(/* isTabletop */ false) + && mAppCompatConfiguration.getIsAutomaticReachabilityInBookModeEnabled(); + } + + /** + * Whether horizontal reachability is enabled for an activity in the current configuration. + * + * <p>Conditions that needs to be met: + * <ul> + * <li>Windowing mode is fullscreen. + * <li>Horizontal Reachability is enabled. + * <li>First top opaque activity fills parent vertically, but not horizontally. + * </ul> + */ + private boolean isHorizontalReachabilityEnabled(@NonNull Configuration parentConfiguration) { + if (!allowHorizontalReachabilityForThinLetterbox()) { + return false; + } + final Rect parentAppBoundsOverride = mActivityRecord.getParentAppBoundsOverride(); + final Rect parentAppBounds = parentAppBoundsOverride != null + ? parentAppBoundsOverride : parentConfiguration.windowConfiguration.getAppBounds(); + // Use screen resolved bounds which uses resolved bounds or size compat bounds + // as activity bounds can sometimes be empty + final Rect opaqueActivityBounds = mActivityRecord.mAppCompatController + .getTransparentPolicy().getFirstOpaqueActivity() + .map(ActivityRecord::getScreenResolvedBounds) + .orElse(mActivityRecord.getScreenResolvedBounds()); + return mAppCompatConfiguration.getIsHorizontalReachabilityEnabled() + && parentConfiguration.windowConfiguration.getWindowingMode() + == WINDOWING_MODE_FULLSCREEN + // Check whether the activity fills the parent vertically. + && parentAppBounds.height() <= opaqueActivityBounds.height() + && parentAppBounds.width() > opaqueActivityBounds.width(); + } + + /** + * Whether vertical reachability is enabled for an activity in the current configuration. + * + * <p>Conditions that needs to be met: + * <ul> + * <li>Windowing mode is fullscreen. + * <li>Vertical Reachability is enabled. + * <li>First top opaque activity fills parent horizontally but not vertically. + * </ul> + */ + private boolean isVerticalReachabilityEnabled(@NonNull Configuration parentConfiguration) { + if (!allowVerticalReachabilityForThinLetterbox()) { + return false; + } + final Rect parentAppBoundsOverride = mActivityRecord.getParentAppBoundsOverride(); + final Rect parentAppBounds = parentAppBoundsOverride != null + ? parentAppBoundsOverride : parentConfiguration.windowConfiguration.getAppBounds(); + // Use screen resolved bounds which uses resolved bounds or size compat bounds + // as activity bounds can sometimes be empty. + final Rect opaqueActivityBounds = mActivityRecord.mAppCompatController + .getTransparentPolicy().getFirstOpaqueActivity() + .map(ActivityRecord::getScreenResolvedBounds) + .orElse(mActivityRecord.getScreenResolvedBounds()); + return mAppCompatConfiguration.getIsVerticalReachabilityEnabled() + && parentConfiguration.windowConfiguration.getWindowingMode() + == WINDOWING_MODE_FULLSCREEN + // Check whether the activity fills the parent horizontally. + && parentAppBounds.width() <= opaqueActivityBounds.width() + && parentAppBounds.height() > opaqueActivityBounds.height(); + } + + private static class ReachabilityState { + // If the current event is a double tap. + private boolean mIsDoubleTapEvent; + + boolean isFromDoubleTap() { + final boolean isFromDoubleTap = mIsDoubleTapEvent; + mIsDoubleTapEvent = false; + return isFromDoubleTap; + } + } + +} diff --git a/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java b/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java new file mode 100644 index 000000000000..e4e765421c06 --- /dev/null +++ b/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +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; +import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_RIGHT; +import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_TOP; +import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__LEFT_TO_CENTER; +import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__RIGHT_TO_CENTER; +import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__TOP_TO_CENTER; +import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER; +import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER; + +import android.annotation.NonNull; +import android.graphics.Rect; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.function.Supplier; + +/** + * Encapsulate logic about app compat reachability. + */ +class AppCompatReachabilityPolicy { + + @NonNull + private final ActivityRecord mActivityRecord; + @NonNull + private final AppCompatConfiguration mAppCompatConfiguration; + + AppCompatReachabilityPolicy(@NonNull ActivityRecord activityRecord, + @NonNull AppCompatConfiguration appCompatConfiguration) { + mActivityRecord = activityRecord; + mAppCompatConfiguration = appCompatConfiguration; + } + + @VisibleForTesting + void handleHorizontalDoubleTap(int x, @NonNull Supplier<Rect> innerFrameSupplier) { + final AppCompatReachabilityOverrides reachabilityOverrides = + mActivityRecord.mAppCompatController.getAppCompatReachabilityOverrides(); + if (!reachabilityOverrides.isHorizontalReachabilityEnabled() + || mActivityRecord.isInTransition()) { + return; + } + final Rect letterboxInnerFrame = innerFrameSupplier.get(); + if (letterboxInnerFrame.left <= x && letterboxInnerFrame.right >= x) { + // Only react to clicks at the sides of the letterboxed app window. + return; + } + final AppCompatDeviceStateQuery deviceStateQuery = mActivityRecord.mAppCompatController + .getAppCompatDeviceStateQuery(); + final boolean isInFullScreenBookMode = deviceStateQuery + .isDisplayFullScreenAndSeparatingHinge() + && mAppCompatConfiguration.getIsAutomaticReachabilityInBookModeEnabled(); + final int letterboxPositionForHorizontalReachability = mAppCompatConfiguration + .getLetterboxPositionForHorizontalReachability(isInFullScreenBookMode); + if (letterboxInnerFrame.left > x) { + // Moving to the next stop on the left side of the app window: right > center > left. + mAppCompatConfiguration.movePositionForHorizontalReachabilityToNextLeftStop( + isInFullScreenBookMode); + int letterboxPositionChangeForLog = + letterboxPositionForHorizontalReachability + == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER + ? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_LEFT + : LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__RIGHT_TO_CENTER; + logLetterboxPositionChange(letterboxPositionChangeForLog); + reachabilityOverrides.setDoubleTapEvent(); + } else if (letterboxInnerFrame.right < x) { + // Moving to the next stop on the right side of the app window: left > center > right. + mAppCompatConfiguration.movePositionForHorizontalReachabilityToNextRightStop( + isInFullScreenBookMode); + final int letterboxPositionChangeForLog = + letterboxPositionForHorizontalReachability + == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER + ? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_RIGHT + : LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__LEFT_TO_CENTER; + logLetterboxPositionChange(letterboxPositionChangeForLog); + reachabilityOverrides.setDoubleTapEvent(); + } + // TODO(197549949): Add animation for transition. + mActivityRecord.recomputeConfiguration(); + } + + @VisibleForTesting + void handleVerticalDoubleTap(int y, @NonNull Supplier<Rect> innerFrameSupplier) { + final AppCompatReachabilityOverrides reachabilityOverrides = + mActivityRecord.mAppCompatController.getAppCompatReachabilityOverrides(); + if (!reachabilityOverrides.isVerticalReachabilityEnabled() + || mActivityRecord.isInTransition()) { + return; + } + final Rect letterboxInnerFrame = innerFrameSupplier.get(); + if (letterboxInnerFrame.top <= y && letterboxInnerFrame.bottom >= y) { + // Only react to clicks at the top and bottom of the letterboxed app window. + return; + } + final AppCompatDeviceStateQuery deviceStateQuery = mActivityRecord.mAppCompatController + .getAppCompatDeviceStateQuery(); + final boolean isInFullScreenTabletopMode = deviceStateQuery + .isDisplayFullScreenAndSeparatingHinge(); + final int letterboxPositionForVerticalReachability = mAppCompatConfiguration + .getLetterboxPositionForVerticalReachability(isInFullScreenTabletopMode); + if (letterboxInnerFrame.top > y) { + // Moving to the next stop on the top side of the app window: bottom > center > top. + mAppCompatConfiguration.movePositionForVerticalReachabilityToNextTopStop( + isInFullScreenTabletopMode); + final int letterboxPositionChangeForLog = + letterboxPositionForVerticalReachability + == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER + ? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_TOP + : LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__BOTTOM_TO_CENTER; + logLetterboxPositionChange(letterboxPositionChangeForLog); + reachabilityOverrides.setDoubleTapEvent(); + } else if (letterboxInnerFrame.bottom < y) { + // Moving to the next stop on the bottom side of the app window: top > center > bottom. + mAppCompatConfiguration.movePositionForVerticalReachabilityToNextBottomStop( + isInFullScreenTabletopMode); + final int letterboxPositionChangeForLog = + letterboxPositionForVerticalReachability + == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER + ? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_BOTTOM + : LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__TOP_TO_CENTER; + logLetterboxPositionChange(letterboxPositionChangeForLog); + reachabilityOverrides.setDoubleTapEvent(); + } + // TODO(197549949): Add animation for transition. + mActivityRecord.recomputeConfiguration(); + } + + /** + * Logs letterbox position changes via {@link ActivityMetricsLogger#logLetterboxPositionChange}. + */ + private void logLetterboxPositionChange(int letterboxPositionChangeForLog) { + mActivityRecord.mTaskSupervisor.getActivityMetricsLogger() + .logLetterboxPositionChange(mActivityRecord, letterboxPositionChangeForLog); + } +} diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java index a4cb389f118c..8c5193ef4a52 100644 --- a/services/core/java/com/android/server/wm/AppCompatUtils.java +++ b/services/core/java/com/android/server/wm/AppCompatUtils.java @@ -98,11 +98,11 @@ class AppCompatUtils { appCompatTaskInfo.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET; appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode = CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE; - if (top == null) { return; } - + final AppCompatReachabilityOverrides reachabilityOverrides = top.mAppCompatController + .getAppCompatReachabilityOverrides(); final boolean isTopActivityResumed = top.getOrganizedTask() == task && top.isState(RESUMED); final boolean isTopActivityVisible = top.getOrganizedTask() == task && top.isVisible(); // Whether the direct top activity is in size compat mode. @@ -123,30 +123,27 @@ class AppCompatUtils { appCompatTaskInfo.isSystemFullscreenOverrideEnabled = top.mAppCompatController .getAppCompatAspectRatioOverrides().isSystemOverrideToFullscreenEnabled(); - appCompatTaskInfo.isFromLetterboxDoubleTap = top.mLetterboxUiController.isFromDoubleTap(); + appCompatTaskInfo.isFromLetterboxDoubleTap = reachabilityOverrides.isFromDoubleTap(); appCompatTaskInfo.topActivityLetterboxWidth = top.getBounds().width(); appCompatTaskInfo.topActivityLetterboxHeight = top.getBounds().height(); - // We need to consider if letterboxed or pillarboxed. // TODO(b/336807329) Encapsulate reachability logic - appCompatTaskInfo.isLetterboxDoubleTapEnabled = top.mLetterboxUiController + appCompatTaskInfo.isLetterboxDoubleTapEnabled = reachabilityOverrides .isLetterboxDoubleTapEducationEnabled(); if (appCompatTaskInfo.isLetterboxDoubleTapEnabled) { if (appCompatTaskInfo.isTopActivityPillarboxed()) { - if (top.mLetterboxUiController.allowHorizontalReachabilityForThinLetterbox()) { + if (reachabilityOverrides.allowHorizontalReachabilityForThinLetterbox()) { // Pillarboxed. appCompatTaskInfo.topActivityLetterboxHorizontalPosition = - top.mLetterboxUiController - .getLetterboxPositionForHorizontalReachability(); + reachabilityOverrides.getLetterboxPositionForHorizontalReachability(); } else { appCompatTaskInfo.isLetterboxDoubleTapEnabled = false; } } else { - if (top.mLetterboxUiController.allowVerticalReachabilityForThinLetterbox()) { + if (reachabilityOverrides.allowVerticalReachabilityForThinLetterbox()) { // Letterboxed. appCompatTaskInfo.topActivityLetterboxVerticalPosition = - top.mLetterboxUiController - .getLetterboxPositionForVerticalReachability(); + reachabilityOverrides.getLetterboxPositionForVerticalReachability(); } else { appCompatTaskInfo.isLetterboxDoubleTapEnabled = false; } diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 291eab1b2d94..eb8a637285fb 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -16,37 +16,16 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 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; -import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM; -import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__CENTER; -import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__LEFT; -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.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; -import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_RIGHT; -import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_TOP; -import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__LEFT_TO_CENTER; -import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__RIGHT_TO_CENTER; -import static com.android.internal.util.FrameworkStatsLog.LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__TOP_TO_CENTER; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND; import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING; import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR; import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_WALLPAPER; -import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER; -import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT; -import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT; -import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM; -import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER; -import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP; import static com.android.server.wm.AppCompatConfiguration.letterboxBackgroundTypeToString; import android.annotation.NonNull; @@ -68,7 +47,6 @@ import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.LetterboxDetails; import com.android.server.wm.AppCompatConfiguration.LetterboxBackgroundType; -import com.android.window.flags.Flags; import java.io.PrintWriter; @@ -92,8 +70,6 @@ final class LetterboxUiController { private boolean mLastShouldShowLetterboxUi; - private boolean mDoubleTapEvent; - LetterboxUiController(WindowManagerService wmService, ActivityRecord activityRecord) { mAppCompatConfiguration = wmService.mAppCompatConfiguration; // Given activityRecord may not be fully constructed since LetterboxUiController @@ -231,7 +207,8 @@ final class LetterboxUiController { .getTransparentPolicy().isRunning() ? mActivityRecord.getBounds() : w.getFrame(); mLetterbox.layout(spaceToFill, innerFrame, mTmpPoint); - if (mDoubleTapEvent) { + if (mActivityRecord.mAppCompatController + .getAppCompatReachabilityOverrides().isDoubleTapEvent()) { // We need to notify Shell that letterbox position has changed. mActivityRecord.getTask().dispatchTaskInfoChangedIfNeeded(true /* force */); } @@ -240,12 +217,6 @@ final class LetterboxUiController { } } - boolean isFromDoubleTap() { - final boolean isFromDoubleTap = mDoubleTapEvent; - mDoubleTapEvent = false; - return isFromDoubleTap; - } - SurfaceControl getLetterboxParentSurface() { if (mActivityRecord.isInLetterboxAnimation()) { return mActivityRecord.getTask().getSurfaceControl(); @@ -272,309 +243,35 @@ final class LetterboxUiController { && mActivityRecord.fillsParent(); } - // Check if we are in the given pose and in fullscreen mode. - // Note that we check the task rather than the parent as with ActivityEmbedding the parent might - // be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is - // actually fullscreen. If display is still in transition e.g. unfolding, don't return true - // for HALF_FOLDED state or app will flicker. - boolean isDisplayFullScreenAndInPosture(boolean isTabletop) { - Task task = mActivityRecord.getTask(); - return mActivityRecord.mDisplayContent != null && task != null - && mActivityRecord.mDisplayContent.getDisplayRotation().isDeviceInPosture( - DeviceStateController.DeviceState.HALF_FOLDED, isTabletop) - && !mActivityRecord.mDisplayContent.inTransition() - && task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN; + float getHorizontalPositionMultiplier(@NonNull Configuration parentConfiguration) { + return mActivityRecord.mAppCompatController.getAppCompatReachabilityOverrides() + .getHorizontalPositionMultiplier(parentConfiguration); } - // Note that we check the task rather than the parent as with ActivityEmbedding the parent might - // be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is - // actually fullscreen. - private boolean isDisplayFullScreenAndSeparatingHinge() { - Task task = mActivityRecord.getTask(); - return mActivityRecord.mDisplayContent != null - && mActivityRecord.mDisplayContent.getDisplayRotation().isDisplaySeparatingHinge() - && task != null - && task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN; - } - - - float getHorizontalPositionMultiplier(Configuration parentConfiguration) { - // Don't check resolved configuration because it may not be updated yet during - // configuration change. - boolean bookModeEnabled = isFullScreenAndBookModeEnabled(); - return isHorizontalReachabilityEnabled(parentConfiguration) - // Using the last global dynamic position to avoid "jumps" when moving - // between apps or activities. - ? mAppCompatConfiguration.getHorizontalMultiplierForReachability(bookModeEnabled) - : mAppCompatConfiguration.getLetterboxHorizontalPositionMultiplier(bookModeEnabled); - } - - private boolean isFullScreenAndBookModeEnabled() { - return isDisplayFullScreenAndInPosture(/* isTabletop */ false) - && mAppCompatConfiguration.getIsAutomaticReachabilityInBookModeEnabled(); - } - - float getVerticalPositionMultiplier(Configuration parentConfiguration) { - // Don't check resolved configuration because it may not be updated yet during - // configuration change. - boolean tabletopMode = isDisplayFullScreenAndInPosture(/* isTabletop */ true); - return isVerticalReachabilityEnabled(parentConfiguration) - // Using the last global dynamic position to avoid "jumps" when moving - // between apps or activities. - ? mAppCompatConfiguration.getVerticalMultiplierForReachability(tabletopMode) - : mAppCompatConfiguration.getLetterboxVerticalPositionMultiplier(tabletopMode); + float getVerticalPositionMultiplier(@NonNull Configuration parentConfiguration) { + return mActivityRecord.mAppCompatController.getAppCompatReachabilityOverrides() + .getVerticalPositionMultiplier(parentConfiguration); } boolean isLetterboxEducationEnabled() { return mAppCompatConfiguration.getIsEducationEnabled(); } - /** - * @return {@value true} if the resulting app is letterboxed in a way defined as thin. - */ - boolean isVerticalThinLetterboxed() { - final int thinHeight = mAppCompatConfiguration.getThinLetterboxHeightPx(); - if (thinHeight < 0) { - return false; - } - final Task task = mActivityRecord.getTask(); - if (task == null) { - return false; - } - final int padding = Math.abs( - task.getBounds().height() - mActivityRecord.getBounds().height()) / 2; - return padding <= thinHeight; - } - - /** - * @return {@value true} if the resulting app is pillarboxed in a way defined as thin. - */ - boolean isHorizontalThinLetterboxed() { - final int thinWidth = mAppCompatConfiguration.getThinLetterboxWidthPx(); - if (thinWidth < 0) { - return false; - } - final Task task = mActivityRecord.getTask(); - if (task == null) { - return false; - } - final int padding = Math.abs( - task.getBounds().width() - mActivityRecord.getBounds().width()) / 2; - return padding <= thinWidth; - } - - - /** - * @return {@value true} if the vertical reachability should be allowed in case of - * thin letteboxing - */ - boolean allowVerticalReachabilityForThinLetterbox() { - if (!Flags.disableThinLetterboxingPolicy()) { - return true; - } - // When the flag is enabled we allow vertical reachability only if the - // app is not thin letterboxed vertically. - return !isVerticalThinLetterboxed(); - } - - /** - * @return {@value true} if the vertical reachability should be enabled in case of - * thin letteboxing - */ - boolean allowHorizontalReachabilityForThinLetterbox() { - if (!Flags.disableThinLetterboxingPolicy()) { - return true; - } - // When the flag is enabled we allow horizontal reachability only if the - // app is not thin pillarboxed. - return !isHorizontalThinLetterboxed(); - } - - boolean shouldOverrideMinAspectRatio() { - return mActivityRecord.mAppCompatController.getAppCompatAspectRatioOverrides() - .shouldOverrideMinAspectRatio(); - } - - @AppCompatConfiguration.LetterboxVerticalReachabilityPosition - int getLetterboxPositionForVerticalReachability() { - final boolean isInFullScreenTabletopMode = isDisplayFullScreenAndSeparatingHinge(); - return mAppCompatConfiguration.getLetterboxPositionForVerticalReachability( - isInFullScreenTabletopMode); - } - - @AppCompatConfiguration.LetterboxHorizontalReachabilityPosition - int getLetterboxPositionForHorizontalReachability() { - final boolean isInFullScreenBookMode = isFullScreenAndBookModeEnabled(); - return mAppCompatConfiguration.getLetterboxPositionForHorizontalReachability( - isInFullScreenBookMode); - } - @VisibleForTesting void handleHorizontalDoubleTap(int x) { - if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) { - return; - } - - if (mLetterbox.getInnerFrame().left <= x && mLetterbox.getInnerFrame().right >= x) { - // Only react to clicks at the sides of the letterboxed app window. - return; - } - - boolean isInFullScreenBookMode = isDisplayFullScreenAndSeparatingHinge() - && mAppCompatConfiguration.getIsAutomaticReachabilityInBookModeEnabled(); - int letterboxPositionForHorizontalReachability = mAppCompatConfiguration - .getLetterboxPositionForHorizontalReachability(isInFullScreenBookMode); - if (mLetterbox.getInnerFrame().left > x) { - // Moving to the next stop on the left side of the app window: right > center > left. - mAppCompatConfiguration.movePositionForHorizontalReachabilityToNextLeftStop( - isInFullScreenBookMode); - int changeToLog = - letterboxPositionForHorizontalReachability - == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER - ? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_LEFT - : LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__RIGHT_TO_CENTER; - logLetterboxPositionChange(changeToLog); - mDoubleTapEvent = true; - } else if (mLetterbox.getInnerFrame().right < x) { - // Moving to the next stop on the right side of the app window: left > center > right. - mAppCompatConfiguration.movePositionForHorizontalReachabilityToNextRightStop( - isInFullScreenBookMode); - int changeToLog = - letterboxPositionForHorizontalReachability - == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER - ? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_RIGHT - : LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__LEFT_TO_CENTER; - logLetterboxPositionChange(changeToLog); - mDoubleTapEvent = true; - } - // TODO(197549949): Add animation for transition. - mActivityRecord.recomputeConfiguration(); + mActivityRecord.mAppCompatController.getAppCompatReachabilityPolicy() + .handleHorizontalDoubleTap(x, mLetterbox::getInnerFrame); } @VisibleForTesting void handleVerticalDoubleTap(int y) { - if (!isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) { - return; - } - - if (mLetterbox.getInnerFrame().top <= y && mLetterbox.getInnerFrame().bottom >= y) { - // Only react to clicks at the top and bottom of the letterboxed app window. - return; - } - boolean isInFullScreenTabletopMode = isDisplayFullScreenAndSeparatingHinge(); - int letterboxPositionForVerticalReachability = mAppCompatConfiguration - .getLetterboxPositionForVerticalReachability(isInFullScreenTabletopMode); - if (mLetterbox.getInnerFrame().top > y) { - // Moving to the next stop on the top side of the app window: bottom > center > top. - mAppCompatConfiguration.movePositionForVerticalReachabilityToNextTopStop( - isInFullScreenTabletopMode); - int changeToLog = - letterboxPositionForVerticalReachability - == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER - ? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_TOP - : LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__BOTTOM_TO_CENTER; - logLetterboxPositionChange(changeToLog); - mDoubleTapEvent = true; - } else if (mLetterbox.getInnerFrame().bottom < y) { - // Moving to the next stop on the bottom side of the app window: top > center > bottom. - mAppCompatConfiguration.movePositionForVerticalReachabilityToNextBottomStop( - isInFullScreenTabletopMode); - int changeToLog = - letterboxPositionForVerticalReachability - == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER - ? LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__CENTER_TO_BOTTOM - : LETTERBOX_POSITION_CHANGED__POSITION_CHANGE__TOP_TO_CENTER; - logLetterboxPositionChange(changeToLog); - mDoubleTapEvent = true; - } - // TODO(197549949): Add animation for transition. - mActivityRecord.recomputeConfiguration(); - } - - /** - * Whether horizontal reachability is enabled for an activity in the current configuration. - * - * <p>Conditions that needs to be met: - * <ul> - * <li>Windowing mode is fullscreen. - * <li>Horizontal Reachability is enabled. - * <li>First top opaque activity fills parent vertically, but not horizontally. - * </ul> - */ - private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) { - if (!allowHorizontalReachabilityForThinLetterbox()) { - return false; - } - final Rect parentAppBoundsOverride = mActivityRecord.getParentAppBoundsOverride(); - final Rect parentAppBounds = parentAppBoundsOverride != null - ? parentAppBoundsOverride : parentConfiguration.windowConfiguration.getAppBounds(); - // Use screen resolved bounds which uses resolved bounds or size compat bounds - // as activity bounds can sometimes be empty - final Rect opaqueActivityBounds = mActivityRecord.mAppCompatController - .getTransparentPolicy().getFirstOpaqueActivity() - .map(ActivityRecord::getScreenResolvedBounds) - .orElse(mActivityRecord.getScreenResolvedBounds()); - return mAppCompatConfiguration.getIsHorizontalReachabilityEnabled() - && parentConfiguration.windowConfiguration.getWindowingMode() - == WINDOWING_MODE_FULLSCREEN - // Check whether the activity fills the parent vertically. - && parentAppBounds.height() <= opaqueActivityBounds.height() - && parentAppBounds.width() > opaqueActivityBounds.width(); - } - - @VisibleForTesting - boolean isHorizontalReachabilityEnabled() { - return isHorizontalReachabilityEnabled(mActivityRecord.getParent().getConfiguration()); - } - - boolean isLetterboxDoubleTapEducationEnabled() { - return isHorizontalReachabilityEnabled() || isVerticalReachabilityEnabled(); - } - - // TODO(b/346264992): Remove after AppCompatController refactoring - private AppCompatOverrides getAppCompatOverrides() { - return mActivityRecord.mAppCompatController.getAppCompatOverrides(); - } - - /** - * Whether vertical reachability is enabled for an activity in the current configuration. - * - * <p>Conditions that needs to be met: - * <ul> - * <li>Windowing mode is fullscreen. - * <li>Vertical Reachability is enabled. - * <li>First top opaque activity fills parent horizontally but not vertically. - * </ul> - */ - private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) { - if (!allowVerticalReachabilityForThinLetterbox()) { - return false; - } - final Rect parentAppBoundsOverride = mActivityRecord.getParentAppBoundsOverride(); - final Rect parentAppBounds = parentAppBoundsOverride != null - ? parentAppBoundsOverride : parentConfiguration.windowConfiguration.getAppBounds(); - // Use screen resolved bounds which uses resolved bounds or size compat bounds - // as activity bounds can sometimes be empty. - final Rect opaqueActivityBounds = mActivityRecord.mAppCompatController - .getTransparentPolicy().getFirstOpaqueActivity() - .map(ActivityRecord::getScreenResolvedBounds) - .orElse(mActivityRecord.getScreenResolvedBounds()); - return mAppCompatConfiguration.getIsVerticalReachabilityEnabled() - && parentConfiguration.windowConfiguration.getWindowingMode() - == WINDOWING_MODE_FULLSCREEN - // Check whether the activity fills the parent horizontally. - && parentAppBounds.width() <= opaqueActivityBounds.width() - && parentAppBounds.height() > opaqueActivityBounds.height(); - } - - @VisibleForTesting - boolean isVerticalReachabilityEnabled() { - return isVerticalReachabilityEnabled(mActivityRecord.getParent().getConfiguration()); + mActivityRecord.mAppCompatController.getAppCompatReachabilityPolicy() + .handleVerticalDoubleTap(y, mLetterbox::getInnerFrame); } @VisibleForTesting boolean shouldShowLetterboxUi(WindowState mainWindow) { - if (getAppCompatOverrides().getAppCompatOrientationOverrides() + if (mActivityRecord.mAppCompatController.getAppCompatOrientationOverrides() .getIsRelaunchingAfterRequestedOrientationChanged()) { return mLastShouldShowLetterboxUi; } @@ -818,8 +515,10 @@ final class LetterboxUiController { if (!shouldShowLetterboxUi) { return; } - pw.println(prefix + " isVerticalThinLetterboxed=" + isVerticalThinLetterboxed()); - pw.println(prefix + " isHorizontalThinLetterboxed=" + isHorizontalThinLetterboxed()); + pw.println(prefix + " isVerticalThinLetterboxed=" + mActivityRecord.mAppCompatController + .getAppCompatReachabilityOverrides().isVerticalThinLetterboxed()); + pw.println(prefix + " isHorizontalThinLetterboxed=" + mActivityRecord.mAppCompatController + .getAppCompatReachabilityOverrides().isHorizontalThinLetterboxed()); pw.println(prefix + " letterboxBackgroundColor=" + Integer.toHexString( getLetterboxBackgroundColor().toArgb())); pw.println(prefix + " letterboxBackgroundType=" @@ -836,10 +535,12 @@ final class LetterboxUiController { pw.println(prefix + " letterboxBackgroundWallpaperBlurRadius=" + getLetterboxWallpaperBlurRadiusPx()); } - + final AppCompatReachabilityOverrides reachabilityOverrides = mActivityRecord + .mAppCompatController.getAppCompatReachabilityOverrides(); pw.println(prefix + " isHorizontalReachabilityEnabled=" - + isHorizontalReachabilityEnabled()); - pw.println(prefix + " isVerticalReachabilityEnabled=" + isVerticalReachabilityEnabled()); + + reachabilityOverrides.isHorizontalReachabilityEnabled()); + pw.println(prefix + " isVerticalReachabilityEnabled=" + + reachabilityOverrides.isVerticalReachabilityEnabled()); pw.println(prefix + " letterboxHorizontalPositionMultiplier=" + getHorizontalPositionMultiplier(mActivityRecord.getParent().getConfiguration())); pw.println(prefix + " letterboxVerticalPositionMultiplier=" @@ -883,64 +584,6 @@ final class LetterboxUiController { return "UNKNOWN_REASON"; } - private int letterboxHorizontalReachabilityPositionToLetterboxPosition( - @AppCompatConfiguration.LetterboxHorizontalReachabilityPosition int position) { - switch (position) { - case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT: - return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__LEFT; - case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER: - return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__CENTER; - case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT: - return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__RIGHT; - default: - throw new AssertionError( - "Unexpected letterbox horizontal reachability position type: " - + position); - } - } - - private int letterboxVerticalReachabilityPositionToLetterboxPosition( - @AppCompatConfiguration.LetterboxVerticalReachabilityPosition int position) { - switch (position) { - case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP: - return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__TOP; - case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER: - return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__CENTER; - case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM: - return APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM; - default: - throw new AssertionError( - "Unexpected letterbox vertical reachability position type: " - + position); - } - } - - int getLetterboxPositionForLogging() { - int positionToLog = APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__UNKNOWN_POSITION; - if (isHorizontalReachabilityEnabled()) { - int letterboxPositionForHorizontalReachability = mAppCompatConfiguration - .getLetterboxPositionForHorizontalReachability( - isDisplayFullScreenAndInPosture(/* isTabletop */ false)); - positionToLog = letterboxHorizontalReachabilityPositionToLetterboxPosition( - letterboxPositionForHorizontalReachability); - } else if (isVerticalReachabilityEnabled()) { - int letterboxPositionForVerticalReachability = mAppCompatConfiguration - .getLetterboxPositionForVerticalReachability( - isDisplayFullScreenAndInPosture(/* isTabletop */ true)); - positionToLog = letterboxVerticalReachabilityPositionToLetterboxPosition( - letterboxPositionForVerticalReachability); - } - return positionToLog; - } - - /** - * Logs letterbox position changes via {@link ActivityMetricsLogger#logLetterboxPositionChange}. - */ - private void logLetterboxPositionChange(int letterboxPositionChange) { - mActivityRecord.mTaskSupervisor.getActivityMetricsLogger() - .logLetterboxPositionChange(mActivityRecord, letterboxPositionChange); - } - @Nullable LetterboxDetails getLetterboxDetails() { final WindowState w = mActivityRecord.findMainWindow(); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 7ada4c7f9c09..d3df5fdcc447 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3389,7 +3389,6 @@ class Task extends TaskFragment { info.isTopActivityTransparent = top != null && !top.fillsParent(); info.isTopActivityStyleFloating = top != null && top.isStyleFloating(); info.lastNonFullscreenBounds = topTask.mLastNonFullscreenBounds; - AppCompatUtils.fillAppCompatTaskInfo(this, info, top); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index 61a6f316244c..33df5d896f7f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -300,7 +300,9 @@ public class LetterboxUiControllerTest extends WindowTestsBase { // Vertical thin letterbox disabled doReturn(-1).when(mActivity.mWmService.mAppCompatConfiguration) .getThinLetterboxHeightPx(); - assertFalse(mController.isVerticalThinLetterboxed()); + final AppCompatReachabilityOverrides reachabilityOverrides = mActivity.mAppCompatController + .getAppCompatReachabilityOverrides(); + assertFalse(reachabilityOverrides.isVerticalThinLetterboxed()); // Define a Task 100x100 final Task task = mock(Task.class); doReturn(new Rect(0, 0, 100, 100)).when(task).getBounds(); @@ -309,21 +311,21 @@ public class LetterboxUiControllerTest extends WindowTestsBase { // Vertical thin letterbox disabled without Task doReturn(null).when(mActivity).getTask(); - assertFalse(mController.isVerticalThinLetterboxed()); + assertFalse(reachabilityOverrides.isVerticalThinLetterboxed()); // Assign a Task for the Activity doReturn(task).when(mActivity).getTask(); // (task.width() - act.width()) / 2 = 5 < 10 doReturn(new Rect(5, 5, 95, 95)).when(mActivity).getBounds(); - assertTrue(mController.isVerticalThinLetterboxed()); + assertTrue(reachabilityOverrides.isVerticalThinLetterboxed()); // (task.width() - act.width()) / 2 = 10 = 10 doReturn(new Rect(10, 10, 90, 90)).when(mActivity).getBounds(); - assertTrue(mController.isVerticalThinLetterboxed()); + assertTrue(reachabilityOverrides.isVerticalThinLetterboxed()); // (task.width() - act.width()) / 2 = 11 > 10 doReturn(new Rect(11, 11, 89, 89)).when(mActivity).getBounds(); - assertFalse(mController.isVerticalThinLetterboxed()); + assertFalse(reachabilityOverrides.isVerticalThinLetterboxed()); } @Test @@ -331,7 +333,9 @@ public class LetterboxUiControllerTest extends WindowTestsBase { // Horizontal thin letterbox disabled doReturn(-1).when(mActivity.mWmService.mAppCompatConfiguration) .getThinLetterboxWidthPx(); - assertFalse(mController.isHorizontalThinLetterboxed()); + final AppCompatReachabilityOverrides reachabilityOverrides = mActivity.mAppCompatController + .getAppCompatReachabilityOverrides(); + assertFalse(reachabilityOverrides.isHorizontalThinLetterboxed()); // Define a Task 100x100 final Task task = mock(Task.class); doReturn(new Rect(0, 0, 100, 100)).when(task).getBounds(); @@ -340,51 +344,55 @@ public class LetterboxUiControllerTest extends WindowTestsBase { // Vertical thin letterbox disabled without Task doReturn(null).when(mActivity).getTask(); - assertFalse(mController.isHorizontalThinLetterboxed()); + assertFalse(reachabilityOverrides.isHorizontalThinLetterboxed()); // Assign a Task for the Activity doReturn(task).when(mActivity).getTask(); // (task.height() - act.height()) / 2 = 5 < 10 doReturn(new Rect(5, 5, 95, 95)).when(mActivity).getBounds(); - assertTrue(mController.isHorizontalThinLetterboxed()); + assertTrue(reachabilityOverrides.isHorizontalThinLetterboxed()); // (task.height() - act.height()) / 2 = 10 = 10 doReturn(new Rect(10, 10, 90, 90)).when(mActivity).getBounds(); - assertTrue(mController.isHorizontalThinLetterboxed()); + assertTrue(reachabilityOverrides.isHorizontalThinLetterboxed()); // (task.height() - act.height()) / 2 = 11 > 10 doReturn(new Rect(11, 11, 89, 89)).when(mActivity).getBounds(); - assertFalse(mController.isHorizontalThinLetterboxed()); + assertFalse(reachabilityOverrides.isHorizontalThinLetterboxed()); } @Test @EnableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_POLICY) public void testAllowReachabilityForThinLetterboxWithFlagEnabled() { - spyOn(mController); - doReturn(true).when(mController).isVerticalThinLetterboxed(); - assertFalse(mController.allowVerticalReachabilityForThinLetterbox()); - doReturn(true).when(mController).isHorizontalThinLetterboxed(); - assertFalse(mController.allowHorizontalReachabilityForThinLetterbox()); - - doReturn(false).when(mController).isVerticalThinLetterboxed(); - assertTrue(mController.allowVerticalReachabilityForThinLetterbox()); - doReturn(false).when(mController).isHorizontalThinLetterboxed(); - assertTrue(mController.allowHorizontalReachabilityForThinLetterbox()); + final AppCompatReachabilityOverrides reachabilityOverrides = + mActivity.mAppCompatController.getAppCompatReachabilityOverrides(); + spyOn(reachabilityOverrides); + doReturn(true).when(reachabilityOverrides).isVerticalThinLetterboxed(); + assertFalse(reachabilityOverrides.allowVerticalReachabilityForThinLetterbox()); + doReturn(true).when(reachabilityOverrides).isHorizontalThinLetterboxed(); + assertFalse(reachabilityOverrides.allowHorizontalReachabilityForThinLetterbox()); + + doReturn(false).when(reachabilityOverrides).isVerticalThinLetterboxed(); + assertTrue(reachabilityOverrides.allowVerticalReachabilityForThinLetterbox()); + doReturn(false).when(reachabilityOverrides).isHorizontalThinLetterboxed(); + assertTrue(reachabilityOverrides.allowHorizontalReachabilityForThinLetterbox()); } @Test @DisableFlags(Flags.FLAG_DISABLE_THIN_LETTERBOXING_POLICY) public void testAllowReachabilityForThinLetterboxWithFlagDisabled() { - spyOn(mController); - doReturn(true).when(mController).isVerticalThinLetterboxed(); - assertTrue(mController.allowVerticalReachabilityForThinLetterbox()); - doReturn(true).when(mController).isHorizontalThinLetterboxed(); - assertTrue(mController.allowHorizontalReachabilityForThinLetterbox()); - - doReturn(false).when(mController).isVerticalThinLetterboxed(); - assertTrue(mController.allowVerticalReachabilityForThinLetterbox()); - doReturn(false).when(mController).isHorizontalThinLetterboxed(); - assertTrue(mController.allowHorizontalReachabilityForThinLetterbox()); + final AppCompatReachabilityOverrides reachabilityOverrides = + mActivity.mAppCompatController.getAppCompatReachabilityOverrides(); + spyOn(reachabilityOverrides); + doReturn(true).when(reachabilityOverrides).isVerticalThinLetterboxed(); + assertTrue(reachabilityOverrides.allowVerticalReachabilityForThinLetterbox()); + doReturn(true).when(reachabilityOverrides).isHorizontalThinLetterboxed(); + assertTrue(reachabilityOverrides.allowHorizontalReachabilityForThinLetterbox()); + + doReturn(false).when(reachabilityOverrides).isVerticalThinLetterboxed(); + assertTrue(reachabilityOverrides.allowVerticalReachabilityForThinLetterbox()); + doReturn(false).when(reachabilityOverrides).isHorizontalThinLetterboxed(); + assertTrue(reachabilityOverrides.allowHorizontalReachabilityForThinLetterbox()); } @Test 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 ed93a8c6ecff..7dc3b07b6ce2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -3431,9 +3431,10 @@ public class SizeCompatTests extends WindowTestsBase { mActivity.getWindowConfiguration().setBounds(null); setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ false); - - assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); - assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); + final AppCompatReachabilityOverrides reachabilityOverrides = + mActivity.mAppCompatController.getAppCompatReachabilityOverrides(); + assertFalse(reachabilityOverrides.isVerticalReachabilityEnabled()); + assertFalse(reachabilityOverrides.isHorizontalReachabilityEnabled()); } @Test @@ -3456,7 +3457,8 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); // Horizontal reachability is disabled because the app is in split screen. - assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); + assertFalse(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isHorizontalReachabilityEnabled()); } @Test @@ -3479,7 +3481,8 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); // Vertical reachability is disabled because the app is in split screen. - assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); + assertFalse(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isVerticalReachabilityEnabled()); } @Test @@ -3501,7 +3504,8 @@ public class SizeCompatTests extends WindowTestsBase { // Vertical reachability is disabled because the app does not match parent width assertNotEquals(mActivity.getScreenResolvedBounds().width(), mActivity.mDisplayContent.getBounds().width()); - assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); + assertFalse(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isVerticalReachabilityEnabled()); } @Test @@ -3518,7 +3522,8 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds()); // Vertical reachability is still enabled as resolved bounds is not empty - assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); + assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isVerticalReachabilityEnabled()); } @Test @@ -3535,7 +3540,8 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds()); // Horizontal reachability is still enabled as resolved bounds is not empty - assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); + assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isHorizontalReachabilityEnabled()); } @Test @@ -3549,7 +3555,8 @@ public class SizeCompatTests extends WindowTestsBase { prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, SCREEN_ORIENTATION_PORTRAIT); - assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); + assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isHorizontalReachabilityEnabled()); } @Test @@ -3563,7 +3570,8 @@ public class SizeCompatTests extends WindowTestsBase { prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, SCREEN_ORIENTATION_LANDSCAPE); - assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); + assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isVerticalReachabilityEnabled()); } @Test @@ -3585,7 +3593,8 @@ public class SizeCompatTests extends WindowTestsBase { // Horizontal reachability is disabled because the app does not match parent height assertNotEquals(mActivity.getScreenResolvedBounds().height(), mActivity.mDisplayContent.getBounds().height()); - assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); + assertFalse(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isHorizontalReachabilityEnabled()); } @Test @@ -3607,7 +3616,8 @@ public class SizeCompatTests extends WindowTestsBase { // Horizontal reachability is enabled because the app matches parent height assertEquals(mActivity.getScreenResolvedBounds().height(), mActivity.mDisplayContent.getBounds().height()); - assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); + assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isHorizontalReachabilityEnabled()); } @Test @@ -3629,7 +3639,8 @@ public class SizeCompatTests extends WindowTestsBase { // Vertical reachability is enabled because the app matches parent width assertEquals(mActivity.getScreenResolvedBounds().width(), mActivity.mDisplayContent.getBounds().width()); - assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); + assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + .isVerticalReachabilityEnabled()); } @Test @@ -4809,10 +4820,12 @@ public class SizeCompatTests extends WindowTestsBase { } private void setUpAllowThinLetterboxed(boolean thinLetterboxAllowed) { - spyOn(mActivity.mLetterboxUiController); - doReturn(thinLetterboxAllowed).when(mActivity.mLetterboxUiController) + final AppCompatReachabilityOverrides reachabilityOverrides = + mActivity.mAppCompatController.getAppCompatReachabilityOverrides(); + spyOn(reachabilityOverrides); + doReturn(thinLetterboxAllowed).when(reachabilityOverrides) .allowVerticalReachabilityForThinLetterbox(); - doReturn(thinLetterboxAllowed).when(mActivity.mLetterboxUiController) + doReturn(thinLetterboxAllowed).when(reachabilityOverrides) .allowHorizontalReachabilityForThinLetterbox(); } |