1 /*
2  * Copyright (C) 2017 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.launcher3.config;
18 
19 import static com.android.launcher3.config.FeatureFlags.BooleanFlag.DISABLED;
20 import static com.android.launcher3.config.FeatureFlags.BooleanFlag.ENABLED;
21 import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
22 
23 import android.content.res.Resources;
24 
25 import androidx.annotation.VisibleForTesting;
26 
27 import com.android.launcher3.BuildConfig;
28 import com.android.launcher3.Flags;
29 
30 /**
31  * Defines a set of flags used to control various launcher behaviors.
32  * <p>
33  * <p>All the flags should be defined here with appropriate default values.
34  */
35 public final class FeatureFlags {
36 
FeatureFlags()37     private FeatureFlags() { }
38 
39     /**
40      * True when the build has come from Android Studio and is being used for local debugging.
41      * @deprecated Use {@link BuildConfig#IS_STUDIO_BUILD} directly
42      */
43     @Deprecated
44     public static final boolean IS_STUDIO_BUILD = BuildConfig.IS_STUDIO_BUILD;
45 
46     /**
47      * Enable moving the QSB on the 0th screen of the workspace. This is not a configuration feature
48      * and should be modified at a project level.
49      * @deprecated Use {@link BuildConfig#QSB_ON_FIRST_SCREEN} directly
50      */
51     @Deprecated
52     public static final boolean QSB_ON_FIRST_SCREEN = BuildConfig.QSB_ON_FIRST_SCREEN;
53 
54     /**
55      * Feature flag to handle define config changes dynamically instead of killing the process.
56      * <p>
57      *
58      * To add a new flag that can be toggled through the flags UI:
59      * <p>
60      * Declare a new ToggleableFlag below. Give it a unique key (e.g. "QSB_ON_FIRST_SCREEN"),
61      * and set a default value for the flag. This will be the default value on Debug builds.
62      * <p>
63      */
64     // TODO(Block 2): Clean up flags
65     public static final BooleanFlag ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH = getDebugFlag(270395073,
66             "ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", DISABLED,
67             "Allow bottom sheet depth to be smaller than 1 for multi-display devices.");
68 
69     // TODO(Block 3): Clean up flags
70     public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
71             "ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
72             "Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
73     public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
74             "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame");
75 
76     public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424,
77             "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", DISABLED,
78             "load the current workspace screen visible to the user before the rest rather than "
79                     + "loading all of them at once.");
80 
81     public static final BooleanFlag CHANGE_MODEL_DELEGATE_LOADING_ORDER = getDebugFlag(251502424,
82             "CHANGE_MODEL_DELEGATE_LOADING_ORDER", DISABLED,
83             "changes the timing of the loading and binding of delegate items during "
84                     + "data preparation for loading the home screen");
85 
86     // TODO(Block 4): Cleanup flags
87     public static final BooleanFlag ENABLE_ALL_APPS_FROM_OVERVIEW =
88             getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED,
89                     "Allow entering All Apps from Overview (e.g. long swipe up from app)");
90 
91     public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
92             270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
93             "Enable option to show keyboard when going to all-apps");
94 
95     // TODO(Block 5): Clean up flags
96     public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851,
97             "ENABLE_TWOLINE_DEVICESEARCH", DISABLED,
98             "Enable two line label for icons with labels on device search.");
99 
100     public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143,
101             "ENABLE_ICON_IN_TEXT_HEADER", DISABLED, "Show icon in textheader");
102 
103     public static final BooleanFlag ENABLE_PREMIUM_HAPTICS_ALL_APPS = getDebugFlag(270396358,
104             "ENABLE_PREMIUM_HAPTICS_ALL_APPS", DISABLED,
105             "Enables haptics opening/closing All apps");
106 
107     // TODO(Block 6): Clean up flags
108     public static final BooleanFlag ENABLE_ALL_APPS_SEARCH_IN_TASKBAR = getDebugFlag(270393900,
109             "ENABLE_ALL_APPS_SEARCH_IN_TASKBAR", ENABLED,
110             "Enables Search box in Taskbar All Apps.");
111 
112     public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(270395140,
113             "SECONDARY_DRAG_N_DROP_TO_PIN", DISABLED,
114             "Enable dragging and dropping to pin apps within secondary display");
115 
116     // TODO(Block 8): Clean up flags
117 
118     // TODO(Block 9): Clean up flags
119     public static final BooleanFlag MULTI_SELECT_EDIT_MODE = getDebugFlag(270709220,
120             "MULTI_SELECT_EDIT_MODE", DISABLED, "Enable new multi-select edit mode "
121                     + "for home screen");
122 
123     // TODO(Block 11): Clean up flags
124     public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
125             "FOLDABLE_SINGLE_PAGE", DISABLED, "Use a single page for the workspace");
126 
127     public static final BooleanFlag ENABLE_PARAMETRIZE_REORDER = getDebugFlag(289420844,
128             "ENABLE_PARAMETRIZE_REORDER", DISABLED,
129             "Enables generating the reorder using a set of parameters");
130 
131     // TODO(Block 12): Clean up flags
132     public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680,
133             "ENABLE_MULTI_INSTANCE", DISABLED,
134             "Enables creation and filtering of multiple task instances in overview");
135 
136     // TODO(Block 13): Clean up flags
137     public static final BooleanFlag ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING = getReleaseFlag(
138             270391397, "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", DISABLED,
139             "Allows on device search in all apps logging");
140 
141     // TODO(Block 14): Cleanup flags
142     public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag(270393108, "NOTIFY_CRASHES",
143             DISABLED, "Sends a notification whenever launcher encounters an uncaught exception.");
144 
145     public static final boolean ENABLE_TASKBAR_NAVBAR_UNIFICATION =
146             enableTaskbarNavbarUnification() && !isPhone();
147 
isPhone()148     private static boolean isPhone() {
149         final boolean isPhone;
150         int foldedDeviceStatesId = Resources.getSystem().getIdentifier(
151                 "config_foldedDeviceStates", "array", "android");
152         if (foldedDeviceStatesId != 0) {
153             isPhone = Resources.getSystem().getIntArray(foldedDeviceStatesId).length == 0;
154         } else {
155             isPhone = true;
156         }
157         return isPhone;
158     }
159 
160     // Aconfig migration complete for ENABLE_TASKBAR_NO_RECREATION.
161     public static final BooleanFlag ENABLE_TASKBAR_NO_RECREATION = getDebugFlag(299193589,
162             "ENABLE_TASKBAR_NO_RECREATION", DISABLED,
163             "Enables taskbar with no recreation from lifecycle changes of TaskbarActivityContext.");
enableTaskbarNoRecreate()164     public static boolean enableTaskbarNoRecreate() {
165         return ENABLE_TASKBAR_NO_RECREATION.get() || Flags.enableTaskbarNoRecreate()
166                 // Task bar pinning and task bar nav bar unification are both dependent on
167                 // ENABLE_TASKBAR_NO_RECREATION. We want to turn ENABLE_TASKBAR_NO_RECREATION on
168                 // when either of the dependent features is turned on.
169                 || enableTaskbarPinning() || ENABLE_TASKBAR_NAVBAR_UNIFICATION;
170     }
171 
172     // TODO(Block 16): Clean up flags
173     // When enabled the promise icon is visible in all apps while installation an app.
174     public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012,
175             "PROMISE_APPS_IN_ALL_APPS", DISABLED, "Add promise icon in all-apps");
176 
177     public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(270390904,
178             "KEYGUARD_ANIMATION", DISABLED,
179             "Enable animation for keyguard going away on wallpaper");
180 
181     public static final BooleanFlag ENABLE_DEVICE_SEARCH = getReleaseFlag(270390907,
182             "ENABLE_DEVICE_SEARCH", ENABLED, "Allows on device search in all apps");
183 
184     public static final BooleanFlag ENABLE_HIDE_HEADER = getReleaseFlag(270390930,
185             "ENABLE_HIDE_HEADER", ENABLED, "Hide header on keyboard before typing in all apps");
186 
187     // Aconfig migration complete for ENABLE_EXPANDING_PAUSE_WORK_BUTTON.
188     public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = getDebugFlag(270390779,
189             "ENABLE_EXPANDING_PAUSE_WORK_BUTTON", DISABLED,
190             "Expand and collapse pause work button while scrolling");
191 
192     // Aconfig migration complete for ENABLE_TWOLINE_ALLAPPS.
193     public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
194             "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps.");
195 
196     public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
197             "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
198 
199     public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638,
200             "FOLDER_NAME_MAJORITY_RANKING", ENABLED,
201             "Suggests folder names based on majority based ranking.");
202 
203     public static final BooleanFlag INJECT_FALLBACK_APP_CORPUS_RESULTS = getReleaseFlag(270391706,
204             "INJECT_FALLBACK_APP_CORPUS_RESULTS", DISABLED,
205             "Inject fallback app corpus result when AiAi fails to return it.");
206 
207     // TODO(Block 17): Clean up flags
208     // Aconfig migration complete for ENABLE_TASKBAR_PINNING.
209     private static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(296231746,
210             "ENABLE_TASKBAR_PINNING", DISABLED,
211             "Enables taskbar pinning to allow user to switch between transient and persistent "
212                     + "taskbar flavors");
213 
enableTaskbarPinning()214     public static boolean enableTaskbarPinning() {
215         return ENABLE_TASKBAR_PINNING.get() || Flags.enableTaskbarPinning();
216     }
217 
218     // Aconfig migration complete for ENABLE_APP_PAIRS.
219     public static final BooleanFlag ENABLE_APP_PAIRS = getDebugFlag(274189428,
220             "ENABLE_APP_PAIRS", DISABLED,
221             "Enables the ability to create and save app pairs on the Home screen for easy"
222                     + " split screen launching.");
enableAppPairs()223     public static boolean enableAppPairs() {
224         return ENABLE_APP_PAIRS.get() || com.android.wm.shell.Flags.enableAppPairs();
225     }
226 
227     // TODO(Block 19): Clean up flags
228     public static final BooleanFlag SCROLL_TOP_TO_RESET = getReleaseFlag(270395177,
229             "SCROLL_TOP_TO_RESET", ENABLED,
230             "Bring up IME and focus on input when scroll to top if 'Always show keyboard'"
231                     + " is enabled or in prefix state");
232 
233     public static final BooleanFlag ENABLE_SEARCH_UNINSTALLED_APPS = getReleaseFlag(270395269,
234             "ENABLE_SEARCH_UNINSTALLED_APPS", ENABLED, "Search uninstalled app results.");
235 
236     // TODO(Block 20): Clean up flags
237     public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(270393276,
238             "ENABLE_SCRIM_FOR_APP_LAUNCH", DISABLED, "Enables scrim during app launch animation.");
239 
240     public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(270393426,
241             "ENABLE_BACK_SWIPE_HOME_ANIMATION", ENABLED,
242             "Enables home animation to icon when user swipes back.");
243 
244     public static final BooleanFlag ENABLE_DYNAMIC_TASKBAR_THRESHOLDS = getDebugFlag(294252473,
245             "ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", ENABLED,
246             "Enables taskbar thresholds that scale based on screen size.");
247 
248     // Aconfig migration complete for ENABLE_HOME_TRANSITION_LISTENER.
249     public static final BooleanFlag ENABLE_HOME_TRANSITION_LISTENER = getDebugFlag(306053414,
250             "ENABLE_HOME_TRANSITION_LISTENER", DISABLED,
251             "Enables launcher to listen to all transitions that include home activity.");
252 
enableHomeTransitionListener()253     public static boolean enableHomeTransitionListener() {
254         return ENABLE_HOME_TRANSITION_LISTENER.get() || Flags.enableHomeTransitionListener();
255     }
256 
257     // TODO(Block 21): Clean up flags
258     public static final BooleanFlag ENABLE_APP_ICON_FOR_INLINE_SHORTCUTS = getDebugFlag(270395087,
259             "ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", DISABLED, "Show app icon for inline shortcut");
260 
261     // TODO(Block 22): Clean up flags
262     public static final BooleanFlag ENABLE_WIDGET_TRANSITION_FOR_RESIZING = getDebugFlag(268553314,
263             "ENABLE_WIDGET_TRANSITION_FOR_RESIZING", DISABLED,
264             "Enable widget transition animation when resizing the widgets");
265 
266     public static final BooleanFlag PREEMPTIVE_UNFOLD_ANIMATION_START = getDebugFlag(270397209,
267             "PREEMPTIVE_UNFOLD_ANIMATION_START", ENABLED,
268             "Enables starting the unfold animation preemptively when unfolding, without"
269                     + "waiting for SystemUI and then merging the SystemUI progress whenever we "
270                     + "start receiving the events");
271 
272     // TODO(Block 25): Clean up flags
273     public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
274             "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
275             "Enable the redesigned gesture navigation tutorial");
276 
277     // TODO(Block 26): Clean up flags
278     public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag(270394384,
279             "ENABLE_WIDGET_HOST_IN_BACKGROUND", ENABLED,
280             "Enable background widget updates listening for widget holder");
281 
282     // TODO(Block 27): Clean up flags
283     public static final BooleanFlag ENABLE_OVERLAY_CONNECTION_OPTIM = getDebugFlag(270392629,
284             "ENABLE_OVERLAY_CONNECTION_OPTIM", DISABLED,
285             "Enable optimizing overlay service connection");
286 
287     /**
288      * Enables region sampling for text color: Needs system health assessment before turning on
289      */
290     public static final BooleanFlag ENABLE_REGION_SAMPLING = getDebugFlag(270391669,
291             "ENABLE_REGION_SAMPLING", DISABLED,
292             "Enable region sampling to determine color of text on screen.");
293 
294     public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
295             getDebugFlag(270393096, "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS",
296             DISABLED, "Always use hardware optimization for folder animations.");
297 
298     public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag(270392980,
299             "SEPARATE_RECENTS_ACTIVITY", DISABLED,
300             "Uses a separate recents activity instead of using the integrated recents+Launcher UI");
301 
302     public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = getReleaseFlag(270393258,
303             "ENABLE_ENFORCED_ROUNDED_CORNERS", ENABLED,
304             "Enforce rounded corners on all App Widgets");
305 
306     public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(270394973,
307             "USE_LOCAL_ICON_OVERRIDES", ENABLED,
308             "Use inbuilt monochrome icons if app doesn't provide one");
309 
310     // Aconfig migration complete for ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.
311     public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
312             270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", DISABLED,
313             "Enable initiating split screen from workspace to workspace.");
enableSplitContextually()314     public static boolean enableSplitContextually() {
315         return ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get() ||
316                 com.android.wm.shell.Flags.enableSplitContextual();
317     }
318 
319     public static final BooleanFlag ENABLE_TRACKPAD_GESTURE = getDebugFlag(271010401,
320             "ENABLE_TRACKPAD_GESTURE", ENABLED, "Enables trackpad gesture.");
321 
322     // TODO(Block 29): Clean up flags
323     public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(270393897,
324             "ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", DISABLED,
325             "Enables displaying the all apps button in the hotseat.");
326 
327     public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(270396844,
328             "ENABLE_KEYBOARD_QUICK_SWITCH", ENABLED, "Enables keyboard quick switching");
329 
330     public static final BooleanFlag ENABLE_KEYBOARD_TASKBAR_TOGGLE = getDebugFlag(281726846,
331             "ENABLE_KEYBOARD_TASKBAR_TOGGLE", ENABLED,
332             "Enables keyboard taskbar stash toggling");
333 
334     // TODO(Block 30): Clean up flags
335     public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(270395010,
336             "USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES", DISABLED,
337             "Use local overrides for search request timeout");
338 
339     // TODO(Block 31): Clean up flags
340 
341     // TODO(Block 32): Clean up flags
342     // Aconfig migration complete for ENABLE_RESPONSIVE_WORKSPACE.
343     @VisibleForTesting
344     public static final BooleanFlag ENABLE_RESPONSIVE_WORKSPACE = getDebugFlag(241386436,
345             "ENABLE_RESPONSIVE_WORKSPACE", DISABLED,
346             "Enables new workspace grid calculations method.");
enableResponsiveWorkspace()347     public static boolean enableResponsiveWorkspace() {
348         return ENABLE_RESPONSIVE_WORKSPACE.get() || Flags.enableResponsiveWorkspace();
349     }
350 
351     // TODO(Block 33): Clean up flags
352     public static final BooleanFlag ENABLE_ALL_APPS_RV_PREINFLATION = getDebugFlag(288161355,
353             "ENABLE_ALL_APPS_RV_PREINFLATION", ENABLED,
354             "Enables preinflating all apps icons to avoid scrolling jank.");
355     public static final BooleanFlag ALL_APPS_GONE_VISIBILITY = getDebugFlag(291651514,
356             "ALL_APPS_GONE_VISIBILITY", ENABLED,
357             "Set all apps container view's hidden visibility to GONE instead of INVISIBLE.");
358 
getDebugFlag( int bugId, String key, BooleanFlag flagState, String description)359     public static BooleanFlag getDebugFlag(
360             int bugId, String key, BooleanFlag flagState, String description) {
361         return flagState;
362     }
363 
getReleaseFlag( int bugId, String key, BooleanFlag flagState, String description)364     public static BooleanFlag getReleaseFlag(
365             int bugId, String key, BooleanFlag flagState, String description) {
366         return flagState;
367     }
368 
369     /**
370      * Enabled state for a flag
371      */
372     public enum BooleanFlag {
373         ENABLED(true),
374         DISABLED(false);
375 
376         private final boolean mValue;
377 
BooleanFlag(boolean value)378         BooleanFlag(boolean value) {
379             mValue = value;
380         }
381 
get()382         public boolean get() {
383             return mValue;
384         }
385     }
386 }
387