• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 android.window;
18 
19 import android.annotation.Nullable;
20 import android.app.ActivityThread;
21 import android.app.Application;
22 import android.content.ContentResolver;
23 import android.os.SystemProperties;
24 import android.provider.Settings;
25 import android.util.Log;
26 
27 import com.android.window.flags.Flags;
28 
29 import java.util.function.BooleanSupplier;
30 
31 /**
32  * Checks desktop mode flag state.
33  *
34  * <p>This enum provides a centralized way to control the behavior of flags related to desktop
35  * windowing features which are aiming for developer preview before their release. It allows
36  * developer option to override the default behavior of these flags.
37  *
38  * <p>NOTE: Flags should only be added to this enum when they have received Product and UX
39  * alignment that the feature is ready for developer preview, otherwise just do a flag check.
40  *
41  * @hide
42  */
43 public enum DesktopModeFlags {
44     // All desktop mode related flags to be overridden by developer option toggle will be added here
45     // go/keep-sorted start
46     DISABLE_DESKTOP_LAUNCH_PARAMS_OUTSIDE_DESKTOP_BUG_FIX(
47             Flags::disableDesktopLaunchParamsOutsideDesktopBugFix, true),
48     DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE(Flags::disableNonResizableAppSnapResizing, true),
49     ENABLE_ACCESSIBLE_CUSTOM_HEADERS(Flags::enableAccessibleCustomHeaders, true),
50     ENABLE_APP_HEADER_WITH_TASK_DENSITY(Flags::enableAppHeaderWithTaskDensity, true),
51     ENABLE_CAMERA_COMPAT_SIMULATE_REQUESTED_ORIENTATION(
52             Flags::enableCameraCompatForDesktopWindowing, true),
53     ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION(Flags::enableCaptionCompatInsetForceConsumption,
54             true),
55     ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS(
56             Flags::enableCaptionCompatInsetForceConsumptionAlways, true),
57     ENABLE_CASCADING_WINDOWS(Flags::enableCascadingWindows, true),
58     ENABLE_DESKTOP_APP_HANDLE_ANIMATION(Flags::enableDesktopAppHandleAnimation, true),
59     ENABLE_DESKTOP_APP_LAUNCH_ALTTAB_TRANSITIONS_BUGFIX(
60             Flags::enableDesktopAppLaunchAlttabTransitionsBugfix, true),
61     ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX(Flags::enableDesktopAppLaunchTransitionsBugfix,
62             true),
63     ENABLE_DESKTOP_CLOSE_SHORTCUT_BUGFIX(Flags::enableDesktopCloseShortcutBugfix, false),
64     ENABLE_DESKTOP_COMPAT_UI_VISIBILITY_STATUS(Flags::enableCompatUiVisibilityStatus, true),
65     ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX(Flags::enableDesktopImmersiveDragBugfix, true),
66     ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX(
67             Flags::enableDesktopIndicatorInSeparateThreadBugfix, true),
68     ENABLE_DESKTOP_OPENING_DEEPLINK_MINIMIZE_ANIMATION_BUGFIX(
69             Flags::enableDesktopOpeningDeeplinkMinimizeAnimationBugfix, true),
70     ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX(
71             Flags::enableDesktopRecentsTransitionsCornersBugfix, true),
72     ENABLE_DESKTOP_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE_BUGFIX(
73             Flags::skipCompatUiEducationInDesktopMode, true),
74     ENABLE_DESKTOP_SYSTEM_DIALOGS_TRANSITIONS(Flags::enableDesktopSystemDialogsTransitions, true),
75     ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX(
76             Flags::enableDesktopTabTearingMinimizeAnimationBugfix, true),
77     ENABLE_DESKTOP_TRAMPOLINE_CLOSE_ANIMATION_BUGFIX(
78             Flags::enableDesktopTrampolineCloseAnimationBugfix, true),
79     ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER(
80             Flags::enableDesktopWallpaperActivityForSystemUser, true),
81     ENABLE_DESKTOP_WINDOWING_APP_TO_WEB(Flags::enableDesktopWindowingAppToWeb, true),
82     ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION(Flags::enableDesktopWindowingAppToWebEducation,
83             true),
84     ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION(Flags::enableDesktopWindowingBackNavigation, true),
85     ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX(
86             Flags::enableDesktopWindowingEnterTransitionBugfix, true),
87     ENABLE_DESKTOP_WINDOWING_EXIT_BY_MINIMIZE_TRANSITION_BUGFIX(
88             Flags::enableDesktopWindowingExitByMinimizeTransitionBugfix, true),
89     ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX(
90             Flags::enableDesktopWindowingExitTransitionsBugfix, true),
91     ENABLE_DESKTOP_WINDOWING_HSUM(Flags::enableDesktopWindowingHsum, true),
92     ENABLE_DESKTOP_WINDOWING_IMMERSIVE_HANDLE_HIDING(
93             Flags::enableDesktopWindowingImmersiveHandleHiding, true),
94     ENABLE_DESKTOP_WINDOWING_MODALS_POLICY(Flags::enableDesktopWindowingModalsPolicy, true),
95     ENABLE_DESKTOP_WINDOWING_MODE(Flags::enableDesktopWindowingMode, true),
96     ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES(
97             Flags::enableDesktopWindowingMultiInstanceFeatures, true),
98     ENABLE_DESKTOP_WINDOWING_PERSISTENCE(Flags::enableDesktopWindowingPersistence, true),
99     ENABLE_DESKTOP_WINDOWING_PIP(Flags::enableDesktopWindowingPip, false),
100     ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH(Flags::enableDesktopWindowingQuickSwitch, true),
101     ENABLE_DESKTOP_WINDOWING_SCVH_CACHE(Flags::enableDesktopWindowingScvhCacheBugFix, true),
102     ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS(Flags::enableDesktopWindowingSizeConstraints, true),
103     ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS(Flags::enableDesktopWindowingTaskbarRunningApps,
104             true),
105     ENABLE_DESKTOP_WINDOWING_TASK_LIMIT(Flags::enableDesktopWindowingTaskLimit, true),
106     ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY(Flags::enableDesktopWindowingWallpaperActivity,
107             true),
108     ENABLE_DRAG_RESIZE_SET_UP_IN_BG_THREAD(Flags::enableDragResizeSetUpInBgThread, true),
109     ENABLE_DRAG_TO_DESKTOP_INCOMING_TRANSITIONS_BUGFIX(
110             Flags::enableDragToDesktopIncomingTransitionsBugfix, true),
111     ENABLE_FULLY_IMMERSIVE_IN_DESKTOP(Flags::enableFullyImmersiveInDesktop, true),
112     ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true),
113     ENABLE_HOLD_TO_DRAG_APP_HANDLE(Flags::enableHoldToDragAppHandle, true),
114     ENABLE_INPUT_LAYER_TRANSITION_FIX(Flags::enableInputLayerTransitionFix, true),
115     ENABLE_MINIMIZE_BUTTON(Flags::enableMinimizeButton, true),
116     ENABLE_MODALS_FULLSCREEN_WITH_PERMISSIONS(Flags::enableModalsFullscreenWithPermission, true),
117     ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS(
118             Flags::enableOpaqueBackgroundForTransparentWindows, true),
119     ENABLE_QUICKSWITCH_DESKTOP_SPLIT_BUGFIX(Flags::enableQuickswitchDesktopSplitBugfix, true),
120     ENABLE_REQUEST_FULLSCREEN_BUGFIX(Flags::enableRequestFullscreenBugfix, true),
121     ENABLE_RESIZING_METRICS(Flags::enableResizingMetrics, true),
122     ENABLE_RESTORE_TO_PREVIOUS_SIZE_FROM_DESKTOP_IMMERSIVE(
123             Flags::enableRestoreToPreviousSizeFromDesktopImmersive, true),
124     ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX(
125             Flags::enableShellInitialBoundsRegressionBugFix, true),
126     ENABLE_START_LAUNCH_TRANSITION_FROM_TASKBAR_BUGFIX(
127             Flags::enableStartLaunchTransitionFromTaskbarBugfix, true),
128     ENABLE_TASKBAR_OVERFLOW(Flags::enableTaskbarOverflow, false),
129     ENABLE_TASKBAR_RECENTS_LAYOUT_TRANSITION(Flags::enableTaskbarRecentsLayoutTransition, false),
130     ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS(Flags::enableTaskResizingKeyboardShortcuts, true),
131     ENABLE_TASK_STACK_OBSERVER_IN_SHELL(Flags::enableTaskStackObserverInShell, true),
132     ENABLE_THEMED_APP_HEADERS(Flags::enableThemedAppHeaders, true),
133     ENABLE_TILE_RESIZING(Flags::enableTileResizing, true),
134     ENABLE_TOP_VISIBLE_ROOT_TASK_PER_USER_TRACKING(Flags::enableTopVisibleRootTaskPerUserTracking,
135             true),
136     ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX(
137             Flags::enableVisualIndicatorInTransitionBugfix, true),
138     ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS(Flags::enableWindowingDynamicInitialBounds, true),
139     ENABLE_WINDOWING_EDGE_DRAG_RESIZE(Flags::enableWindowingEdgeDragResize, true),
140     ENABLE_WINDOWING_SCALED_RESIZING(Flags::enableWindowingScaledResizing, true),
141     ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS(
142             Flags::enableWindowingTransitionHandlersObservers, false),
143     EXCLUDE_CAPTION_FROM_APP_BOUNDS(Flags::excludeCaptionFromAppBounds, true),
144     FORCE_CLOSE_TOP_TRANSPARENT_FULLSCREEN_TASK(
145             Flags::forceCloseTopTransparentFullscreenTask, false),
146     IGNORE_ASPECT_RATIO_RESTRICTIONS_FOR_RESIZEABLE_FREEFORM_ACTIVITIES(
147             Flags::ignoreAspectRatioRestrictionsForResizeableFreeformActivities, true),
148     INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC(
149             Flags::includeTopTransparentFullscreenTaskInDesktopHeuristic, true),
150     INHERIT_TASK_BOUNDS_FOR_TRAMPOLINE_TASK_LAUNCHES(
151             Flags::inheritTaskBoundsForTrampolineTaskLaunches, true),
152     SKIP_DECOR_VIEW_RELAYOUT_WHEN_CLOSING_BUGFIX(
153             Flags::skipDecorViewRelayoutWhenClosingBugfix, true),
154     // go/keep-sorted end
155     ;
156 
157     /**
158      * Flag class, to be used in case the enum cannot be used because the flag is not accessible.
159      *
160      * <p> This class will still use the process-wide cache.
161      */
162     public static class DesktopModeFlag {
163         // Function called to obtain aconfig flag value.
164         private final BooleanSupplier mFlagFunction;
165         // Whether the flag state should be affected by developer option.
166         private final boolean mShouldOverrideByDevOption;
167 
DesktopModeFlag(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption)168         public DesktopModeFlag(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) {
169             this.mFlagFunction = flagFunction;
170             this.mShouldOverrideByDevOption = shouldOverrideByDevOption;
171         }
172 
173         /**
174          * Determines state of flag based on the actual flag and desktop mode developer option
175          * overrides.
176          */
isTrue()177         public boolean isTrue() {
178             return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption);
179         }
180 
181     }
182 
183     private static final String TAG = "DesktopModeFlags";
184     // Function called to obtain aconfig flag value.
185     private final BooleanSupplier mFlagFunction;
186     // Whether the flag state should be affected by developer option.
187     private final boolean mShouldOverrideByDevOption;
188 
189     // Local cache for toggle override, which is initialized once on its first access. It needs to
190     // be refreshed only on reboots as overridden state is expected to take effect on reboots.
191     private static ToggleOverride sCachedToggleOverride;
192 
193     public static final String SYSTEM_PROPERTY_NAME = "persist.wm.debug.desktop_experience_devopts";
194 
DesktopModeFlags(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption)195     DesktopModeFlags(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) {
196         this.mFlagFunction = flagFunction;
197         this.mShouldOverrideByDevOption = shouldOverrideByDevOption;
198     }
199 
200     /**
201      * Determines state of flag based on the actual flag and desktop mode developer option
202      * overrides.
203      */
isTrue()204     public boolean isTrue() {
205         return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption);
206     }
207 
isDesktopModeForcedEnabled()208     public static boolean isDesktopModeForcedEnabled() {
209         return getToggleOverride() == ToggleOverride.OVERRIDE_ON;
210     }
211 
isFlagTrue(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption)212     private static boolean isFlagTrue(BooleanSupplier flagFunction,
213             boolean shouldOverrideByDevOption) {
214         if (!shouldOverrideByDevOption) return flagFunction.getAsBoolean();
215         if (Flags.showDesktopExperienceDevOption()) {
216             return switch (getToggleOverride()) {
217                 case OVERRIDE_UNSET, OVERRIDE_OFF -> flagFunction.getAsBoolean();
218                 case OVERRIDE_ON -> true;
219             };
220         }
221         if (Flags.showDesktopWindowingDevOption()) {
222             boolean shouldToggleBeEnabledByDefault = Flags.enableDesktopWindowingMode();
223             return switch (getToggleOverride()) {
224                 case OVERRIDE_UNSET -> flagFunction.getAsBoolean();
225                 // When toggle override matches its default state, don't override flags. This
226                 // helps users reset their feature overrides.
227                 case OVERRIDE_OFF -> !shouldToggleBeEnabledByDefault && flagFunction.getAsBoolean();
228                 case OVERRIDE_ON -> !shouldToggleBeEnabledByDefault || flagFunction.getAsBoolean();
229             };
230         }
231         return flagFunction.getAsBoolean();
232     }
233 
234     private static ToggleOverride getToggleOverride() {
235         // If cached, return it
236         if (sCachedToggleOverride != null) {
237             return sCachedToggleOverride;
238         }
239         // Otherwise, fetch and cache it
240         ToggleOverride override = getToggleOverrideFromSystem();
241         sCachedToggleOverride = override;
242         Log.d(TAG, "Toggle override initialized to: " + override);
243         return override;
244     }
245 
246     /**
247      *  Returns {@link ToggleOverride} from Settings.Global set by toggle.
248      */
249     private static ToggleOverride getToggleOverrideFromSystem() {
250         int settingValue;
251         if (Flags.showDesktopExperienceDevOption()) {
252             settingValue = SystemProperties.getInt(
253                     SYSTEM_PROPERTY_NAME,
254                     ToggleOverride.OVERRIDE_UNSET.getSetting()
255             );
256         } else {
257             final Application application = ActivityThread.currentApplication();
258             if (application == null) {
259                 Log.w(TAG, "Could not get the current application.");
260                 return ToggleOverride.OVERRIDE_UNSET;
261             }
262             final ContentResolver contentResolver = application.getContentResolver();
263             if (contentResolver == null) {
264                 Log.w(TAG, "Could not get the content resolver for the application.");
265                 return ToggleOverride.OVERRIDE_UNSET;
266             }
267             settingValue = Settings.Global.getInt(
268                     contentResolver,
269                     Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
270                     ToggleOverride.OVERRIDE_UNSET.getSetting()
271             );
272         }
273         return ToggleOverride.fromSetting(settingValue, ToggleOverride.OVERRIDE_UNSET);
274     }
275 
276     /** Override state of desktop mode developer option toggle. */
277     public enum ToggleOverride {
278         OVERRIDE_UNSET,
279         OVERRIDE_OFF,
280         OVERRIDE_ON;
281 
282         /** Returns the integer representation of this {@code ToggleOverride}. */
283         public int getSetting() {
284             return switch (this) {
285                 case OVERRIDE_ON -> 1;
286                 case OVERRIDE_OFF -> 0;
287                 case OVERRIDE_UNSET -> -1;
288             };
289         }
290 
291         /** Returns the {@code ToggleOverride} corresponding to a given integer setting. */
292         public static ToggleOverride fromSetting(int setting, @Nullable ToggleOverride fallback) {
293             return switch (setting) {
294                 case 1 -> OVERRIDE_ON;
295                 case 0 -> OVERRIDE_OFF;
296                 case -1 -> OVERRIDE_UNSET;
297                 default -> fallback;
298             };
299         }
300     }
301 }
302