• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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