1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 20 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 21 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.content.Context; 26 import android.graphics.Color; 27 import android.provider.DeviceConfig; 28 29 import com.android.internal.R; 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.server.wm.utils.DimenPxIntSupplier; 32 33 import java.io.PrintWriter; 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.util.function.Function; 37 38 /** Reads app compatibility configs from resources and controls their overrides at runtime. */ 39 final class AppCompatConfiguration { 40 41 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppCompatConfiguration" : TAG_ATM; 42 43 // Whether camera compatibility treatment is enabled. 44 // See DisplayRotationCompatPolicy for context. 45 private static final String KEY_ENABLE_CAMERA_COMPAT_TREATMENT = 46 "enable_compat_camera_treatment"; 47 48 private static final boolean DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT = true; 49 50 // Whether enabling rotation compat policy for immersive apps that prevents auto 51 // rotation into non-optimal screen orientation while in fullscreen. This is needed 52 // because immersive apps, such as games, are often not optimized for all 53 // orientations and can have a poor UX when rotated. Additionally, some games rely 54 // on sensors for the gameplay so users can trigger such rotations accidentally 55 // when auto rotation is on. 56 private static final String KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY = 57 "enable_display_rotation_immersive_app_compat_policy"; 58 59 private static final boolean DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY = 60 true; 61 62 // Whether ignore orientation request is allowed 63 private static final String KEY_ALLOW_IGNORE_ORIENTATION_REQUEST = 64 "allow_ignore_orientation_request"; 65 66 private static final boolean DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST = true; 67 68 // Whether sending compat fake focus is enabled for unfocused apps in splitscreen. 69 // Some game engines wait to get focus before drawing the content of the app so 70 // this needs to be used otherwise the apps get blacked out when they are resumed 71 // and do not have focus yet. 72 private static final String KEY_ENABLE_COMPAT_FAKE_FOCUS = "enable_compat_fake_focus"; 73 74 private static final boolean DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS = true; 75 76 // Whether translucent activities policy is enabled 77 private static final String KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY = 78 "enable_letterbox_translucent_activity"; 79 80 private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY = true; 81 82 // Whether per-app user aspect ratio override settings is enabled 83 private static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS = 84 "enable_app_compat_aspect_ratio_user_settings"; 85 86 // TODO(b/288142656): Enable user aspect ratio settings by default. 87 private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = true; 88 89 // Whether per-app fullscreen user aspect ratio override option is enabled 90 private static final String KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = 91 "enable_app_compat_user_aspect_ratio_fullscreen"; 92 private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN = true; 93 94 // Whether the letterbox wallpaper style is enabled by default 95 private static final String KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER = 96 "enable_letterbox_background_wallpaper"; 97 98 // TODO(b/290048978): Enable wallpaper as default letterbox background. 99 private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER = false; 100 101 /** 102 * Override of aspect ratio for fixed orientation letterboxing that is set via ADB with 103 * set-fixed-orientation-letterbox-aspect-ratio or via {@link 104 * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored 105 * if it is <= this value. 106 */ 107 static final float MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO = 1.0f; 108 109 /** The default aspect ratio for a letterboxed app in multi-window mode. */ 110 static final float DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW = 1.01f; 111 112 /** Letterboxed app window position multiplier indicating center position. */ 113 static final float LETTERBOX_POSITION_MULTIPLIER_CENTER = 0.5f; 114 115 /** Enum for Letterbox background type. */ 116 @Retention(RetentionPolicy.SOURCE) 117 @IntDef({LETTERBOX_BACKGROUND_OVERRIDE_UNSET, 118 LETTERBOX_BACKGROUND_SOLID_COLOR, 119 LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND, 120 LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING, 121 LETTERBOX_BACKGROUND_WALLPAPER}) 122 @interface LetterboxBackgroundType {}; 123 124 /** No letterbox background style set. Using the one defined by DeviceConfig. */ 125 static final int LETTERBOX_BACKGROUND_OVERRIDE_UNSET = -1; 126 127 /** Solid background using color specified in R.color.config_letterboxBackgroundColor. */ 128 static final int LETTERBOX_BACKGROUND_SOLID_COLOR = 0; 129 130 /** Color specified in R.attr.colorBackground for the letterboxed application. */ 131 static final int LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND = 1; 132 133 /** Color specified in R.attr.colorBackgroundFloating for the letterboxed application. */ 134 static final int LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING = 2; 135 136 /** Using wallpaper as a background which can be blurred or dimmed with dark scrim. */ 137 static final int LETTERBOX_BACKGROUND_WALLPAPER = 3; 138 139 /** 140 * Enum for Letterbox horizontal reachability position types. 141 * 142 * <p>Order from left to right is important since it's used in {@link 143 * #movePositionForReachabilityToNextRightStop} and {@link 144 * #movePositionForReachabilityToNextLeftStop}. 145 */ 146 @Retention(RetentionPolicy.SOURCE) 147 @IntDef({LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT, 148 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER, 149 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT}) 150 @interface LetterboxHorizontalReachabilityPosition {}; 151 152 /** Letterboxed app window is aligned to the left side. */ 153 static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT = 0; 154 155 /** Letterboxed app window is positioned in the horizontal center. */ 156 static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER = 1; 157 158 /** Letterboxed app window is aligned to the right side. */ 159 static final int LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT = 2; 160 161 /** 162 * Enum for Letterbox vertical reachability position types. 163 * 164 * <p>Order from top to bottom is important since it's used in {@link 165 * #movePositionForReachabilityToNextBottomStop} and {@link 166 * #movePositionForReachabilityToNextTopStop}. 167 */ 168 @Retention(RetentionPolicy.SOURCE) 169 @IntDef({LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP, 170 LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER, 171 LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM}) 172 @interface LetterboxVerticalReachabilityPosition {}; 173 174 /** Letterboxed app window is aligned to the left side. */ 175 static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP = 0; 176 177 /** Letterboxed app window is positioned in the vertical center. */ 178 static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER = 1; 179 180 /** Letterboxed app window is aligned to the right side. */ 181 static final int LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM = 2; 182 183 final Context mContext; 184 185 // Responsible for the persistence of letterbox[Horizontal|Vertical]PositionMultiplier 186 @NonNull 187 private final AppCompatConfigurationPersister mAppCompatConfigurationPersister; 188 189 // Aspect ratio of letterbox for fixed orientation, values <= 190 // MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO will be ignored. 191 private float mFixedOrientationLetterboxAspectRatio; 192 193 // Default min aspect ratio for unresizable apps that are eligible for the size compat mode. 194 private float mDefaultMinAspectRatioForUnresizableApps; 195 196 // Corners radius for activities presented in the letterbox mode, values < 0 will be ignored. 197 private int mLetterboxActivityCornersRadius; 198 199 // Color for {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} letterbox background type. 200 @Nullable private Color mLetterboxBackgroundColorOverride; 201 202 // Color resource id for {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} letterbox background type. 203 @Nullable private Integer mLetterboxBackgroundColorResourceIdOverride; 204 205 @LetterboxBackgroundType 206 private final int mLetterboxBackgroundType; 207 208 // Blur radius for LETTERBOX_BACKGROUND_WALLPAPER option from getLetterboxBackgroundType(). 209 // Values <= 0 are ignored and 0 is used instead. 210 private int mLetterboxBackgroundWallpaperBlurRadiusPx; 211 212 // Alpha of a black scrim shown over wallpaper letterbox background when 213 // LETTERBOX_BACKGROUND_WALLPAPER option is returned from getLetterboxBackgroundType(). 214 // Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead. 215 private float mLetterboxBackgroundWallpaperDarkScrimAlpha; 216 217 // Horizontal position of a center of the letterboxed app window. 0 corresponds to the left 218 // side of the screen and 1.0 to the right side. 219 private float mLetterboxHorizontalPositionMultiplier; 220 221 // Vertical position of a center of the letterboxed app window. 0 corresponds to the top 222 // side of the screen and 1.0 to the bottom side. 223 private float mLetterboxVerticalPositionMultiplier; 224 225 // Horizontal position of a center of the letterboxed app window when the device is half-folded. 226 // 0 corresponds to the left side of the screen and 1.0 to the right side. 227 private float mLetterboxBookModePositionMultiplier; 228 229 // Vertical position of a center of the letterboxed app window when the device is half-folded. 230 // 0 corresponds to the top side of the screen and 1.0 to the bottom side. 231 private float mLetterboxTabletopModePositionMultiplier; 232 233 // Default horizontal position the letterboxed app window when horizontal reachability is 234 // enabled and an app is fullscreen in landscape device orientation. 235 // It is used as a starting point for mLetterboxPositionForHorizontalReachability. 236 @LetterboxHorizontalReachabilityPosition 237 private int mDefaultPositionForHorizontalReachability; 238 239 // Default vertical position the letterboxed app window when vertical reachability is enabled 240 // and an app is fullscreen in portrait device orientation. 241 // It is used as a starting point for mLetterboxPositionForVerticalReachability. 242 @LetterboxVerticalReachabilityPosition 243 private int mDefaultPositionForVerticalReachability; 244 245 // Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in 246 // landscape device orientation. 247 private boolean mIsHorizontalReachabilityEnabled; 248 249 // Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in 250 // portrait device orientation. 251 private boolean mIsVerticalReachabilityEnabled; 252 253 // Whether book mode automatic horizontal reachability positioning is allowed for letterboxed 254 // fullscreen apps in landscape device orientation. 255 private boolean mIsAutomaticReachabilityInBookModeEnabled; 256 257 // Whether education is allowed for letterboxed fullscreen apps. 258 private boolean mIsEducationEnabled; 259 260 // Whether using split screen aspect ratio as a default aspect ratio for unresizable apps. 261 private boolean mIsSplitScreenAspectRatioForUnresizableAppsEnabled; 262 263 // Whether using display aspect ratio as a default aspect ratio for all letterboxed apps. 264 // mIsSplitScreenAspectRatioForUnresizableAppsEnabled and 265 // config_letterboxDefaultMinAspectRatioForUnresizableApps take priority over this for 266 // unresizable apps 267 private boolean mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox; 268 269 // Supplier for the value in pixel to consider when detecting vertical thin letterboxing 270 private final DimenPxIntSupplier mThinLetterboxWidthPxSupplier; 271 272 // Supplier for the value in pixel to consider when detecting horizontal thin letterboxing 273 private final DimenPxIntSupplier mThinLetterboxHeightPxSupplier; 274 275 // Allows to enable letterboxing strategy for translucent activities ignoring flags. 276 private boolean mTranslucentLetterboxingOverrideEnabled; 277 278 // Allows to enable user aspect ratio settings ignoring flags. 279 private boolean mUserAppAspectRatioSettingsOverrideEnabled; 280 281 // Allows to enable fullscreen option in user aspect ratio settings ignoring flags. 282 private boolean mUserAppAspectRatioFullscreenOverrideEnabled; 283 284 // The override for letterbox background type in case it's different from 285 // LETTERBOX_BACKGROUND_OVERRIDE_UNSET 286 @LetterboxBackgroundType 287 private int mLetterboxBackgroundTypeOverride = LETTERBOX_BACKGROUND_OVERRIDE_UNSET; 288 289 // Whether we should use split screen aspect ratio for the activity when camera compat treatment 290 // is enabled and activity is connected to the camera in fullscreen. 291 private final boolean mIsCameraCompatSplitScreenAspectRatioEnabled; 292 293 // Which aspect ratio to use when camera compat treatment is enabled and an activity eligible 294 // for treatment is connected to the camera. 295 private float mCameraCompatAspectRatio; 296 297 // Whether activity "refresh" in camera compatibility treatment is enabled. 298 // See RefreshCallbackItem for context. 299 private boolean mIsCameraCompatTreatmentRefreshEnabled = true; 300 301 // Whether activity "refresh" in camera compatibility treatment should happen using the 302 // "stopped -> resumed" cycle rather than "paused -> resumed" cycle. Using "stop -> resumed" 303 // cycle by default due to higher success rate confirmed with app compatibility testing. 304 // See RefreshCallbackItem for context. 305 private boolean mIsCameraCompatRefreshCycleThroughStopEnabled = true; 306 307 // Whether camera compat freeform treatment should be enabled for all eligible activities. 308 // This has the same effect as enabling the per-app override 309 // ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT for every app. 310 private boolean mIsCameraCompatFreeformWindowingTreatmentEnabled = false; 311 312 // Whether should ignore app requested orientation in response to an app 313 // calling Activity#setRequestedOrientation. See 314 // AppCompatOrientationPolicy#shouldIgnoreRequestedOrientation for details. 315 private final boolean mIsPolicyForIgnoringRequestedOrientationEnabled; 316 317 // Flags dynamically updated with {@link android.provider.DeviceConfig}. 318 @NonNull private final SynchedDeviceConfig mDeviceConfig; 319 AppCompatConfiguration(@onNull final Context systemUiContext)320 AppCompatConfiguration(@NonNull final Context systemUiContext) { 321 this(systemUiContext, new AppCompatConfigurationPersister( 322 () -> readLetterboxHorizontalReachabilityPositionFromConfig( 323 systemUiContext, /* forBookMode */ false), 324 () -> readLetterboxVerticalReachabilityPositionFromConfig( 325 systemUiContext, /* forTabletopMode */ false), 326 () -> readLetterboxHorizontalReachabilityPositionFromConfig( 327 systemUiContext, /* forBookMode */ true), 328 () -> readLetterboxVerticalReachabilityPositionFromConfig( 329 systemUiContext, /* forTabletopMode */ true))); 330 } 331 332 @VisibleForTesting AppCompatConfiguration(@onNull final Context systemUiContext, @NonNull final AppCompatConfigurationPersister appCompatConfigurationPersister)333 AppCompatConfiguration(@NonNull final Context systemUiContext, 334 @NonNull final AppCompatConfigurationPersister appCompatConfigurationPersister) { 335 mContext = systemUiContext; 336 337 mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat( 338 R.dimen.config_fixedOrientationLetterboxAspectRatio); 339 mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext); 340 mLetterboxActivityCornersRadius = mContext.getResources().getInteger( 341 R.integer.config_letterboxActivityCornersRadius); 342 mLetterboxBackgroundWallpaperBlurRadiusPx = mContext.getResources().getDimensionPixelSize( 343 R.dimen.config_letterboxBackgroundWallpaperBlurRadius); 344 mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat( 345 R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha); 346 setLetterboxHorizontalPositionMultiplier(mContext.getResources().getFloat( 347 R.dimen.config_letterboxHorizontalPositionMultiplier)); 348 setLetterboxVerticalPositionMultiplier(mContext.getResources().getFloat( 349 R.dimen.config_letterboxVerticalPositionMultiplier)); 350 setLetterboxBookModePositionMultiplier(mContext.getResources().getFloat( 351 R.dimen.config_letterboxBookModePositionMultiplier)); 352 setLetterboxTabletopModePositionMultiplier(mContext.getResources() 353 .getFloat(R.dimen.config_letterboxTabletopModePositionMultiplier)); 354 mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean( 355 R.bool.config_letterboxIsHorizontalReachabilityEnabled); 356 mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean( 357 R.bool.config_letterboxIsVerticalReachabilityEnabled); 358 mIsAutomaticReachabilityInBookModeEnabled = mContext.getResources().getBoolean( 359 R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled); 360 mDefaultPositionForHorizontalReachability = 361 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, false); 362 mDefaultPositionForVerticalReachability = 363 readLetterboxVerticalReachabilityPositionFromConfig(mContext, false); 364 mIsEducationEnabled = mContext.getResources().getBoolean( 365 R.bool.config_letterboxIsEducationEnabled); 366 setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat( 367 R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps)); 368 mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean( 369 R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled); 370 mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = mContext.getResources() 371 .getBoolean(R.bool 372 .config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled); 373 mIsCameraCompatSplitScreenAspectRatioEnabled = mContext.getResources().getBoolean( 374 R.bool.config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled); 375 mCameraCompatAspectRatio = mContext.getResources().getFloat( 376 R.dimen.config_windowManagerCameraCompatAspectRatio); 377 mIsPolicyForIgnoringRequestedOrientationEnabled = mContext.getResources().getBoolean( 378 R.bool.config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled); 379 380 mThinLetterboxWidthPxSupplier = new DimenPxIntSupplier(mContext, 381 R.dimen.config_letterboxThinLetterboxWidthDp); 382 mThinLetterboxHeightPxSupplier = new DimenPxIntSupplier(mContext, 383 R.dimen.config_letterboxThinLetterboxHeightDp); 384 385 mAppCompatConfigurationPersister = appCompatConfigurationPersister; 386 mAppCompatConfigurationPersister.start(); 387 388 mDeviceConfig = SynchedDeviceConfig.builder(DeviceConfig.NAMESPACE_WINDOW_MANAGER, 389 systemUiContext.getMainExecutor()) 390 .addDeviceConfigEntry(KEY_ENABLE_CAMERA_COMPAT_TREATMENT, 391 DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT, 392 mContext.getResources().getBoolean( 393 R.bool.config_isWindowManagerCameraCompatTreatmentEnabled)) 394 .addDeviceConfigEntry(KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY, 395 DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY, 396 mContext.getResources().getBoolean(R.bool 397 .config_letterboxIsDisplayRotationImmersiveAppCompatPolicyEnabled)) 398 .addDeviceConfigEntry(KEY_ALLOW_IGNORE_ORIENTATION_REQUEST, 399 DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST, /* enabled */ true) 400 .addDeviceConfigEntry(KEY_ENABLE_COMPAT_FAKE_FOCUS, 401 DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS, 402 mContext.getResources().getBoolean(R.bool.config_isCompatFakeFocusEnabled)) 403 .addDeviceConfigEntry(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY, 404 DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY, 405 mContext.getResources().getBoolean( 406 R.bool.config_letterboxIsEnabledForTranslucentActivities)) 407 .addDeviceConfigEntry(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS, 408 DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS, 409 mContext.getResources().getBoolean( 410 R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled)) 411 .addDeviceConfigEntry(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER, 412 DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER, /* enabled */ true) 413 .addDeviceConfigEntry(KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN, 414 DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN, 415 mContext.getResources().getBoolean( 416 R.bool.config_appCompatUserAppAspectRatioFullscreenIsEnabled)) 417 .build(); 418 } 419 420 /** 421 * Whether enabling ignoreOrientationRequest is allowed on the device. This value is controlled 422 * via {@link android.provider.DeviceConfig}. 423 */ isIgnoreOrientationRequestAllowed()424 boolean isIgnoreOrientationRequestAllowed() { 425 return mDeviceConfig.getFlagValue(KEY_ALLOW_IGNORE_ORIENTATION_REQUEST); 426 } 427 428 /** 429 * Overrides the aspect ratio of letterbox for fixed orientation. If given value is <= {@link 430 * #MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO}, both it and a value of {@link 431 * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored and 432 * the framework implementation will be used to determine the aspect ratio. 433 */ setFixedOrientationLetterboxAspectRatio(float aspectRatio)434 void setFixedOrientationLetterboxAspectRatio(float aspectRatio) { 435 mFixedOrientationLetterboxAspectRatio = aspectRatio; 436 } 437 438 /** 439 * Resets the aspect ratio of letterbox for fixed orientation to {@link 440 * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}. 441 */ resetFixedOrientationLetterboxAspectRatio()442 void resetFixedOrientationLetterboxAspectRatio() { 443 mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat( 444 com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio); 445 } 446 447 /** 448 * Gets the aspect ratio of letterbox for fixed orientation. 449 */ getFixedOrientationLetterboxAspectRatio()450 float getFixedOrientationLetterboxAspectRatio() { 451 return mFixedOrientationLetterboxAspectRatio; 452 } 453 454 /** 455 * Resets the min aspect ratio for unresizable apps that are eligible for size compat mode. 456 */ resetDefaultMinAspectRatioForUnresizableApps()457 void resetDefaultMinAspectRatioForUnresizableApps() { 458 setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat( 459 R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps)); 460 } 461 462 /** 463 * Gets the min aspect ratio for unresizable apps that are eligible for size compat mode. 464 */ getDefaultMinAspectRatioForUnresizableApps()465 float getDefaultMinAspectRatioForUnresizableApps() { 466 return mDefaultMinAspectRatioForUnresizableApps; 467 } 468 469 /** 470 * Overrides the min aspect ratio for unresizable apps that are eligible for size compat mode. 471 */ setDefaultMinAspectRatioForUnresizableApps(float aspectRatio)472 void setDefaultMinAspectRatioForUnresizableApps(float aspectRatio) { 473 mDefaultMinAspectRatioForUnresizableApps = aspectRatio; 474 } 475 476 /** 477 * Overrides corners radius for activities presented in the letterbox mode. If given value < 0, 478 * both it and a value of {@link 479 * com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and 480 * corners of the activity won't be rounded. 481 */ setLetterboxActivityCornersRadius(int cornersRadius)482 void setLetterboxActivityCornersRadius(int cornersRadius) { 483 mLetterboxActivityCornersRadius = cornersRadius; 484 } 485 486 /** 487 * Resets corners radius for activities presented in the letterbox mode to {@link 488 * com.android.internal.R.integer.config_letterboxActivityCornersRadius}. 489 */ resetLetterboxActivityCornersRadius()490 void resetLetterboxActivityCornersRadius() { 491 mLetterboxActivityCornersRadius = mContext.getResources().getInteger( 492 com.android.internal.R.integer.config_letterboxActivityCornersRadius); 493 } 494 495 /** 496 * Whether corners of letterboxed activities are rounded. 497 */ isLetterboxActivityCornersRounded()498 boolean isLetterboxActivityCornersRounded() { 499 return getLetterboxActivityCornersRadius() != 0; 500 } 501 502 /** 503 * Gets corners radius for activities presented in the letterbox mode. 504 */ getLetterboxActivityCornersRadius()505 int getLetterboxActivityCornersRadius() { 506 return mLetterboxActivityCornersRadius; 507 } 508 509 /** 510 * Gets color of letterbox background which is used when {@link 511 * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as 512 * fallback for other background types. 513 */ getLetterboxBackgroundColor()514 Color getLetterboxBackgroundColor() { 515 if (mLetterboxBackgroundColorOverride != null) { 516 return mLetterboxBackgroundColorOverride; 517 } 518 int colorId = mLetterboxBackgroundColorResourceIdOverride != null 519 ? mLetterboxBackgroundColorResourceIdOverride 520 : R.color.config_letterboxBackgroundColor; 521 // Query color dynamically because material colors extracted from wallpaper are updated 522 // when wallpaper is changed. 523 return Color.valueOf(mContext.getResources().getColor(colorId)); 524 } 525 526 527 /** 528 * Sets color of letterbox background which is used when {@link 529 * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as 530 * fallback for other background types. 531 */ setLetterboxBackgroundColor(Color color)532 void setLetterboxBackgroundColor(Color color) { 533 mLetterboxBackgroundColorOverride = color; 534 } 535 536 /** 537 * Sets color ID of letterbox background which is used when {@link 538 * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as 539 * fallback for other background types. 540 */ setLetterboxBackgroundColorResourceId(int colorId)541 void setLetterboxBackgroundColorResourceId(int colorId) { 542 mLetterboxBackgroundColorResourceIdOverride = colorId; 543 } 544 545 /** 546 * Resets color of letterbox background to {@link 547 * com.android.internal.R.color.config_letterboxBackgroundColor}. 548 */ resetLetterboxBackgroundColor()549 void resetLetterboxBackgroundColor() { 550 mLetterboxBackgroundColorOverride = null; 551 mLetterboxBackgroundColorResourceIdOverride = null; 552 } 553 554 /** 555 * Gets {@link LetterboxBackgroundType} specified via ADB command or the default one. 556 */ 557 @LetterboxBackgroundType getLetterboxBackgroundType()558 int getLetterboxBackgroundType() { 559 return mLetterboxBackgroundTypeOverride != LETTERBOX_BACKGROUND_OVERRIDE_UNSET 560 ? mLetterboxBackgroundTypeOverride 561 : getDefaultLetterboxBackgroundType(); 562 } 563 564 /** Overrides the letterbox background type. */ setLetterboxBackgroundTypeOverride(@etterboxBackgroundType int backgroundType)565 void setLetterboxBackgroundTypeOverride(@LetterboxBackgroundType int backgroundType) { 566 mLetterboxBackgroundTypeOverride = backgroundType; 567 } 568 569 /** 570 * Resets letterbox background type value depending on the 571 * {@link #KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER} built time and runtime flags. 572 * 573 * <p>If enabled, the letterbox background type value is set toZ 574 * {@link #LETTERBOX_BACKGROUND_WALLPAPER}. When disabled the letterbox background type value 575 * comes from {@link R.integer.config_letterboxBackgroundType}. 576 */ resetLetterboxBackgroundType()577 void resetLetterboxBackgroundType() { 578 mLetterboxBackgroundTypeOverride = LETTERBOX_BACKGROUND_OVERRIDE_UNSET; 579 } 580 581 // Returns KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER if the DeviceConfig flag is enabled 582 // or the value in com.android.internal.R.integer.config_letterboxBackgroundType if the flag 583 // is disabled. 584 @LetterboxBackgroundType getDefaultLetterboxBackgroundType()585 private int getDefaultLetterboxBackgroundType() { 586 return mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER) 587 ? LETTERBOX_BACKGROUND_WALLPAPER : mLetterboxBackgroundType; 588 } 589 590 /** Returns a string representing the given {@link LetterboxBackgroundType}. */ letterboxBackgroundTypeToString( @etterboxBackgroundType int backgroundType)591 static String letterboxBackgroundTypeToString( 592 @LetterboxBackgroundType int backgroundType) { 593 switch (backgroundType) { 594 case LETTERBOX_BACKGROUND_SOLID_COLOR: 595 return "LETTERBOX_BACKGROUND_SOLID_COLOR"; 596 case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND: 597 return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND"; 598 case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING: 599 return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING"; 600 case LETTERBOX_BACKGROUND_WALLPAPER: 601 return "LETTERBOX_BACKGROUND_WALLPAPER"; 602 default: 603 return "unknown=" + backgroundType; 604 } 605 } 606 607 @LetterboxBackgroundType readLetterboxBackgroundTypeFromConfig(Context context)608 private static int readLetterboxBackgroundTypeFromConfig(Context context) { 609 int backgroundType = context.getResources().getInteger( 610 com.android.internal.R.integer.config_letterboxBackgroundType); 611 return backgroundType == LETTERBOX_BACKGROUND_SOLID_COLOR 612 || backgroundType == LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND 613 || backgroundType == LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING 614 || backgroundType == LETTERBOX_BACKGROUND_WALLPAPER 615 ? backgroundType : LETTERBOX_BACKGROUND_SOLID_COLOR; 616 } 617 618 /** 619 * Overrides alpha of a black scrim shown over wallpaper for {@link 620 * #LETTERBOX_BACKGROUND_WALLPAPER} option returned from {@link #getLetterboxBackgroundType()}. 621 * 622 * <p>If given value is < 0 or >= 1, both it and a value of {@link 623 * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha} are ignored 624 * and 0.0 (transparent) is instead. 625 */ setLetterboxBackgroundWallpaperDarkScrimAlpha(float alpha)626 void setLetterboxBackgroundWallpaperDarkScrimAlpha(float alpha) { 627 mLetterboxBackgroundWallpaperDarkScrimAlpha = alpha; 628 } 629 630 /** 631 * Resets alpha of a black scrim shown over wallpaper letterbox background to {@link 632 * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha}. 633 */ resetLetterboxBackgroundWallpaperDarkScrimAlpha()634 void resetLetterboxBackgroundWallpaperDarkScrimAlpha() { 635 mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat( 636 com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha); 637 } 638 639 /** 640 * Gets alpha of a black scrim shown over wallpaper letterbox background. 641 */ getLetterboxBackgroundWallpaperDarkScrimAlpha()642 float getLetterboxBackgroundWallpaperDarkScrimAlpha() { 643 return mLetterboxBackgroundWallpaperDarkScrimAlpha; 644 } 645 646 /** 647 * Overrides blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option from {@link 648 * #getLetterboxBackgroundType()}. 649 * 650 * <p> If given value <= 0, both it and a value of {@link 651 * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius} are ignored 652 * and 0 is used instead. 653 */ setLetterboxBackgroundWallpaperBlurRadiusPx(int radius)654 void setLetterboxBackgroundWallpaperBlurRadiusPx(int radius) { 655 mLetterboxBackgroundWallpaperBlurRadiusPx = radius; 656 } 657 658 /** 659 * Resets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option returned by {@link 660 * #getLetterboxBackgroundType()} to {@link 661 * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius}. 662 */ resetLetterboxBackgroundWallpaperBlurRadiusPx()663 void resetLetterboxBackgroundWallpaperBlurRadiusPx() { 664 mLetterboxBackgroundWallpaperBlurRadiusPx = mContext.getResources().getDimensionPixelSize( 665 com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius); 666 } 667 668 /** 669 * Gets blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option returned by {@link 670 * #getLetterboxBackgroundType()}. 671 */ getLetterboxBackgroundWallpaperBlurRadiusPx()672 int getLetterboxBackgroundWallpaperBlurRadiusPx() { 673 return mLetterboxBackgroundWallpaperBlurRadiusPx; 674 } 675 676 /** 677 * Gets horizontal position of a center of the letterboxed app window specified 678 * in {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} 679 * or via an ADB command. 0 corresponds to the left side of the screen and 1 to the 680 * right side. 681 */ getLetterboxHorizontalPositionMultiplier(boolean isInBookMode)682 float getLetterboxHorizontalPositionMultiplier(boolean isInBookMode) { 683 return isInBookMode ? mLetterboxBookModePositionMultiplier 684 : mLetterboxHorizontalPositionMultiplier; 685 } 686 687 /** 688 * Gets vertical position of a center of the letterboxed app window specified 689 * in {@link com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier} 690 * or via an ADB command. 0 corresponds to the top side of the screen and 1 to the 691 * bottom side. 692 */ getLetterboxVerticalPositionMultiplier(boolean isInTabletopMode)693 float getLetterboxVerticalPositionMultiplier(boolean isInTabletopMode) { 694 return isInTabletopMode ? mLetterboxTabletopModePositionMultiplier 695 : mLetterboxVerticalPositionMultiplier; 696 } 697 698 /** 699 * Overrides horizontal position of a center of the letterboxed app window. 700 * 701 * @throws IllegalArgumentException If given value < 0 or > 1. 702 */ setLetterboxHorizontalPositionMultiplier(float multiplier)703 void setLetterboxHorizontalPositionMultiplier(float multiplier) { 704 mLetterboxHorizontalPositionMultiplier = assertValidMultiplier(multiplier, 705 "mLetterboxHorizontalPositionMultiplier"); 706 } 707 708 /** 709 * Overrides vertical position of a center of the letterboxed app window. 710 * 711 * @throws IllegalArgumentException If given value < 0 or > 1. 712 */ setLetterboxVerticalPositionMultiplier(float multiplier)713 void setLetterboxVerticalPositionMultiplier(float multiplier) { 714 mLetterboxVerticalPositionMultiplier = assertValidMultiplier(multiplier, 715 "mLetterboxVerticalPositionMultiplier"); 716 } 717 718 /** 719 * Resets horizontal position of a center of the letterboxed app window to {@link 720 * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}. 721 */ resetLetterboxHorizontalPositionMultiplier()722 void resetLetterboxHorizontalPositionMultiplier() { 723 mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat( 724 com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier); 725 } 726 727 /** 728 * Resets vertical position of a center of the letterboxed app window to {@link 729 * com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier}. 730 */ resetLetterboxVerticalPositionMultiplier()731 void resetLetterboxVerticalPositionMultiplier() { 732 mLetterboxVerticalPositionMultiplier = mContext.getResources().getFloat( 733 com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier); 734 } 735 736 /** 737 * Sets tabletop mode position multiplier. 738 * 739 * @throws IllegalArgumentException If given value < 0 or > 1. 740 */ 741 @VisibleForTesting setLetterboxTabletopModePositionMultiplier(float multiplier)742 void setLetterboxTabletopModePositionMultiplier(float multiplier) { 743 mLetterboxTabletopModePositionMultiplier = assertValidMultiplier(multiplier, 744 "mLetterboxTabletopModePositionMultiplier"); 745 } 746 747 /** 748 * Sets tabletop mode position multiplier. 749 * 750 * @throws IllegalArgumentException If given value < 0 or > 1. 751 */ 752 @VisibleForTesting setLetterboxBookModePositionMultiplier(float multiplier)753 void setLetterboxBookModePositionMultiplier(float multiplier) { 754 mLetterboxBookModePositionMultiplier = assertValidMultiplier(multiplier, 755 "mLetterboxBookModePositionMultiplier"); 756 } 757 758 /** 759 * Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in 760 * landscape device orientation. 761 */ getIsHorizontalReachabilityEnabled()762 boolean getIsHorizontalReachabilityEnabled() { 763 return mIsHorizontalReachabilityEnabled; 764 } 765 766 /** 767 * Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in 768 * portrait device orientation. 769 */ getIsVerticalReachabilityEnabled()770 boolean getIsVerticalReachabilityEnabled() { 771 return mIsVerticalReachabilityEnabled; 772 } 773 774 /** 775 * Whether automatic horizontal reachability repositioning in book mode is allowed for 776 * letterboxed fullscreen apps in landscape device orientation. 777 */ getIsAutomaticReachabilityInBookModeEnabled()778 boolean getIsAutomaticReachabilityInBookModeEnabled() { 779 return mIsAutomaticReachabilityInBookModeEnabled; 780 } 781 782 /** 783 * Overrides whether horizontal reachability repositioning is allowed for letterboxed fullscreen 784 * apps in landscape device orientation. 785 */ setIsHorizontalReachabilityEnabled(boolean enabled)786 void setIsHorizontalReachabilityEnabled(boolean enabled) { 787 mIsHorizontalReachabilityEnabled = enabled; 788 } 789 790 /** 791 * Overrides whether vertical reachability repositioning is allowed for letterboxed fullscreen 792 * apps in portrait device orientation. 793 */ setIsVerticalReachabilityEnabled(boolean enabled)794 void setIsVerticalReachabilityEnabled(boolean enabled) { 795 mIsVerticalReachabilityEnabled = enabled; 796 } 797 798 /** 799 * Overrides whether automatic horizontal reachability repositioning in book mode is allowed for 800 * letterboxed fullscreen apps in landscape device orientation. 801 */ setIsAutomaticReachabilityInBookModeEnabled(boolean enabled)802 void setIsAutomaticReachabilityInBookModeEnabled(boolean enabled) { 803 mIsAutomaticReachabilityInBookModeEnabled = enabled; 804 } 805 806 /** 807 * Resets whether horizontal reachability repositioning is allowed for letterboxed fullscreen 808 * apps in landscape device orientation to 809 * {@link R.bool.config_letterboxIsHorizontalReachabilityEnabled}. 810 */ resetIsHorizontalReachabilityEnabled()811 void resetIsHorizontalReachabilityEnabled() { 812 mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean( 813 R.bool.config_letterboxIsHorizontalReachabilityEnabled); 814 } 815 816 /** 817 * Resets whether vertical reachability repositioning is allowed for letterboxed fullscreen apps 818 * in portrait device orientation to 819 * {@link R.bool.config_letterboxIsVerticalReachabilityEnabled}. 820 */ resetIsVerticalReachabilityEnabled()821 void resetIsVerticalReachabilityEnabled() { 822 mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean( 823 R.bool.config_letterboxIsVerticalReachabilityEnabled); 824 } 825 826 /** 827 * Resets whether automatic horizontal reachability repositioning in book mode is 828 * allowed for letterboxed fullscreen apps in landscape device orientation to 829 * {@link R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled}. 830 */ resetEnabledAutomaticReachabilityInBookMode()831 void resetEnabledAutomaticReachabilityInBookMode() { 832 mIsAutomaticReachabilityInBookModeEnabled = mContext.getResources().getBoolean( 833 R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled); 834 } 835 836 /** 837 * Gets default horizontal position of the letterboxed app window when horizontal reachability 838 * is enabled. 839 * 840 * <p> Specified in {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability} 841 * or via an ADB command. 842 */ 843 @LetterboxHorizontalReachabilityPosition getDefaultPositionForHorizontalReachability()844 int getDefaultPositionForHorizontalReachability() { 845 return mDefaultPositionForHorizontalReachability; 846 } 847 848 /** 849 * Gets default vertical position of the letterboxed app window when vertical reachability is 850 * enabled. 851 * 852 * <p> Specified in {@link R.integer.config_letterboxDefaultPositionForVerticalReachability} or 853 * via an ADB command. 854 */ 855 @LetterboxVerticalReachabilityPosition getDefaultPositionForVerticalReachability()856 int getDefaultPositionForVerticalReachability() { 857 return mDefaultPositionForVerticalReachability; 858 } 859 860 /** 861 * Overrides default horizontal position of the letterboxed app window when horizontal 862 * reachability is enabled. 863 */ setDefaultPositionForHorizontalReachability( @etterboxHorizontalReachabilityPosition int position)864 void setDefaultPositionForHorizontalReachability( 865 @LetterboxHorizontalReachabilityPosition int position) { 866 mDefaultPositionForHorizontalReachability = position; 867 } 868 869 /** 870 * Overrides default vertical position of the letterboxed app window when vertical 871 * reachability is enabled. 872 */ setDefaultPositionForVerticalReachability( @etterboxVerticalReachabilityPosition int position)873 void setDefaultPositionForVerticalReachability( 874 @LetterboxVerticalReachabilityPosition int position) { 875 mDefaultPositionForVerticalReachability = position; 876 } 877 878 /** 879 * Resets default horizontal position of the letterboxed app window when horizontal reachability 880 * is enabled to {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability}. 881 */ resetDefaultPositionForHorizontalReachability()882 void resetDefaultPositionForHorizontalReachability() { 883 mDefaultPositionForHorizontalReachability = 884 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, 885 false /* forBookMode */); 886 } 887 888 /** 889 * Resets default vertical position of the letterboxed app window when vertical reachability 890 * is enabled to {@link R.integer.config_letterboxDefaultPositionForVerticalReachability}. 891 */ resetDefaultPositionForVerticalReachability()892 void resetDefaultPositionForVerticalReachability() { 893 mDefaultPositionForVerticalReachability = 894 readLetterboxVerticalReachabilityPositionFromConfig(mContext, 895 false /* forTabletopMode */); 896 } 897 898 /** 899 * Overrides persistent horizontal position of the letterboxed app window when horizontal 900 * reachability is enabled. 901 */ setPersistentLetterboxPositionForHorizontalReachability(boolean forBookMode, @LetterboxHorizontalReachabilityPosition int position)902 void setPersistentLetterboxPositionForHorizontalReachability(boolean forBookMode, 903 @LetterboxHorizontalReachabilityPosition int position) { 904 mAppCompatConfigurationPersister.setLetterboxPositionForHorizontalReachability( 905 forBookMode, position); 906 } 907 908 /** 909 * Overrides persistent vertical position of the letterboxed app window when vertical 910 * reachability is enabled. 911 */ setPersistentLetterboxPositionForVerticalReachability(boolean forTabletopMode, @LetterboxVerticalReachabilityPosition int position)912 void setPersistentLetterboxPositionForVerticalReachability(boolean forTabletopMode, 913 @LetterboxVerticalReachabilityPosition int position) { 914 mAppCompatConfigurationPersister.setLetterboxPositionForVerticalReachability( 915 forTabletopMode, position); 916 } 917 918 /** 919 * Resets persistent horizontal position of the letterboxed app window when horizontal 920 * reachability 921 * is enabled to default position. 922 */ resetPersistentLetterboxPositionForHorizontalReachability()923 void resetPersistentLetterboxPositionForHorizontalReachability() { 924 mAppCompatConfigurationPersister.setLetterboxPositionForHorizontalReachability( 925 false /* forBookMode */, 926 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, 927 false /* forBookMode */)); 928 mAppCompatConfigurationPersister.setLetterboxPositionForHorizontalReachability( 929 true /* forBookMode */, 930 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, 931 true /* forBookMode */)); 932 } 933 934 /** 935 * Resets persistent vertical position of the letterboxed app window when vertical reachability 936 * is 937 * enabled to default position. 938 */ resetPersistentLetterboxPositionForVerticalReachability()939 void resetPersistentLetterboxPositionForVerticalReachability() { 940 mAppCompatConfigurationPersister.setLetterboxPositionForVerticalReachability( 941 false /* forTabletopMode */, 942 readLetterboxVerticalReachabilityPositionFromConfig(mContext, 943 false /* forTabletopMode */)); 944 mAppCompatConfigurationPersister.setLetterboxPositionForVerticalReachability( 945 true /* forTabletopMode */, 946 readLetterboxVerticalReachabilityPositionFromConfig(mContext, 947 true /* forTabletopMode */)); 948 } 949 950 @LetterboxHorizontalReachabilityPosition readLetterboxHorizontalReachabilityPositionFromConfig(Context context, boolean forBookMode)951 private static int readLetterboxHorizontalReachabilityPositionFromConfig(Context context, 952 boolean forBookMode) { 953 int position = context.getResources().getInteger( 954 forBookMode 955 ? R.integer.config_letterboxDefaultPositionForBookModeReachability 956 : R.integer.config_letterboxDefaultPositionForHorizontalReachability); 957 return position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT 958 || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER 959 || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT 960 ? position : LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER; 961 } 962 963 @LetterboxVerticalReachabilityPosition readLetterboxVerticalReachabilityPositionFromConfig(Context context, boolean forTabletopMode)964 private static int readLetterboxVerticalReachabilityPositionFromConfig(Context context, 965 boolean forTabletopMode) { 966 int position = context.getResources().getInteger( 967 forTabletopMode 968 ? R.integer.config_letterboxDefaultPositionForTabletopModeReachability 969 : R.integer.config_letterboxDefaultPositionForVerticalReachability); 970 return position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP 971 || position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER 972 || position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM 973 ? position : LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER; 974 } 975 976 /** 977 * Gets horizontal position of a center of the letterboxed app window when reachability 978 * is enabled specified. 0 corresponds to the left side of the screen and 1 to the right side. 979 * 980 * <p>The position multiplier is changed after each double tap in the letterbox area. 981 */ getHorizontalMultiplierForReachability(boolean isDeviceInBookMode)982 float getHorizontalMultiplierForReachability(boolean isDeviceInBookMode) { 983 final int letterboxPositionForHorizontalReachability = 984 mAppCompatConfigurationPersister.getLetterboxPositionForHorizontalReachability( 985 isDeviceInBookMode); 986 switch (letterboxPositionForHorizontalReachability) { 987 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT: 988 return 0.0f; 989 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER: 990 return 0.5f; 991 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT: 992 return 1.0f; 993 default: 994 throw new AssertionError( 995 "Unexpected letterbox position type: " 996 + letterboxPositionForHorizontalReachability); 997 } 998 } 999 1000 /** 1001 * Gets vertical position of a center of the letterboxed app window when reachability 1002 * is enabled specified. 0 corresponds to the top side of the screen and 1 to the bottom side. 1003 * 1004 * <p>The position multiplier is changed after each double tap in the letterbox area. 1005 */ getVerticalMultiplierForReachability(boolean isDeviceInTabletopMode)1006 float getVerticalMultiplierForReachability(boolean isDeviceInTabletopMode) { 1007 final int letterboxPositionForVerticalReachability = 1008 mAppCompatConfigurationPersister.getLetterboxPositionForVerticalReachability( 1009 isDeviceInTabletopMode); 1010 switch (letterboxPositionForVerticalReachability) { 1011 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP: 1012 return 0.0f; 1013 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER: 1014 return 0.5f; 1015 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM: 1016 return 1.0f; 1017 default: 1018 throw new AssertionError( 1019 "Unexpected letterbox position type: " 1020 + letterboxPositionForVerticalReachability); 1021 } 1022 } 1023 1024 /** 1025 * Gets the horizontal position of the letterboxed app window when horizontal reachability is 1026 * enabled. 1027 */ 1028 @LetterboxHorizontalReachabilityPosition getLetterboxPositionForHorizontalReachability(boolean isInFullScreenBookMode)1029 int getLetterboxPositionForHorizontalReachability(boolean isInFullScreenBookMode) { 1030 return mAppCompatConfigurationPersister.getLetterboxPositionForHorizontalReachability( 1031 isInFullScreenBookMode); 1032 } 1033 1034 /** 1035 * Gets the vertical position of the letterboxed app window when vertical reachability is 1036 * enabled. 1037 */ 1038 @LetterboxVerticalReachabilityPosition getLetterboxPositionForVerticalReachability(boolean isInFullScreenTabletopMode)1039 int getLetterboxPositionForVerticalReachability(boolean isInFullScreenTabletopMode) { 1040 return mAppCompatConfigurationPersister.getLetterboxPositionForVerticalReachability( 1041 isInFullScreenTabletopMode); 1042 } 1043 1044 /** Returns a string representing the given {@link LetterboxHorizontalReachabilityPosition}. */ letterboxHorizontalReachabilityPositionToString( @etterboxHorizontalReachabilityPosition int position)1045 static String letterboxHorizontalReachabilityPositionToString( 1046 @LetterboxHorizontalReachabilityPosition int position) { 1047 switch (position) { 1048 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT: 1049 return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT"; 1050 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER: 1051 return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER"; 1052 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT: 1053 return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT"; 1054 default: 1055 throw new AssertionError( 1056 "Unexpected letterbox position type: " + position); 1057 } 1058 } 1059 1060 /** Returns a string representing the given {@link LetterboxVerticalReachabilityPosition}. */ letterboxVerticalReachabilityPositionToString( @etterboxVerticalReachabilityPosition int position)1061 static String letterboxVerticalReachabilityPositionToString( 1062 @LetterboxVerticalReachabilityPosition int position) { 1063 switch (position) { 1064 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP: 1065 return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP"; 1066 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER: 1067 return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER"; 1068 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM: 1069 return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM"; 1070 default: 1071 throw new AssertionError( 1072 "Unexpected letterbox position type: " + position); 1073 } 1074 } 1075 1076 /** 1077 * Changes letterbox position for horizontal reachability to the next available one on the 1078 * right side. 1079 */ movePositionForHorizontalReachabilityToNextRightStop(boolean isDeviceInBookMode)1080 void movePositionForHorizontalReachabilityToNextRightStop(boolean isDeviceInBookMode) { 1081 updatePositionForHorizontalReachability(isDeviceInBookMode, prev -> Math.min( 1082 prev + (isDeviceInBookMode ? 2 : 1), // Move 2 stops in book mode to avoid center. 1083 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT)); 1084 } 1085 1086 /** 1087 * Changes letterbox position for horizontal reachability to the next available one on the left 1088 * side. 1089 */ movePositionForHorizontalReachabilityToNextLeftStop(boolean isDeviceInBookMode)1090 void movePositionForHorizontalReachabilityToNextLeftStop(boolean isDeviceInBookMode) { 1091 updatePositionForHorizontalReachability(isDeviceInBookMode, prev -> Math.max( 1092 prev - (isDeviceInBookMode ? 2 : 1), 0)); // Move 2 stops in book mode to avoid 1093 // center. 1094 } 1095 1096 /** 1097 * Changes letterbox position for vertical reachability to the next available one on the bottom 1098 * side. 1099 */ movePositionForVerticalReachabilityToNextBottomStop(boolean isDeviceInTabletopMode)1100 void movePositionForVerticalReachabilityToNextBottomStop(boolean isDeviceInTabletopMode) { 1101 updatePositionForVerticalReachability(isDeviceInTabletopMode, prev -> Math.min( 1102 prev + (isDeviceInTabletopMode ? 2 : 1), // Move 2 stops in tabletop mode to avoid 1103 // center. 1104 LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM)); 1105 } 1106 1107 /** 1108 * Changes letterbox position for vertical reachability to the next available one on the top 1109 * side. 1110 */ movePositionForVerticalReachabilityToNextTopStop(boolean isDeviceInTabletopMode)1111 void movePositionForVerticalReachabilityToNextTopStop(boolean isDeviceInTabletopMode) { 1112 updatePositionForVerticalReachability(isDeviceInTabletopMode, prev -> Math.max( 1113 prev - (isDeviceInTabletopMode ? 2 : 1), 0)); // Move 2 stops in tabletop mode to 1114 // avoid center. 1115 } 1116 1117 /** 1118 * Whether education is allowed for letterboxed fullscreen apps. 1119 */ getIsEducationEnabled()1120 boolean getIsEducationEnabled() { 1121 return mIsEducationEnabled; 1122 } 1123 1124 /** 1125 * Overrides whether education is allowed for letterboxed fullscreen apps. 1126 */ setIsEducationEnabled(boolean enabled)1127 void setIsEducationEnabled(boolean enabled) { 1128 mIsEducationEnabled = enabled; 1129 } 1130 1131 /** 1132 * Resets whether education is allowed for letterboxed fullscreen apps to 1133 * {@link R.bool.config_letterboxIsEducationEnabled}. 1134 */ resetIsEducationEnabled()1135 void resetIsEducationEnabled() { 1136 mIsEducationEnabled = mContext.getResources().getBoolean( 1137 R.bool.config_letterboxIsEducationEnabled); 1138 } 1139 1140 /** 1141 * Whether using split screen aspect ratio as a default aspect ratio for unresizable apps. 1142 */ getIsSplitScreenAspectRatioForUnresizableAppsEnabled()1143 boolean getIsSplitScreenAspectRatioForUnresizableAppsEnabled() { 1144 return mIsSplitScreenAspectRatioForUnresizableAppsEnabled; 1145 } 1146 1147 /** 1148 * Whether using display aspect ratio as a default aspect ratio for all letterboxed apps. 1149 */ getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()1150 boolean getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox() { 1151 return mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox; 1152 } 1153 1154 /** 1155 * @return Width in pixel about the padding to use to understand if the letterbox for an 1156 * activity is thin. If the available space has width W and the app has width w, this 1157 * is the maximum value for (W - w) / 2 to be considered for a thin letterboxed app. 1158 */ getThinLetterboxWidthPx()1159 int getThinLetterboxWidthPx() { 1160 return mThinLetterboxWidthPxSupplier.getAsInt(); 1161 } 1162 1163 /** 1164 * @return Height in pixel about the padding to use to understand if a letterbox is thin. 1165 * If the available space has height H and the app has height h, this is the maximum 1166 * value for (H - h) / 2 to be considered for a thin letterboxed app. 1167 */ getThinLetterboxHeightPx()1168 int getThinLetterboxHeightPx() { 1169 return mThinLetterboxHeightPxSupplier.getAsInt(); 1170 } 1171 1172 /** 1173 * Overrides whether using split screen aspect ratio as a default aspect ratio for unresizable 1174 * apps. 1175 */ setIsSplitScreenAspectRatioForUnresizableAppsEnabled(boolean enabled)1176 void setIsSplitScreenAspectRatioForUnresizableAppsEnabled(boolean enabled) { 1177 mIsSplitScreenAspectRatioForUnresizableAppsEnabled = enabled; 1178 } 1179 1180 /** 1181 * Overrides whether using display aspect ratio as a default aspect ratio for all letterboxed 1182 * apps. 1183 */ setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(boolean enabled)1184 void setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(boolean enabled) { 1185 mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = enabled; 1186 } 1187 1188 /** 1189 * Resets whether using split screen aspect ratio as a default aspect ratio for unresizable 1190 * apps {@link R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled}. 1191 */ resetIsSplitScreenAspectRatioForUnresizableAppsEnabled()1192 void resetIsSplitScreenAspectRatioForUnresizableAppsEnabled() { 1193 mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean( 1194 R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled); 1195 } 1196 1197 /** 1198 * Resets whether using display aspect ratio as a default aspect ratio for all letterboxed 1199 * apps {@link R.bool.config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled}. 1200 */ resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()1201 void resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox() { 1202 mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = mContext.getResources() 1203 .getBoolean(R.bool 1204 .config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled); 1205 } 1206 isTranslucentLetterboxingEnabled()1207 boolean isTranslucentLetterboxingEnabled() { 1208 return mTranslucentLetterboxingOverrideEnabled 1209 || mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY); 1210 } 1211 1212 /** 1213 * Sets whether we use the constraints override strategy for letterboxing when dealing 1214 * with translucent activities. 1215 */ setTranslucentLetterboxingOverrideEnabled( boolean translucentLetterboxingOverrideEnabled)1216 void setTranslucentLetterboxingOverrideEnabled( 1217 boolean translucentLetterboxingOverrideEnabled) { 1218 mTranslucentLetterboxingOverrideEnabled = translucentLetterboxingOverrideEnabled; 1219 } 1220 1221 /** 1222 * Resets whether we use the constraints override strategy for letterboxing when dealing 1223 * with translucent activities, which means mDeviceConfig.getFlagValue( 1224 * KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY) will be used. 1225 */ resetTranslucentLetterboxingEnabled()1226 void resetTranslucentLetterboxingEnabled() { 1227 setTranslucentLetterboxingOverrideEnabled(false); 1228 } 1229 1230 /** Calculates a new letterboxPositionForHorizontalReachability value and updates the store */ updatePositionForHorizontalReachability(boolean isDeviceInBookMode, Function<Integer, Integer> newHorizonalPositionFun)1231 private void updatePositionForHorizontalReachability(boolean isDeviceInBookMode, 1232 Function<Integer, Integer> newHorizonalPositionFun) { 1233 final int letterboxPositionForHorizontalReachability = 1234 mAppCompatConfigurationPersister.getLetterboxPositionForHorizontalReachability( 1235 isDeviceInBookMode); 1236 final int nextHorizontalPosition = newHorizonalPositionFun.apply( 1237 letterboxPositionForHorizontalReachability); 1238 mAppCompatConfigurationPersister.setLetterboxPositionForHorizontalReachability( 1239 isDeviceInBookMode, nextHorizontalPosition); 1240 } 1241 1242 /** Calculates a new letterboxPositionForVerticalReachability value and updates the store */ updatePositionForVerticalReachability(boolean isDeviceInTabletopMode, Function<Integer, Integer> newVerticalPositionFun)1243 private void updatePositionForVerticalReachability(boolean isDeviceInTabletopMode, 1244 Function<Integer, Integer> newVerticalPositionFun) { 1245 final int letterboxPositionForVerticalReachability = 1246 mAppCompatConfigurationPersister.getLetterboxPositionForVerticalReachability( 1247 isDeviceInTabletopMode); 1248 final int nextVerticalPosition = newVerticalPositionFun.apply( 1249 letterboxPositionForVerticalReachability); 1250 mAppCompatConfigurationPersister.setLetterboxPositionForVerticalReachability( 1251 isDeviceInTabletopMode, nextVerticalPosition); 1252 } 1253 1254 /** Whether fake sending focus is enabled for unfocused apps in splitscreen */ isCompatFakeFocusEnabled()1255 boolean isCompatFakeFocusEnabled() { 1256 return mDeviceConfig.getFlagValue(KEY_ENABLE_COMPAT_FAKE_FOCUS); 1257 } 1258 1259 /** 1260 * Whether should ignore app requested orientation in response to an app calling 1261 * {@link android.app.Activity#setRequestedOrientation}. See {@link 1262 * AppCompatOrientationPolicy#shouldIgnoreRequestedOrientation} for details. 1263 */ isPolicyForIgnoringRequestedOrientationEnabled()1264 boolean isPolicyForIgnoringRequestedOrientationEnabled() { 1265 return mIsPolicyForIgnoringRequestedOrientationEnabled; 1266 } 1267 1268 /** 1269 * Whether we should use split screen aspect ratio for the activity when camera compat treatment 1270 * is enabled and activity is connected to the camera in fullscreen. 1271 */ isCameraCompatSplitScreenAspectRatioEnabled()1272 boolean isCameraCompatSplitScreenAspectRatioEnabled() { 1273 return mIsCameraCompatSplitScreenAspectRatioEnabled; 1274 } 1275 1276 /** 1277 * @return Whether camera compatibility treatment is currently enabled. 1278 */ isCameraCompatTreatmentEnabled()1279 boolean isCameraCompatTreatmentEnabled() { 1280 return mDeviceConfig.getFlagValue(KEY_ENABLE_CAMERA_COMPAT_TREATMENT); 1281 } 1282 1283 /** 1284 * @return Whether camera compatibility treatment is enabled at build time. This is used when 1285 * we need to safely initialize a component before the {@link DeviceConfig} flag value is 1286 * available. 1287 */ isCameraCompatTreatmentEnabledAtBuildTime()1288 boolean isCameraCompatTreatmentEnabledAtBuildTime() { 1289 return mDeviceConfig.isBuildTimeFlagEnabled(KEY_ENABLE_CAMERA_COMPAT_TREATMENT); 1290 } 1291 1292 /** Whether camera compatibility refresh is enabled. */ isCameraCompatRefreshEnabled()1293 boolean isCameraCompatRefreshEnabled() { 1294 return mIsCameraCompatTreatmentRefreshEnabled; 1295 } 1296 1297 /** Overrides whether camera compatibility treatment is enabled. */ setCameraCompatRefreshEnabled(boolean enabled)1298 void setCameraCompatRefreshEnabled(boolean enabled) { 1299 mIsCameraCompatTreatmentRefreshEnabled = enabled; 1300 } 1301 1302 /** 1303 * Resets whether camera compatibility treatment is enabled to {@code true}. 1304 */ resetCameraCompatRefreshEnabled()1305 void resetCameraCompatRefreshEnabled() { 1306 mIsCameraCompatTreatmentRefreshEnabled = true; 1307 } 1308 1309 /** 1310 * Whether activity "refresh" in camera compatibility treatment should happen using the 1311 * "stopped -> resumed" cycle rather than "paused -> resumed" cycle. 1312 */ isCameraCompatRefreshCycleThroughStopEnabled()1313 boolean isCameraCompatRefreshCycleThroughStopEnabled() { 1314 return mIsCameraCompatRefreshCycleThroughStopEnabled; 1315 } 1316 1317 /** 1318 * Overrides whether activity "refresh" in camera compatibility treatment should happen using 1319 * "stopped -> resumed" cycle rather than "paused -> resumed" cycle. 1320 */ setCameraCompatRefreshCycleThroughStopEnabled(boolean enabled)1321 void setCameraCompatRefreshCycleThroughStopEnabled(boolean enabled) { 1322 mIsCameraCompatRefreshCycleThroughStopEnabled = enabled; 1323 } 1324 1325 /** 1326 * Resets whether activity "refresh" in camera compatibility treatment should happen using 1327 * "stopped -> resumed" cycle rather than "paused -> resumed" cycle to {@code true}. 1328 */ resetCameraCompatRefreshCycleThroughStopEnabled()1329 void resetCameraCompatRefreshCycleThroughStopEnabled() { 1330 mIsCameraCompatRefreshCycleThroughStopEnabled = true; 1331 } 1332 1333 /** 1334 * Overrides aspect ratio to use when camera compat treatment is enabled and an activity 1335 * eligible for treatment is connected to the camera. 1336 */ setCameraCompatAspectRatio(float aspectRatio)1337 void setCameraCompatAspectRatio(float aspectRatio) { 1338 mCameraCompatAspectRatio = aspectRatio; 1339 } 1340 1341 /** 1342 * Which aspect ratio to use when camera compat treatment is enabled and an activity eligible 1343 * for treatment is connected to the camera. 1344 */ getCameraCompatAspectRatio()1345 float getCameraCompatAspectRatio() { 1346 return mCameraCompatAspectRatio; 1347 } 1348 1349 /** 1350 * Resets aspect ratio to use when camera compat treatment is enabled and an activity eligible 1351 * for treatment is connected to the camera. 1352 */ resetCameraCompatAspectRatio()1353 void resetCameraCompatAspectRatio() { 1354 mCameraCompatAspectRatio = mContext.getResources().getFloat(R.dimen 1355 .config_windowManagerCameraCompatAspectRatio); 1356 } 1357 1358 /** 1359 * Sets whether the camera compatibility treatment in freeform windowing mode is enabled for 1360 * all fixed-orientation apps when using camera. 1361 */ setIsCameraCompatFreeformWindowingTreatmentEnabled(boolean enabled)1362 void setIsCameraCompatFreeformWindowingTreatmentEnabled(boolean enabled) { 1363 mIsCameraCompatFreeformWindowingTreatmentEnabled = enabled; 1364 } 1365 1366 /** 1367 * Whether the camera compatibility treatment in freeform windowing mode is enabled for all 1368 * fixed-orientation apps when using camera. 1369 */ isCameraCompatFreeformWindowingTreatmentEnabled()1370 boolean isCameraCompatFreeformWindowingTreatmentEnabled() { 1371 return mIsCameraCompatFreeformWindowingTreatmentEnabled; 1372 } 1373 1374 /** 1375 * Resets whether the camera compatibility treatment in freeform windowing mode is enabled for 1376 * all fixed-orientation apps when using camera. 1377 */ resetIsCameraCompatFreeformWindowingTreatmentEnabled()1378 void resetIsCameraCompatFreeformWindowingTreatmentEnabled() { 1379 mIsCameraCompatFreeformWindowingTreatmentEnabled = false; 1380 } 1381 1382 /** 1383 * Checks whether rotation compat policy for immersive apps that prevents auto rotation 1384 * into non-optimal screen orientation while in fullscreen is enabled at build time. This is 1385 * used when we need to safely initialize a component before the {@link DeviceConfig} flag 1386 * value is available. 1387 * 1388 * <p>This is needed because immersive apps, such as games, are often not optimized for all 1389 * orientations and can have a poor UX when rotated. Additionally, some games rely on sensors 1390 * for the gameplay so users can trigger such rotations accidentally when auto rotation is on. 1391 */ isDisplayRotationImmersiveAppCompatPolicyEnabledAtBuildTime()1392 boolean isDisplayRotationImmersiveAppCompatPolicyEnabledAtBuildTime() { 1393 return mDeviceConfig.isBuildTimeFlagEnabled( 1394 KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY); 1395 } 1396 1397 /** 1398 * Checks whether rotation compat policy for immersive apps that prevents auto rotation 1399 * into non-optimal screen orientation while in fullscreen is currently enabled. 1400 * 1401 * <p>This is needed because immersive apps, such as games, are often not optimized for all 1402 * orientations and can have a poor UX when rotated. Additionally, some games rely on sensors 1403 * for the gameplay so users can trigger such rotations accidentally when auto rotation is on. 1404 */ isDisplayRotationImmersiveAppCompatPolicyEnabled()1405 boolean isDisplayRotationImmersiveAppCompatPolicyEnabled() { 1406 return mDeviceConfig.getFlagValue(KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY); 1407 } 1408 1409 /** 1410 * Whether per-app user aspect ratio override settings is enabled 1411 */ isUserAppAspectRatioSettingsEnabled()1412 boolean isUserAppAspectRatioSettingsEnabled() { 1413 return mUserAppAspectRatioSettingsOverrideEnabled 1414 || mDeviceConfig.getFlagValue(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS); 1415 } 1416 setUserAppAspectRatioSettingsOverrideEnabled(boolean enabled)1417 void setUserAppAspectRatioSettingsOverrideEnabled(boolean enabled) { 1418 mUserAppAspectRatioSettingsOverrideEnabled = enabled; 1419 } 1420 1421 /** 1422 * Resets whether per-app user aspect ratio override settings is enabled 1423 * {@code mDeviceConfig.getFlagValue(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS)}. 1424 */ resetUserAppAspectRatioSettingsEnabled()1425 void resetUserAppAspectRatioSettingsEnabled() { 1426 setUserAppAspectRatioSettingsOverrideEnabled(false); 1427 } 1428 1429 /** 1430 * Whether fullscreen option in per-app user aspect ratio settings is enabled 1431 */ isUserAppAspectRatioFullscreenEnabled()1432 boolean isUserAppAspectRatioFullscreenEnabled() { 1433 return isUserAppAspectRatioSettingsEnabled() 1434 && (mUserAppAspectRatioFullscreenOverrideEnabled 1435 || mDeviceConfig.getFlagValue(KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN)); 1436 } 1437 setUserAppAspectRatioFullscreenOverrideEnabled(boolean enabled)1438 void setUserAppAspectRatioFullscreenOverrideEnabled(boolean enabled) { 1439 mUserAppAspectRatioFullscreenOverrideEnabled = enabled; 1440 } 1441 resetUserAppAspectRatioFullscreenEnabled()1442 void resetUserAppAspectRatioFullscreenEnabled() { 1443 setUserAppAspectRatioFullscreenOverrideEnabled(false); 1444 } 1445 dump(@onNull PrintWriter pw, @NonNull String prefix)1446 void dump(@NonNull PrintWriter pw, @NonNull String prefix) { 1447 // TODO(b/359438445): Add more useful information to dump(). 1448 pw.println(prefix + " letterboxPositionForHorizontalReachability=" 1449 + letterboxHorizontalReachabilityPositionToString( 1450 getLetterboxPositionForHorizontalReachability( 1451 /* isInFullScreenBookMode */ false))); 1452 pw.println(prefix + " letterboxPositionForVerticalReachability=" 1453 + letterboxVerticalReachabilityPositionToString( 1454 getLetterboxPositionForVerticalReachability( 1455 /* isInFullScreenTabletopMode */ false))); 1456 pw.println(prefix + " fixedOrientationLetterboxAspectRatio=" 1457 + getFixedOrientationLetterboxAspectRatio()); 1458 pw.println(prefix + " defaultMinAspectRatioForUnresizableApps=" 1459 + getDefaultMinAspectRatioForUnresizableApps()); 1460 pw.println(prefix + " isSplitScreenAspectRatioForUnresizableAppsEnabled=" 1461 + getIsSplitScreenAspectRatioForUnresizableAppsEnabled()); 1462 pw.println(prefix + " isDisplayAspectRatioEnabledForFixedOrientationLetterbox=" 1463 + getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()); 1464 } 1465 1466 /** 1467 * Checks whether the multiplier is between [0,1]. 1468 * 1469 * @param multiplierName sent in the exception if multiplier is invalid, for easier debugging. 1470 * 1471 * @return multiplier, if valid 1472 * @throws IllegalArgumentException if outside bounds. 1473 */ assertValidMultiplier(float multiplier, String multiplierName)1474 private float assertValidMultiplier(float multiplier, String multiplierName) 1475 throws IllegalArgumentException { 1476 if (multiplier < 0.0f || multiplier > 1.0f) { 1477 throw new IllegalArgumentException("Trying to set " + multiplierName 1478 + " out of bounds: " + multiplier); 1479 } 1480 return multiplier; 1481 } 1482 } 1483