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