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.DimenRes; 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.content.Context; 27 import android.graphics.Color; 28 import android.provider.DeviceConfig; 29 30 import com.android.internal.R; 31 import com.android.internal.annotations.VisibleForTesting; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.util.function.Function; 36 import java.util.function.IntSupplier; 37 38 /** Reads letterbox configs from resources and controls their overrides at runtime. */ 39 final class LetterboxConfiguration { 40 41 private static final String TAG = TAG_WITH_CLASS_NAME ? "LetterboxConfiguration" : 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 LetterboxConfigurationPersister mLetterboxConfigurationPersister; 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 // Whether activity "refresh" in camera compatibility treatment is enabled. 294 // See RefreshCallbackItem for context. 295 private boolean mIsCameraCompatTreatmentRefreshEnabled = true; 296 297 // Whether activity "refresh" in camera compatibility treatment should happen using the 298 // "stopped -> resumed" cycle rather than "paused -> resumed" cycle. Using "stop -> resumed" 299 // cycle by default due to higher success rate confirmed with app compatibility testing. 300 // See RefreshCallbackItem for context. 301 private boolean mIsCameraCompatRefreshCycleThroughStopEnabled = true; 302 303 // Whether should ignore app requested orientation in response to an app 304 // calling Activity#setRequestedOrientation. See 305 // LetterboxUiController#shouldIgnoreRequestedOrientation for details. 306 private final boolean mIsPolicyForIgnoringRequestedOrientationEnabled; 307 308 // Flags dynamically updated with {@link android.provider.DeviceConfig}. 309 @NonNull private final SynchedDeviceConfig mDeviceConfig; 310 311 // Cached version of IntSupplier customised to evaluate new dimen in pixels 312 // when density changes 313 private static class DimenPxIntSupplier implements IntSupplier { 314 315 @NonNull 316 private final Context mContext; 317 318 private final int mResourceId; 319 320 private float mLastDensity = Float.MIN_VALUE; 321 private int mValue = 0; 322 DimenPxIntSupplier(@onNull Context context, @DimenRes int resourceId)323 private DimenPxIntSupplier(@NonNull Context context, @DimenRes int resourceId) { 324 mContext = context; 325 mResourceId = resourceId; 326 } 327 328 @Override getAsInt()329 public int getAsInt() { 330 final float newDensity = mContext.getResources().getDisplayMetrics().density; 331 if (newDensity != mLastDensity) { 332 mLastDensity = newDensity; 333 mValue = mContext.getResources().getDimensionPixelSize(mResourceId); 334 } 335 return mValue; 336 } 337 } 338 LetterboxConfiguration(@onNull final Context systemUiContext)339 LetterboxConfiguration(@NonNull final Context systemUiContext) { 340 this(systemUiContext, new LetterboxConfigurationPersister( 341 () -> readLetterboxHorizontalReachabilityPositionFromConfig( 342 systemUiContext, /* forBookMode */ false), 343 () -> readLetterboxVerticalReachabilityPositionFromConfig( 344 systemUiContext, /* forTabletopMode */ false), 345 () -> readLetterboxHorizontalReachabilityPositionFromConfig( 346 systemUiContext, /* forBookMode */ true), 347 () -> readLetterboxVerticalReachabilityPositionFromConfig( 348 systemUiContext, /* forTabletopMode */ true))); 349 } 350 351 @VisibleForTesting LetterboxConfiguration(@onNull final Context systemUiContext, @NonNull final LetterboxConfigurationPersister letterboxConfigurationPersister)352 LetterboxConfiguration(@NonNull final Context systemUiContext, 353 @NonNull final LetterboxConfigurationPersister letterboxConfigurationPersister) { 354 mContext = systemUiContext; 355 356 mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat( 357 R.dimen.config_fixedOrientationLetterboxAspectRatio); 358 mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext); 359 mLetterboxActivityCornersRadius = mContext.getResources().getInteger( 360 R.integer.config_letterboxActivityCornersRadius); 361 mLetterboxBackgroundWallpaperBlurRadiusPx = mContext.getResources().getDimensionPixelSize( 362 R.dimen.config_letterboxBackgroundWallpaperBlurRadius); 363 mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat( 364 R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha); 365 setLetterboxHorizontalPositionMultiplier(mContext.getResources().getFloat( 366 R.dimen.config_letterboxHorizontalPositionMultiplier)); 367 setLetterboxVerticalPositionMultiplier(mContext.getResources().getFloat( 368 R.dimen.config_letterboxVerticalPositionMultiplier)); 369 setLetterboxBookModePositionMultiplier(mContext.getResources().getFloat( 370 R.dimen.config_letterboxBookModePositionMultiplier)); 371 setLetterboxTabletopModePositionMultiplier(mContext.getResources() 372 .getFloat(R.dimen.config_letterboxTabletopModePositionMultiplier)); 373 mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean( 374 R.bool.config_letterboxIsHorizontalReachabilityEnabled); 375 mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean( 376 R.bool.config_letterboxIsVerticalReachabilityEnabled); 377 mIsAutomaticReachabilityInBookModeEnabled = mContext.getResources().getBoolean( 378 R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled); 379 mDefaultPositionForHorizontalReachability = 380 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, false); 381 mDefaultPositionForVerticalReachability = 382 readLetterboxVerticalReachabilityPositionFromConfig(mContext, false); 383 mIsEducationEnabled = mContext.getResources().getBoolean( 384 R.bool.config_letterboxIsEducationEnabled); 385 setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat( 386 R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps)); 387 mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean( 388 R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled); 389 mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = mContext.getResources() 390 .getBoolean(R.bool 391 .config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled); 392 mIsCameraCompatSplitScreenAspectRatioEnabled = mContext.getResources().getBoolean( 393 R.bool.config_isWindowManagerCameraCompatSplitScreenAspectRatioEnabled); 394 mIsPolicyForIgnoringRequestedOrientationEnabled = mContext.getResources().getBoolean( 395 R.bool.config_letterboxIsPolicyForIgnoringRequestedOrientationEnabled); 396 397 mThinLetterboxWidthPxSupplier = new DimenPxIntSupplier(mContext, 398 R.dimen.config_letterboxThinLetterboxWidthDp); 399 mThinLetterboxHeightPxSupplier = new DimenPxIntSupplier(mContext, 400 R.dimen.config_letterboxThinLetterboxHeightDp); 401 402 mLetterboxConfigurationPersister = letterboxConfigurationPersister; 403 mLetterboxConfigurationPersister.start(); 404 405 mDeviceConfig = SynchedDeviceConfig.builder(DeviceConfig.NAMESPACE_WINDOW_MANAGER, 406 systemUiContext.getMainExecutor()) 407 .addDeviceConfigEntry(KEY_ENABLE_CAMERA_COMPAT_TREATMENT, 408 DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT, 409 mContext.getResources().getBoolean( 410 R.bool.config_isWindowManagerCameraCompatTreatmentEnabled)) 411 .addDeviceConfigEntry(KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY, 412 DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY, 413 mContext.getResources().getBoolean(R.bool 414 .config_letterboxIsDisplayRotationImmersiveAppCompatPolicyEnabled)) 415 .addDeviceConfigEntry(KEY_ALLOW_IGNORE_ORIENTATION_REQUEST, 416 DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST, /* enabled */ true) 417 .addDeviceConfigEntry(KEY_ENABLE_COMPAT_FAKE_FOCUS, 418 DEFAULT_VALUE_ENABLE_COMPAT_FAKE_FOCUS, 419 mContext.getResources().getBoolean(R.bool.config_isCompatFakeFocusEnabled)) 420 .addDeviceConfigEntry(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY, 421 DEFAULT_VALUE_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY, 422 mContext.getResources().getBoolean( 423 R.bool.config_letterboxIsEnabledForTranslucentActivities)) 424 .addDeviceConfigEntry(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS, 425 DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS, 426 mContext.getResources().getBoolean( 427 R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled)) 428 .addDeviceConfigEntry(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER, 429 DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER, /* enabled */ true) 430 .addDeviceConfigEntry(KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN, 431 DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_FULLSCREEN, 432 mContext.getResources().getBoolean( 433 R.bool.config_appCompatUserAppAspectRatioFullscreenIsEnabled)) 434 .build(); 435 } 436 437 /** 438 * Whether enabling ignoreOrientationRequest is allowed on the device. This value is controlled 439 * via {@link android.provider.DeviceConfig}. 440 */ isIgnoreOrientationRequestAllowed()441 boolean isIgnoreOrientationRequestAllowed() { 442 return mDeviceConfig.getFlagValue(KEY_ALLOW_IGNORE_ORIENTATION_REQUEST); 443 } 444 445 /** 446 * Overrides the aspect ratio of letterbox for fixed orientation. If given value is <= {@link 447 * #MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO}, both it and a value of {@link 448 * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio} will be ignored and 449 * the framework implementation will be used to determine the aspect ratio. 450 */ setFixedOrientationLetterboxAspectRatio(float aspectRatio)451 void setFixedOrientationLetterboxAspectRatio(float aspectRatio) { 452 mFixedOrientationLetterboxAspectRatio = aspectRatio; 453 } 454 455 /** 456 * Resets the aspect ratio of letterbox for fixed orientation to {@link 457 * com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio}. 458 */ resetFixedOrientationLetterboxAspectRatio()459 void resetFixedOrientationLetterboxAspectRatio() { 460 mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat( 461 com.android.internal.R.dimen.config_fixedOrientationLetterboxAspectRatio); 462 } 463 464 /** 465 * Gets the aspect ratio of letterbox for fixed orientation. 466 */ getFixedOrientationLetterboxAspectRatio()467 float getFixedOrientationLetterboxAspectRatio() { 468 return mFixedOrientationLetterboxAspectRatio; 469 } 470 471 /** 472 * Resets the min aspect ratio for unresizable apps that are eligible for size compat mode. 473 */ resetDefaultMinAspectRatioForUnresizableApps()474 void resetDefaultMinAspectRatioForUnresizableApps() { 475 setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat( 476 R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps)); 477 } 478 479 /** 480 * Gets the min aspect ratio for unresizable apps that are eligible for size compat mode. 481 */ getDefaultMinAspectRatioForUnresizableApps()482 float getDefaultMinAspectRatioForUnresizableApps() { 483 return mDefaultMinAspectRatioForUnresizableApps; 484 } 485 486 /** 487 * Overrides the min aspect ratio for unresizable apps that are eligible for size compat mode. 488 */ setDefaultMinAspectRatioForUnresizableApps(float aspectRatio)489 void setDefaultMinAspectRatioForUnresizableApps(float aspectRatio) { 490 mDefaultMinAspectRatioForUnresizableApps = aspectRatio; 491 } 492 493 /** 494 * Overrides corners radius for activities presented in the letterbox mode. If given value < 0, 495 * both it and a value of {@link 496 * com.android.internal.R.integer.config_letterboxActivityCornersRadius} will be ignored and 497 * corners of the activity won't be rounded. 498 */ setLetterboxActivityCornersRadius(int cornersRadius)499 void setLetterboxActivityCornersRadius(int cornersRadius) { 500 mLetterboxActivityCornersRadius = cornersRadius; 501 } 502 503 /** 504 * Resets corners radius for activities presented in the letterbox mode to {@link 505 * com.android.internal.R.integer.config_letterboxActivityCornersRadius}. 506 */ resetLetterboxActivityCornersRadius()507 void resetLetterboxActivityCornersRadius() { 508 mLetterboxActivityCornersRadius = mContext.getResources().getInteger( 509 com.android.internal.R.integer.config_letterboxActivityCornersRadius); 510 } 511 512 /** 513 * Whether corners of letterboxed activities are rounded. 514 */ isLetterboxActivityCornersRounded()515 boolean isLetterboxActivityCornersRounded() { 516 return getLetterboxActivityCornersRadius() != 0; 517 } 518 519 /** 520 * Gets corners radius for activities presented in the letterbox mode. 521 */ getLetterboxActivityCornersRadius()522 int getLetterboxActivityCornersRadius() { 523 return mLetterboxActivityCornersRadius; 524 } 525 526 /** 527 * Gets color of letterbox background which is used when {@link 528 * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as 529 * fallback for other background types. 530 */ getLetterboxBackgroundColor()531 Color getLetterboxBackgroundColor() { 532 if (mLetterboxBackgroundColorOverride != null) { 533 return mLetterboxBackgroundColorOverride; 534 } 535 int colorId = mLetterboxBackgroundColorResourceIdOverride != null 536 ? mLetterboxBackgroundColorResourceIdOverride 537 : R.color.config_letterboxBackgroundColor; 538 // Query color dynamically because material colors extracted from wallpaper are updated 539 // when wallpaper is changed. 540 return Color.valueOf(mContext.getResources().getColor(colorId)); 541 } 542 543 544 /** 545 * Sets color of letterbox background which is used when {@link 546 * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as 547 * fallback for other background types. 548 */ setLetterboxBackgroundColor(Color color)549 void setLetterboxBackgroundColor(Color color) { 550 mLetterboxBackgroundColorOverride = color; 551 } 552 553 /** 554 * Sets color ID of letterbox background which is used when {@link 555 * #getLetterboxBackgroundType()} is {@link #LETTERBOX_BACKGROUND_SOLID_COLOR} or as 556 * fallback for other background types. 557 */ setLetterboxBackgroundColorResourceId(int colorId)558 void setLetterboxBackgroundColorResourceId(int colorId) { 559 mLetterboxBackgroundColorResourceIdOverride = colorId; 560 } 561 562 /** 563 * Resets color of letterbox background to {@link 564 * com.android.internal.R.color.config_letterboxBackgroundColor}. 565 */ resetLetterboxBackgroundColor()566 void resetLetterboxBackgroundColor() { 567 mLetterboxBackgroundColorOverride = null; 568 mLetterboxBackgroundColorResourceIdOverride = null; 569 } 570 571 /** 572 * Gets {@link LetterboxBackgroundType} specified via ADB command or the default one. 573 */ 574 @LetterboxBackgroundType getLetterboxBackgroundType()575 int getLetterboxBackgroundType() { 576 return mLetterboxBackgroundTypeOverride != LETTERBOX_BACKGROUND_OVERRIDE_UNSET 577 ? mLetterboxBackgroundTypeOverride 578 : getDefaultLetterboxBackgroundType(); 579 } 580 581 /** Overrides the letterbox background type. */ setLetterboxBackgroundTypeOverride(@etterboxBackgroundType int backgroundType)582 void setLetterboxBackgroundTypeOverride(@LetterboxBackgroundType int backgroundType) { 583 mLetterboxBackgroundTypeOverride = backgroundType; 584 } 585 586 /** 587 * Resets letterbox background type value depending on the 588 * {@link #KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER} built time and runtime flags. 589 * 590 * <p>If enabled, the letterbox background type value is set toZ 591 * {@link #LETTERBOX_BACKGROUND_WALLPAPER}. When disabled the letterbox background type value 592 * comes from {@link R.integer.config_letterboxBackgroundType}. 593 */ resetLetterboxBackgroundType()594 void resetLetterboxBackgroundType() { 595 mLetterboxBackgroundTypeOverride = LETTERBOX_BACKGROUND_OVERRIDE_UNSET; 596 } 597 598 // Returns KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER if the DeviceConfig flag is enabled 599 // or the value in com.android.internal.R.integer.config_letterboxBackgroundType if the flag 600 // is disabled. 601 @LetterboxBackgroundType getDefaultLetterboxBackgroundType()602 private int getDefaultLetterboxBackgroundType() { 603 return mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER) 604 ? LETTERBOX_BACKGROUND_WALLPAPER : mLetterboxBackgroundType; 605 } 606 607 /** Returns a string representing the given {@link LetterboxBackgroundType}. */ letterboxBackgroundTypeToString( @etterboxBackgroundType int backgroundType)608 static String letterboxBackgroundTypeToString( 609 @LetterboxBackgroundType int backgroundType) { 610 switch (backgroundType) { 611 case LETTERBOX_BACKGROUND_SOLID_COLOR: 612 return "LETTERBOX_BACKGROUND_SOLID_COLOR"; 613 case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND: 614 return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND"; 615 case LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING: 616 return "LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING"; 617 case LETTERBOX_BACKGROUND_WALLPAPER: 618 return "LETTERBOX_BACKGROUND_WALLPAPER"; 619 default: 620 return "unknown=" + backgroundType; 621 } 622 } 623 624 @LetterboxBackgroundType readLetterboxBackgroundTypeFromConfig(Context context)625 private static int readLetterboxBackgroundTypeFromConfig(Context context) { 626 int backgroundType = context.getResources().getInteger( 627 com.android.internal.R.integer.config_letterboxBackgroundType); 628 return backgroundType == LETTERBOX_BACKGROUND_SOLID_COLOR 629 || backgroundType == LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND 630 || backgroundType == LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING 631 || backgroundType == LETTERBOX_BACKGROUND_WALLPAPER 632 ? backgroundType : LETTERBOX_BACKGROUND_SOLID_COLOR; 633 } 634 635 /** 636 * Overrides alpha of a black scrim shown over wallpaper for {@link 637 * #LETTERBOX_BACKGROUND_WALLPAPER} option returned from {@link getLetterboxBackgroundType()}. 638 * 639 * <p>If given value is < 0 or >= 1, both it and a value of {@link 640 * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha} are ignored 641 * and 0.0 (transparent) is instead. 642 */ setLetterboxBackgroundWallpaperDarkScrimAlpha(float alpha)643 void setLetterboxBackgroundWallpaperDarkScrimAlpha(float alpha) { 644 mLetterboxBackgroundWallpaperDarkScrimAlpha = alpha; 645 } 646 647 /** 648 * Resets alpha of a black scrim shown over wallpaper letterbox background to {@link 649 * com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha}. 650 */ resetLetterboxBackgroundWallpaperDarkScrimAlpha()651 void resetLetterboxBackgroundWallpaperDarkScrimAlpha() { 652 mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat( 653 com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha); 654 } 655 656 /** 657 * Gets alpha of a black scrim shown over wallpaper letterbox background. 658 */ getLetterboxBackgroundWallpaperDarkScrimAlpha()659 float getLetterboxBackgroundWallpaperDarkScrimAlpha() { 660 return mLetterboxBackgroundWallpaperDarkScrimAlpha; 661 } 662 663 /** 664 * Overrides blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option from 665 * {@link getLetterboxBackgroundType()}. 666 * 667 * <p> If given value <= 0, both it and a value of {@link 668 * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius} are ignored 669 * and 0 is used instead. 670 */ setLetterboxBackgroundWallpaperBlurRadiusPx(int radius)671 void setLetterboxBackgroundWallpaperBlurRadiusPx(int radius) { 672 mLetterboxBackgroundWallpaperBlurRadiusPx = radius; 673 } 674 675 /** 676 * Resets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option returned by {@link 677 * getLetterboxBackgroundType()} to {@link 678 * com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius}. 679 */ resetLetterboxBackgroundWallpaperBlurRadiusPx()680 void resetLetterboxBackgroundWallpaperBlurRadiusPx() { 681 mLetterboxBackgroundWallpaperBlurRadiusPx = mContext.getResources().getDimensionPixelSize( 682 com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius); 683 } 684 685 /** 686 * Gets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option returned by {@link 687 * getLetterboxBackgroundType()}. 688 */ getLetterboxBackgroundWallpaperBlurRadiusPx()689 int getLetterboxBackgroundWallpaperBlurRadiusPx() { 690 return mLetterboxBackgroundWallpaperBlurRadiusPx; 691 } 692 693 /* 694 * Gets horizontal position of a center of the letterboxed app window specified 695 * in {@link com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} 696 * or via an ADB command. 0 corresponds to the left side of the screen and 1 to the 697 * right side. 698 */ getLetterboxHorizontalPositionMultiplier(boolean isInBookMode)699 float getLetterboxHorizontalPositionMultiplier(boolean isInBookMode) { 700 return isInBookMode ? mLetterboxBookModePositionMultiplier 701 : mLetterboxHorizontalPositionMultiplier; 702 } 703 704 /* 705 * Gets vertical position of a center of the letterboxed app window specified 706 * in {@link com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier} 707 * or via an ADB command. 0 corresponds to the top side of the screen and 1 to the 708 * bottom side. 709 */ getLetterboxVerticalPositionMultiplier(boolean isInTabletopMode)710 float getLetterboxVerticalPositionMultiplier(boolean isInTabletopMode) { 711 return isInTabletopMode ? mLetterboxTabletopModePositionMultiplier 712 : mLetterboxVerticalPositionMultiplier; 713 } 714 715 /** 716 * Overrides horizontal position of a center of the letterboxed app window. 717 * 718 * @throws IllegalArgumentException If given value < 0 or > 1. 719 */ setLetterboxHorizontalPositionMultiplier(float multiplier)720 void setLetterboxHorizontalPositionMultiplier(float multiplier) { 721 mLetterboxHorizontalPositionMultiplier = assertValidMultiplier(multiplier, 722 "mLetterboxHorizontalPositionMultiplier"); 723 } 724 725 /** 726 * Overrides vertical position of a center of the letterboxed app window. 727 * 728 * @throws IllegalArgumentException If given value < 0 or > 1. 729 */ setLetterboxVerticalPositionMultiplier(float multiplier)730 void setLetterboxVerticalPositionMultiplier(float multiplier) { 731 mLetterboxVerticalPositionMultiplier = assertValidMultiplier(multiplier, 732 "mLetterboxVerticalPositionMultiplier"); 733 } 734 735 /** 736 * Resets horizontal position of a center of the letterboxed app window to {@link 737 * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier}. 738 */ resetLetterboxHorizontalPositionMultiplier()739 void resetLetterboxHorizontalPositionMultiplier() { 740 mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat( 741 com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier); 742 } 743 744 /** 745 * Resets vertical position of a center of the letterboxed app window to {@link 746 * com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier}. 747 */ resetLetterboxVerticalPositionMultiplier()748 void resetLetterboxVerticalPositionMultiplier() { 749 mLetterboxVerticalPositionMultiplier = mContext.getResources().getFloat( 750 com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier); 751 } 752 753 /** 754 * Sets tabletop mode position multiplier. 755 * 756 * @throws IllegalArgumentException If given value < 0 or > 1. 757 */ 758 @VisibleForTesting setLetterboxTabletopModePositionMultiplier(float multiplier)759 void setLetterboxTabletopModePositionMultiplier(float multiplier) { 760 mLetterboxTabletopModePositionMultiplier = assertValidMultiplier(multiplier, 761 "mLetterboxTabletopModePositionMultiplier"); 762 } 763 764 /** 765 * Sets tabletop mode position multiplier. 766 * 767 * @throws IllegalArgumentException If given value < 0 or > 1. 768 */ 769 @VisibleForTesting setLetterboxBookModePositionMultiplier(float multiplier)770 void setLetterboxBookModePositionMultiplier(float multiplier) { 771 mLetterboxBookModePositionMultiplier = assertValidMultiplier(multiplier, 772 "mLetterboxBookModePositionMultiplier"); 773 } 774 775 /* 776 * Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in 777 * landscape device orientation. 778 */ getIsHorizontalReachabilityEnabled()779 boolean getIsHorizontalReachabilityEnabled() { 780 return mIsHorizontalReachabilityEnabled; 781 } 782 783 /* 784 * Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps in 785 * portrait device orientation. 786 */ getIsVerticalReachabilityEnabled()787 boolean getIsVerticalReachabilityEnabled() { 788 return mIsVerticalReachabilityEnabled; 789 } 790 791 /* 792 * Whether automatic horizontal reachability repositioning in book mode is allowed for 793 * letterboxed fullscreen apps in landscape device orientation. 794 */ getIsAutomaticReachabilityInBookModeEnabled()795 boolean getIsAutomaticReachabilityInBookModeEnabled() { 796 return mIsAutomaticReachabilityInBookModeEnabled; 797 } 798 799 /** 800 * Overrides whether horizontal reachability repositioning is allowed for letterboxed fullscreen 801 * apps in landscape device orientation. 802 */ setIsHorizontalReachabilityEnabled(boolean enabled)803 void setIsHorizontalReachabilityEnabled(boolean enabled) { 804 mIsHorizontalReachabilityEnabled = enabled; 805 } 806 807 /** 808 * Overrides whether vertical reachability repositioning is allowed for letterboxed fullscreen 809 * apps in portrait device orientation. 810 */ setIsVerticalReachabilityEnabled(boolean enabled)811 void setIsVerticalReachabilityEnabled(boolean enabled) { 812 mIsVerticalReachabilityEnabled = enabled; 813 } 814 815 /** 816 * Overrides whether automatic horizontal reachability repositioning in book mode is allowed for 817 * letterboxed fullscreen apps in landscape device orientation. 818 */ setIsAutomaticReachabilityInBookModeEnabled(boolean enabled)819 void setIsAutomaticReachabilityInBookModeEnabled(boolean enabled) { 820 mIsAutomaticReachabilityInBookModeEnabled = enabled; 821 } 822 823 /** 824 * Resets whether horizontal reachability repositioning is allowed for letterboxed fullscreen 825 * apps in landscape device orientation to 826 * {@link R.bool.config_letterboxIsHorizontalReachabilityEnabled}. 827 */ resetIsHorizontalReachabilityEnabled()828 void resetIsHorizontalReachabilityEnabled() { 829 mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean( 830 R.bool.config_letterboxIsHorizontalReachabilityEnabled); 831 } 832 833 /** 834 * Resets whether vertical reachability repositioning is allowed for letterboxed fullscreen apps 835 * in portrait device orientation to 836 * {@link R.bool.config_letterboxIsVerticalReachabilityEnabled}. 837 */ resetIsVerticalReachabilityEnabled()838 void resetIsVerticalReachabilityEnabled() { 839 mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean( 840 R.bool.config_letterboxIsVerticalReachabilityEnabled); 841 } 842 843 /** 844 * Resets whether automatic horizontal reachability repositioning in book mode is 845 * allowed for letterboxed fullscreen apps in landscape device orientation to 846 * {@link R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled}. 847 */ resetEnabledAutomaticReachabilityInBookMode()848 void resetEnabledAutomaticReachabilityInBookMode() { 849 mIsAutomaticReachabilityInBookModeEnabled = mContext.getResources().getBoolean( 850 R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled); 851 } 852 853 /* 854 * Gets default horizontal position of the letterboxed app window when horizontal reachability 855 * is enabled. 856 * 857 * <p> Specified in {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability} 858 * or via an ADB command. 859 */ 860 @LetterboxHorizontalReachabilityPosition getDefaultPositionForHorizontalReachability()861 int getDefaultPositionForHorizontalReachability() { 862 return mDefaultPositionForHorizontalReachability; 863 } 864 865 /* 866 * Gets default vertical position of the letterboxed app window when vertical reachability is 867 * enabled. 868 * 869 * <p> Specified in {@link R.integer.config_letterboxDefaultPositionForVerticalReachability} or 870 * via an ADB command. 871 */ 872 @LetterboxVerticalReachabilityPosition getDefaultPositionForVerticalReachability()873 int getDefaultPositionForVerticalReachability() { 874 return mDefaultPositionForVerticalReachability; 875 } 876 877 /** 878 * Overrides default horizontal position of the letterboxed app window when horizontal 879 * reachability is enabled. 880 */ setDefaultPositionForHorizontalReachability( @etterboxHorizontalReachabilityPosition int position)881 void setDefaultPositionForHorizontalReachability( 882 @LetterboxHorizontalReachabilityPosition int position) { 883 mDefaultPositionForHorizontalReachability = position; 884 } 885 886 /** 887 * Overrides default vertical position of the letterboxed app window when vertical 888 * reachability is enabled. 889 */ setDefaultPositionForVerticalReachability( @etterboxVerticalReachabilityPosition int position)890 void setDefaultPositionForVerticalReachability( 891 @LetterboxVerticalReachabilityPosition int position) { 892 mDefaultPositionForVerticalReachability = position; 893 } 894 895 /** 896 * Resets default horizontal position of the letterboxed app window when horizontal reachability 897 * is enabled to {@link R.integer.config_letterboxDefaultPositionForHorizontalReachability}. 898 */ resetDefaultPositionForHorizontalReachability()899 void resetDefaultPositionForHorizontalReachability() { 900 mDefaultPositionForHorizontalReachability = 901 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, 902 false /* forBookMode */); 903 } 904 905 /** 906 * Resets default vertical position of the letterboxed app window when vertical reachability 907 * is enabled to {@link R.integer.config_letterboxDefaultPositionForVerticalReachability}. 908 */ resetDefaultPositionForVerticalReachability()909 void resetDefaultPositionForVerticalReachability() { 910 mDefaultPositionForVerticalReachability = 911 readLetterboxVerticalReachabilityPositionFromConfig(mContext, 912 false /* forTabletopMode */); 913 } 914 915 /** 916 * Overrides persistent horizontal position of the letterboxed app window when horizontal 917 * reachability is enabled. 918 */ setPersistentLetterboxPositionForHorizontalReachability(boolean forBookMode, @LetterboxHorizontalReachabilityPosition int position)919 void setPersistentLetterboxPositionForHorizontalReachability(boolean forBookMode, 920 @LetterboxHorizontalReachabilityPosition int position) { 921 mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability( 922 forBookMode, position); 923 } 924 925 /** 926 * Overrides persistent vertical position of the letterboxed app window when vertical 927 * reachability is enabled. 928 */ setPersistentLetterboxPositionForVerticalReachability(boolean forTabletopMode, @LetterboxVerticalReachabilityPosition int position)929 void setPersistentLetterboxPositionForVerticalReachability(boolean forTabletopMode, 930 @LetterboxVerticalReachabilityPosition int position) { 931 mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability( 932 forTabletopMode, position); 933 } 934 935 /** 936 * Resets persistent horizontal position of the letterboxed app window when horizontal 937 * reachability 938 * is enabled to default position. 939 */ resetPersistentLetterboxPositionForHorizontalReachability()940 void resetPersistentLetterboxPositionForHorizontalReachability() { 941 mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability( 942 false /* forBookMode */, 943 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, 944 false /* forBookMode */)); 945 mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability( 946 true /* forBookMode */, 947 readLetterboxHorizontalReachabilityPositionFromConfig(mContext, 948 true /* forBookMode */)); 949 } 950 951 /** 952 * Resets persistent vertical position of the letterboxed app window when vertical reachability 953 * is 954 * enabled to default position. 955 */ resetPersistentLetterboxPositionForVerticalReachability()956 void resetPersistentLetterboxPositionForVerticalReachability() { 957 mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability( 958 false /* forTabletopMode */, 959 readLetterboxVerticalReachabilityPositionFromConfig(mContext, 960 false /* forTabletopMode */)); 961 mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability( 962 true /* forTabletopMode */, 963 readLetterboxVerticalReachabilityPositionFromConfig(mContext, 964 true /* forTabletopMode */)); 965 } 966 967 @LetterboxHorizontalReachabilityPosition readLetterboxHorizontalReachabilityPositionFromConfig(Context context, boolean forBookMode)968 private static int readLetterboxHorizontalReachabilityPositionFromConfig(Context context, 969 boolean forBookMode) { 970 int position = context.getResources().getInteger( 971 forBookMode 972 ? R.integer.config_letterboxDefaultPositionForBookModeReachability 973 : R.integer.config_letterboxDefaultPositionForHorizontalReachability); 974 return position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT 975 || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER 976 || position == LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT 977 ? position : LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER; 978 } 979 980 @LetterboxVerticalReachabilityPosition readLetterboxVerticalReachabilityPositionFromConfig(Context context, boolean forTabletopMode)981 private static int readLetterboxVerticalReachabilityPositionFromConfig(Context context, 982 boolean forTabletopMode) { 983 int position = context.getResources().getInteger( 984 forTabletopMode 985 ? R.integer.config_letterboxDefaultPositionForTabletopModeReachability 986 : R.integer.config_letterboxDefaultPositionForVerticalReachability); 987 return position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP 988 || position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER 989 || position == LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM 990 ? position : LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER; 991 } 992 993 /* 994 * Gets horizontal position of a center of the letterboxed app window when reachability 995 * is enabled specified. 0 corresponds to the left side of the screen and 1 to the right side. 996 * 997 * <p>The position multiplier is changed after each double tap in the letterbox area. 998 */ getHorizontalMultiplierForReachability(boolean isDeviceInBookMode)999 float getHorizontalMultiplierForReachability(boolean isDeviceInBookMode) { 1000 final int letterboxPositionForHorizontalReachability = 1001 mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability( 1002 isDeviceInBookMode); 1003 switch (letterboxPositionForHorizontalReachability) { 1004 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT: 1005 return 0.0f; 1006 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER: 1007 return 0.5f; 1008 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT: 1009 return 1.0f; 1010 default: 1011 throw new AssertionError( 1012 "Unexpected letterbox position type: " 1013 + letterboxPositionForHorizontalReachability); 1014 } 1015 } 1016 1017 /* 1018 * Gets vertical position of a center of the letterboxed app window when reachability 1019 * is enabled specified. 0 corresponds to the top side of the screen and 1 to the bottom side. 1020 * 1021 * <p>The position multiplier is changed after each double tap in the letterbox area. 1022 */ getVerticalMultiplierForReachability(boolean isDeviceInTabletopMode)1023 float getVerticalMultiplierForReachability(boolean isDeviceInTabletopMode) { 1024 final int letterboxPositionForVerticalReachability = 1025 mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability( 1026 isDeviceInTabletopMode); 1027 switch (letterboxPositionForVerticalReachability) { 1028 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP: 1029 return 0.0f; 1030 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER: 1031 return 0.5f; 1032 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM: 1033 return 1.0f; 1034 default: 1035 throw new AssertionError( 1036 "Unexpected letterbox position type: " 1037 + letterboxPositionForVerticalReachability); 1038 } 1039 } 1040 1041 /* 1042 * Gets the horizontal position of the letterboxed app window when horizontal reachability is 1043 * enabled. 1044 */ 1045 @LetterboxHorizontalReachabilityPosition getLetterboxPositionForHorizontalReachability(boolean isInFullScreenBookMode)1046 int getLetterboxPositionForHorizontalReachability(boolean isInFullScreenBookMode) { 1047 return mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability( 1048 isInFullScreenBookMode); 1049 } 1050 1051 /* 1052 * Gets the vertical position of the letterboxed app window when vertical reachability is 1053 * enabled. 1054 */ 1055 @LetterboxVerticalReachabilityPosition getLetterboxPositionForVerticalReachability(boolean isInFullScreenTabletopMode)1056 int getLetterboxPositionForVerticalReachability(boolean isInFullScreenTabletopMode) { 1057 return mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability( 1058 isInFullScreenTabletopMode); 1059 } 1060 1061 /** Returns a string representing the given {@link LetterboxHorizontalReachabilityPosition}. */ letterboxHorizontalReachabilityPositionToString( @etterboxHorizontalReachabilityPosition int position)1062 static String letterboxHorizontalReachabilityPositionToString( 1063 @LetterboxHorizontalReachabilityPosition int position) { 1064 switch (position) { 1065 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT: 1066 return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT"; 1067 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER: 1068 return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER"; 1069 case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT: 1070 return "LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT"; 1071 default: 1072 throw new AssertionError( 1073 "Unexpected letterbox position type: " + position); 1074 } 1075 } 1076 1077 /** Returns a string representing the given {@link LetterboxVerticalReachabilityPosition}. */ letterboxVerticalReachabilityPositionToString( @etterboxVerticalReachabilityPosition int position)1078 static String letterboxVerticalReachabilityPositionToString( 1079 @LetterboxVerticalReachabilityPosition int position) { 1080 switch (position) { 1081 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP: 1082 return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP"; 1083 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER: 1084 return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER"; 1085 case LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM: 1086 return "LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM"; 1087 default: 1088 throw new AssertionError( 1089 "Unexpected letterbox position type: " + position); 1090 } 1091 } 1092 1093 /** 1094 * Changes letterbox position for horizontal reachability to the next available one on the 1095 * right side. 1096 */ movePositionForHorizontalReachabilityToNextRightStop(boolean isDeviceInBookMode)1097 void movePositionForHorizontalReachabilityToNextRightStop(boolean isDeviceInBookMode) { 1098 updatePositionForHorizontalReachability(isDeviceInBookMode, prev -> Math.min( 1099 prev + (isDeviceInBookMode ? 2 : 1), // Move 2 stops in book mode to avoid center. 1100 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT)); 1101 } 1102 1103 /** 1104 * Changes letterbox position for horizontal reachability to the next available one on the left 1105 * side. 1106 */ movePositionForHorizontalReachabilityToNextLeftStop(boolean isDeviceInBookMode)1107 void movePositionForHorizontalReachabilityToNextLeftStop(boolean isDeviceInBookMode) { 1108 updatePositionForHorizontalReachability(isDeviceInBookMode, prev -> Math.max( 1109 prev - (isDeviceInBookMode ? 2 : 1), 0)); // Move 2 stops in book mode to avoid 1110 // center. 1111 } 1112 1113 /** 1114 * Changes letterbox position for vertical reachability to the next available one on the bottom 1115 * side. 1116 */ movePositionForVerticalReachabilityToNextBottomStop(boolean isDeviceInTabletopMode)1117 void movePositionForVerticalReachabilityToNextBottomStop(boolean isDeviceInTabletopMode) { 1118 updatePositionForVerticalReachability(isDeviceInTabletopMode, prev -> Math.min( 1119 prev + (isDeviceInTabletopMode ? 2 : 1), // Move 2 stops in tabletop mode to avoid 1120 // center. 1121 LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM)); 1122 } 1123 1124 /** 1125 * Changes letterbox position for vertical reachability to the next available one on the top 1126 * side. 1127 */ movePositionForVerticalReachabilityToNextTopStop(boolean isDeviceInTabletopMode)1128 void movePositionForVerticalReachabilityToNextTopStop(boolean isDeviceInTabletopMode) { 1129 updatePositionForVerticalReachability(isDeviceInTabletopMode, prev -> Math.max( 1130 prev - (isDeviceInTabletopMode ? 2 : 1), 0)); // Move 2 stops in tabletop mode to 1131 // avoid center. 1132 } 1133 1134 /** 1135 * Whether education is allowed for letterboxed fullscreen apps. 1136 */ getIsEducationEnabled()1137 boolean getIsEducationEnabled() { 1138 return mIsEducationEnabled; 1139 } 1140 1141 /** 1142 * Overrides whether education is allowed for letterboxed fullscreen apps. 1143 */ setIsEducationEnabled(boolean enabled)1144 void setIsEducationEnabled(boolean enabled) { 1145 mIsEducationEnabled = enabled; 1146 } 1147 1148 /** 1149 * Resets whether education is allowed for letterboxed fullscreen apps to 1150 * {@link R.bool.config_letterboxIsEducationEnabled}. 1151 */ resetIsEducationEnabled()1152 void resetIsEducationEnabled() { 1153 mIsEducationEnabled = mContext.getResources().getBoolean( 1154 R.bool.config_letterboxIsEducationEnabled); 1155 } 1156 1157 /** 1158 * Whether using split screen aspect ratio as a default aspect ratio for unresizable apps. 1159 */ getIsSplitScreenAspectRatioForUnresizableAppsEnabled()1160 boolean getIsSplitScreenAspectRatioForUnresizableAppsEnabled() { 1161 return mIsSplitScreenAspectRatioForUnresizableAppsEnabled; 1162 } 1163 1164 /** 1165 * Whether using display aspect ratio as a default aspect ratio for all letterboxed apps. 1166 */ getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()1167 boolean getIsDisplayAspectRatioEnabledForFixedOrientationLetterbox() { 1168 return mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox; 1169 } 1170 1171 /** 1172 * @return Width in pixel about the padding to use to understand if the letterbox for an 1173 * activity is thin. If the available space has width W and the app has width w, this 1174 * is the maximum value for (W - w) / 2 to be considered for a thin letterboxed app. 1175 */ getThinLetterboxWidthPx()1176 int getThinLetterboxWidthPx() { 1177 return mThinLetterboxWidthPxSupplier.getAsInt(); 1178 } 1179 1180 /** 1181 * @return Height in pixel about the padding to use to understand if a letterbox is thin. 1182 * If the available space has height H and the app has height h, this is the maximum 1183 * value for (H - h) / 2 to be considered for a thin letterboxed app. 1184 */ getThinLetterboxHeightPx()1185 int getThinLetterboxHeightPx() { 1186 return mThinLetterboxHeightPxSupplier.getAsInt(); 1187 } 1188 1189 /** 1190 * Overrides whether using split screen aspect ratio as a default aspect ratio for unresizable 1191 * apps. 1192 */ setIsSplitScreenAspectRatioForUnresizableAppsEnabled(boolean enabled)1193 void setIsSplitScreenAspectRatioForUnresizableAppsEnabled(boolean enabled) { 1194 mIsSplitScreenAspectRatioForUnresizableAppsEnabled = enabled; 1195 } 1196 1197 /** 1198 * Overrides whether using display aspect ratio as a default aspect ratio for all letterboxed 1199 * apps. 1200 */ setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(boolean enabled)1201 void setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(boolean enabled) { 1202 mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = enabled; 1203 } 1204 1205 /** 1206 * Resets whether using split screen aspect ratio as a default aspect ratio for unresizable 1207 * apps {@link R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled}. 1208 */ resetIsSplitScreenAspectRatioForUnresizableAppsEnabled()1209 void resetIsSplitScreenAspectRatioForUnresizableAppsEnabled() { 1210 mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean( 1211 R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled); 1212 } 1213 1214 /** 1215 * Resets whether using display aspect ratio as a default aspect ratio for all letterboxed 1216 * apps {@link R.bool.config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled}. 1217 */ resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox()1218 void resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox() { 1219 mIsDisplayAspectRatioEnabledForFixedOrientationLetterbox = mContext.getResources() 1220 .getBoolean(R.bool 1221 .config_letterboxIsDisplayAspectRatioForFixedOrientationLetterboxEnabled); 1222 } 1223 isTranslucentLetterboxingEnabled()1224 boolean isTranslucentLetterboxingEnabled() { 1225 return mTranslucentLetterboxingOverrideEnabled 1226 || mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY); 1227 } 1228 setTranslucentLetterboxingOverrideEnabled( boolean translucentLetterboxingOverrideEnabled)1229 void setTranslucentLetterboxingOverrideEnabled( 1230 boolean translucentLetterboxingOverrideEnabled) { 1231 mTranslucentLetterboxingOverrideEnabled = translucentLetterboxingOverrideEnabled; 1232 } 1233 1234 /** 1235 * Resets whether we use the constraints override strategy for letterboxing when dealing 1236 * with translucent activities 1237 * {@link mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_TRANSLUCENT_ACTIVITY)}. 1238 */ resetTranslucentLetterboxingEnabled()1239 void resetTranslucentLetterboxingEnabled() { 1240 setTranslucentLetterboxingOverrideEnabled(false); 1241 } 1242 1243 /** Calculates a new letterboxPositionForHorizontalReachability value and updates the store */ updatePositionForHorizontalReachability(boolean isDeviceInBookMode, Function<Integer, Integer> newHorizonalPositionFun)1244 private void updatePositionForHorizontalReachability(boolean isDeviceInBookMode, 1245 Function<Integer, Integer> newHorizonalPositionFun) { 1246 final int letterboxPositionForHorizontalReachability = 1247 mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability( 1248 isDeviceInBookMode); 1249 final int nextHorizontalPosition = newHorizonalPositionFun.apply( 1250 letterboxPositionForHorizontalReachability); 1251 mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability( 1252 isDeviceInBookMode, nextHorizontalPosition); 1253 } 1254 1255 /** Calculates a new letterboxPositionForVerticalReachability value and updates the store */ updatePositionForVerticalReachability(boolean isDeviceInTabletopMode, Function<Integer, Integer> newVerticalPositionFun)1256 private void updatePositionForVerticalReachability(boolean isDeviceInTabletopMode, 1257 Function<Integer, Integer> newVerticalPositionFun) { 1258 final int letterboxPositionForVerticalReachability = 1259 mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability( 1260 isDeviceInTabletopMode); 1261 final int nextVerticalPosition = newVerticalPositionFun.apply( 1262 letterboxPositionForVerticalReachability); 1263 mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability( 1264 isDeviceInTabletopMode, nextVerticalPosition); 1265 } 1266 1267 /** Whether fake sending focus is enabled for unfocused apps in splitscreen */ isCompatFakeFocusEnabled()1268 boolean isCompatFakeFocusEnabled() { 1269 return mDeviceConfig.getFlagValue(KEY_ENABLE_COMPAT_FAKE_FOCUS); 1270 } 1271 1272 /** 1273 * Whether should ignore app requested orientation in response to an app calling 1274 * {@link android.app.Activity#setRequestedOrientation}. See {@link 1275 * LetterboxUiController#shouldIgnoreRequestedOrientation} for details. 1276 */ isPolicyForIgnoringRequestedOrientationEnabled()1277 boolean isPolicyForIgnoringRequestedOrientationEnabled() { 1278 return mIsPolicyForIgnoringRequestedOrientationEnabled; 1279 } 1280 1281 /** 1282 * Whether we should use split screen aspect ratio for the activity when camera compat treatment 1283 * is enabled and activity is connected to the camera in fullscreen. 1284 */ isCameraCompatSplitScreenAspectRatioEnabled()1285 boolean isCameraCompatSplitScreenAspectRatioEnabled() { 1286 return mIsCameraCompatSplitScreenAspectRatioEnabled; 1287 } 1288 1289 /** 1290 * @return Whether camera compatibility treatment is currently enabled. 1291 */ isCameraCompatTreatmentEnabled()1292 boolean isCameraCompatTreatmentEnabled() { 1293 return mDeviceConfig.getFlagValue(KEY_ENABLE_CAMERA_COMPAT_TREATMENT); 1294 } 1295 1296 /** 1297 * @return Whether camera compatibility treatment is enabled at build time. This is used when 1298 * we need to safely initialize a component before the {@link DeviceConfig} flag value is 1299 * available. 1300 */ isCameraCompatTreatmentEnabledAtBuildTime()1301 boolean isCameraCompatTreatmentEnabledAtBuildTime() { 1302 return mDeviceConfig.isBuildTimeFlagEnabled(KEY_ENABLE_CAMERA_COMPAT_TREATMENT); 1303 } 1304 1305 /** Whether camera compatibility refresh is enabled. */ isCameraCompatRefreshEnabled()1306 boolean isCameraCompatRefreshEnabled() { 1307 return mIsCameraCompatTreatmentRefreshEnabled; 1308 } 1309 1310 /** Overrides whether camera compatibility treatment is enabled. */ setCameraCompatRefreshEnabled(boolean enabled)1311 void setCameraCompatRefreshEnabled(boolean enabled) { 1312 mIsCameraCompatTreatmentRefreshEnabled = enabled; 1313 } 1314 1315 /** 1316 * Resets whether camera compatibility treatment is enabled to {@code true}. 1317 */ resetCameraCompatRefreshEnabled()1318 void resetCameraCompatRefreshEnabled() { 1319 mIsCameraCompatTreatmentRefreshEnabled = true; 1320 } 1321 1322 /** 1323 * Whether activity "refresh" in camera compatibility treatment should happen using the 1324 * "stopped -> resumed" cycle rather than "paused -> resumed" cycle. 1325 */ isCameraCompatRefreshCycleThroughStopEnabled()1326 boolean isCameraCompatRefreshCycleThroughStopEnabled() { 1327 return mIsCameraCompatRefreshCycleThroughStopEnabled; 1328 } 1329 1330 /** 1331 * Overrides whether activity "refresh" in camera compatibility treatment should happen using 1332 * "stopped -> resumed" cycle rather than "paused -> resumed" cycle. 1333 */ setCameraCompatRefreshCycleThroughStopEnabled(boolean enabled)1334 void setCameraCompatRefreshCycleThroughStopEnabled(boolean enabled) { 1335 mIsCameraCompatRefreshCycleThroughStopEnabled = enabled; 1336 } 1337 1338 /** 1339 * Resets whether activity "refresh" in camera compatibility treatment should happen using 1340 * "stopped -> resumed" cycle rather than "paused -> resumed" cycle to {@code true}. 1341 */ resetCameraCompatRefreshCycleThroughStopEnabled()1342 void resetCameraCompatRefreshCycleThroughStopEnabled() { 1343 mIsCameraCompatRefreshCycleThroughStopEnabled = true; 1344 } 1345 1346 /** 1347 * Checks whether rotation compat policy for immersive apps that prevents auto rotation 1348 * into non-optimal screen orientation while in fullscreen is enabled at build time. This is 1349 * used when we need to safely initialize a component before the {@link DeviceConfig} flag 1350 * value is available. 1351 * 1352 * <p>This is needed because immersive apps, such as games, are often not optimized for all 1353 * orientations and can have a poor UX when rotated. Additionally, some games rely on sensors 1354 * for the gameplay so users can trigger such rotations accidentally when auto rotation is on. 1355 */ isDisplayRotationImmersiveAppCompatPolicyEnabledAtBuildTime()1356 boolean isDisplayRotationImmersiveAppCompatPolicyEnabledAtBuildTime() { 1357 return mDeviceConfig.isBuildTimeFlagEnabled( 1358 KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY); 1359 } 1360 1361 /** 1362 * Checks whether rotation compat policy for immersive apps that prevents auto rotation 1363 * into non-optimal screen orientation while in fullscreen is currently enabled. 1364 * 1365 * <p>This is needed because immersive apps, such as games, are often not optimized for all 1366 * orientations and can have a poor UX when rotated. Additionally, some games rely on sensors 1367 * for the gameplay so users can trigger such rotations accidentally when auto rotation is on. 1368 */ isDisplayRotationImmersiveAppCompatPolicyEnabled()1369 boolean isDisplayRotationImmersiveAppCompatPolicyEnabled() { 1370 return mDeviceConfig.getFlagValue(KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY); 1371 } 1372 1373 /** 1374 * Whether per-app user aspect ratio override settings is enabled 1375 */ isUserAppAspectRatioSettingsEnabled()1376 boolean isUserAppAspectRatioSettingsEnabled() { 1377 return mUserAppAspectRatioSettingsOverrideEnabled 1378 || mDeviceConfig.getFlagValue(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS); 1379 } 1380 setUserAppAspectRatioSettingsOverrideEnabled(boolean enabled)1381 void setUserAppAspectRatioSettingsOverrideEnabled(boolean enabled) { 1382 mUserAppAspectRatioSettingsOverrideEnabled = enabled; 1383 } 1384 1385 /** 1386 * Resets whether per-app user aspect ratio override settings is enabled 1387 * {@code mDeviceConfig.getFlagValue(KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS)}. 1388 */ resetUserAppAspectRatioSettingsEnabled()1389 void resetUserAppAspectRatioSettingsEnabled() { 1390 setUserAppAspectRatioSettingsOverrideEnabled(false); 1391 } 1392 1393 /** 1394 * Whether fullscreen option in per-app user aspect ratio settings is enabled 1395 */ isUserAppAspectRatioFullscreenEnabled()1396 boolean isUserAppAspectRatioFullscreenEnabled() { 1397 return isUserAppAspectRatioSettingsEnabled() 1398 && (mUserAppAspectRatioFullscreenOverrideEnabled 1399 || mDeviceConfig.getFlagValue(KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN)); 1400 } 1401 setUserAppAspectRatioFullscreenOverrideEnabled(boolean enabled)1402 void setUserAppAspectRatioFullscreenOverrideEnabled(boolean enabled) { 1403 mUserAppAspectRatioFullscreenOverrideEnabled = enabled; 1404 } 1405 resetUserAppAspectRatioFullscreenEnabled()1406 void resetUserAppAspectRatioFullscreenEnabled() { 1407 setUserAppAspectRatioFullscreenOverrideEnabled(false); 1408 } 1409 1410 /** 1411 * Checks whether the multiplier is between [0,1]. 1412 * 1413 * @param multiplierName sent in the exception if multiplier is invalid, for easier debugging. 1414 * 1415 * @return multiplier, if valid 1416 * @throws IllegalArgumentException if outside bounds. 1417 */ assertValidMultiplier(float multiplier, String multiplierName)1418 private float assertValidMultiplier(float multiplier, String multiplierName) 1419 throws IllegalArgumentException { 1420 if (multiplier < 0.0f || multiplier > 1.0f) { 1421 throw new IllegalArgumentException("Trying to set " + multiplierName 1422 + " out of bounds: " + multiplier); 1423 } 1424 return multiplier; 1425 } 1426 } 1427