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 android.content.Context; 20 21 import com.android.launcher3.BuildConfig; 22 import com.android.launcher3.Utilities; 23 import com.android.launcher3.uioverrides.DeviceFlag; 24 25 import java.io.PrintWriter; 26 import java.util.ArrayList; 27 import java.util.List; 28 29 /** 30 * Defines a set of flags used to control various launcher behaviors. 31 * 32 * <p>All the flags should be defined here with appropriate default values. 33 */ 34 public final class FeatureFlags { 35 36 private static final List<DebugFlag> sDebugFlags = new ArrayList<>(); 37 38 public static final String FLAGS_PREF_NAME = "featureFlags"; 39 FeatureFlags()40 private FeatureFlags() { } 41 showFlagTogglerUi(Context context)42 public static boolean showFlagTogglerUi(Context context) { 43 return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context); 44 } 45 46 /** 47 * True when the build has come from Android Studio and is being used for local debugging. 48 */ 49 public static final boolean IS_STUDIO_BUILD = BuildConfig.DEBUG; 50 51 /** 52 * Enable moving the QSB on the 0th screen of the workspace. This is not a configuration feature 53 * and should be modified at a project level. 54 */ 55 public static final boolean QSB_ON_FIRST_SCREEN = true; 56 57 /** 58 * Feature flag to handle define config changes dynamically instead of killing the process. 59 * 60 * 61 * To add a new flag that can be toggled through the flags UI: 62 * 63 * Declare a new ToggleableFlag below. Give it a unique key (e.g. "QSB_ON_FIRST_SCREEN"), 64 * and set a default value for the flag. This will be the default value on Debug builds. 65 */ 66 // When enabled the promise icon is visible in all apps while installation an app. 67 public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag( 68 "PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps"); 69 70 // When enabled a promise icon is added to the home screen when install session is active. 71 public static final BooleanFlag PROMISE_APPS_NEW_INSTALLS = getDebugFlag( 72 "PROMISE_APPS_NEW_INSTALLS", true, 73 "Adds a promise icon to the home screen for new install sessions."); 74 75 // TODO: b/206508141: Long pressing on some icons on home screen cause launcher to crash. 76 public static final BooleanFlag ENABLE_LOCAL_COLOR_POPUPS = getDebugFlag( 77 "ENABLE_LOCAL_COLOR_POPUPS", false, "Enable local color extraction for popups."); 78 79 public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag( 80 "KEYGUARD_ANIMATION", false, "Enable animation for keyguard going away on wallpaper"); 81 82 public static final BooleanFlag ADAPTIVE_ICON_WINDOW_ANIM = getDebugFlag( 83 "ADAPTIVE_ICON_WINDOW_ANIM", true, "Use adaptive icons for window animations."); 84 85 public static final BooleanFlag ENABLE_QUICKSTEP_LIVE_TILE = getDebugFlag( 86 "ENABLE_QUICKSTEP_LIVE_TILE", true, "Enable live tile in Quickstep overview"); 87 88 public static final BooleanFlag ENABLE_QUICKSTEP_WIDGET_APP_START = getDebugFlag( 89 "ENABLE_QUICKSTEP_WIDGET_APP_START", true, 90 "Enable Quickstep animation when launching activities from an app widget"); 91 92 public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag( 93 "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps"); 94 95 public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag( 96 "ENABLE_TWOLINE_ALLAPPS", false, "Enables two line label inside all apps."); 97 98 public static final BooleanFlag ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING = new DeviceFlag( 99 "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", true, 100 "Allows on device search in all apps logging"); 101 102 public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag( 103 "IME_STICKY_SNACKBAR_EDU", true, "Show sticky IME edu in AllApps"); 104 105 public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag( 106 "ENABLE_PEOPLE_TILE_PREVIEW", false, 107 "Experimental: Shows conversation shortcuts on home screen as search results"); 108 109 public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag( 110 "FOLDER_NAME_SUGGEST", true, 111 "Suggests folder names instead of blank text."); 112 113 public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag( 114 "FOLDER_NAME_MAJORITY_RANKING", true, 115 "Suggests folder names based on majority based ranking."); 116 117 public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag( 118 "ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list"); 119 120 public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag( 121 "ASSISTANT_GIVES_LAUNCHER_FOCUS", false, 122 "Allow Launcher to handle nav bar gestures while Assistant is running over it"); 123 124 public static final BooleanFlag HOTSEAT_MIGRATE_TO_FOLDER = getDebugFlag( 125 "HOTSEAT_MIGRATE_TO_FOLDER", false, "Should move hotseat items into a folder"); 126 127 public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag( 128 "ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache"); 129 130 public static final BooleanFlag ENABLE_THEMED_ICONS = getDebugFlag( 131 "ENABLE_THEMED_ICONS", true, "Enable themed icons on workspace"); 132 133 public static final BooleanFlag ENABLE_BULK_WORKSPACE_ICON_LOADING = getDebugFlag( 134 "ENABLE_BULK_WORKSPACE_ICON_LOADING", 135 false, 136 "Enable loading workspace icons in bulk."); 137 138 public static final BooleanFlag ENABLE_BULK_ALL_APPS_ICON_LOADING = getDebugFlag( 139 "ENABLE_BULK_ALL_APPS_ICON_LOADING", 140 false, 141 "Enable loading all apps icons in bulk."); 142 143 // Keep as DeviceFlag for remote disable in emergency. 144 public static final BooleanFlag ENABLE_OVERVIEW_SELECTIONS = new DeviceFlag( 145 "ENABLE_OVERVIEW_SELECTIONS", true, "Show Select Mode button in Overview Actions"); 146 147 public static final BooleanFlag ENABLE_WIDGETS_PICKER_AIAI_SEARCH = new DeviceFlag( 148 "ENABLE_WIDGETS_PICKER_AIAI_SEARCH", true, "Enable AiAi search in the widgets picker"); 149 150 public static final BooleanFlag ENABLE_OVERVIEW_SHARING_TO_PEOPLE = getDebugFlag( 151 "ENABLE_OVERVIEW_SHARING_TO_PEOPLE", true, 152 "Show indicators for content on Overview to share with top people. "); 153 154 public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag( 155 "ENABLE_DATABASE_RESTORE", false, 156 "Enable database restore when new restore session is created"); 157 158 public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag( 159 "ENABLE_SMARTSPACE_DISMISS", true, 160 "Adds a menu option to dismiss the current Enhanced Smartspace card."); 161 162 public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS = 163 getDebugFlag( 164 "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false, 165 "Always use hardware optimization for folder animations."); 166 167 public static final BooleanFlag ENABLE_ALL_APPS_EDU = getDebugFlag( 168 "ENABLE_ALL_APPS_EDU", true, 169 "Shows user a tutorial on how to get to All Apps after X amount of attempts."); 170 171 public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag( 172 "SEPARATE_RECENTS_ACTIVITY", false, 173 "Uses a separate recents activity instead of using the integrated recents+Launcher UI"); 174 175 public static final BooleanFlag ENABLE_MINIMAL_DEVICE = getDebugFlag( 176 "ENABLE_MINIMAL_DEVICE", false, 177 "Allow user to toggle minimal device mode in launcher."); 178 179 public static final BooleanFlag EXPANDED_SMARTSPACE = new DeviceFlag( 180 "EXPANDED_SMARTSPACE", false, "Expands smartspace height to two rows. " 181 + "Any apps occupying the first row will be removed from workspace."); 182 183 // TODO: b/172467144 Remove ENABLE_LAUNCHER_ACTIVITY_THEME_CROSSFADE feature flag. 184 public static final BooleanFlag ENABLE_LAUNCHER_ACTIVITY_THEME_CROSSFADE = new DeviceFlag( 185 "ENABLE_LAUNCHER_ACTIVITY_THEME_CROSSFADE", false, "Enables a " 186 + "crossfade animation when the system these changes."); 187 188 // TODO: b/174174514 Remove ENABLE_APP_PREDICTIONS_WHILE_VISIBLE feature flag. 189 public static final BooleanFlag ENABLE_APP_PREDICTIONS_WHILE_VISIBLE = new DeviceFlag( 190 "ENABLE_APP_PREDICTIONS_WHILE_VISIBLE", true, "Allows app " 191 + "predictions to be updated while they are visible to the user."); 192 193 public static final BooleanFlag ENABLE_TASKBAR = getDebugFlag( 194 "ENABLE_TASKBAR", true, "Allows a system Taskbar to be shown on larger devices."); 195 196 public static final BooleanFlag ENABLE_TASKBAR_EDU = getDebugFlag("ENABLE_TASKBAR_EDU", true, 197 "Enables showing taskbar education the first time an app is opened."); 198 199 public static final BooleanFlag ENABLE_TASKBAR_POPUP_MENU = getDebugFlag( 200 "ENABLE_TASKBAR_POPUP_MENU", false, "Enables long pressing taskbar icons to show the" 201 + " popup menu."); 202 203 public static final BooleanFlag ENABLE_OVERVIEW_GRID = getDebugFlag( 204 "ENABLE_OVERVIEW_GRID", true, "Uses grid overview layout. " 205 + "Only applicable on large screen devices."); 206 207 public static final BooleanFlag ENABLE_TWO_PANEL_HOME = getDebugFlag( 208 "ENABLE_TWO_PANEL_HOME", true, 209 "Uses two panel on home screen. Only applicable on large screen devices."); 210 211 public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag( 212 "ENABLE_SCRIM_FOR_APP_LAUNCH", false, 213 "Enables scrim during app launch animation."); 214 215 public static final BooleanFlag ENABLE_SPLIT_SELECT = getDebugFlag( 216 "ENABLE_SPLIT_SELECT", true, "Uses new split screen selection overview UI"); 217 218 public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = new DeviceFlag( 219 "ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets"); 220 221 public static final BooleanFlag ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER = new DeviceFlag( 222 "ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER", true, 223 "Enables a local filter for recommended widgets."); 224 225 public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false, 226 "Sends a notification whenever launcher encounters an uncaught exception."); 227 228 public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag( 229 "ENABLE_WALLPAPER_SCRIM", false, 230 "Enables scrim over wallpaper for text protection."); 231 232 public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag( 233 "WIDGETS_IN_LAUNCHER_PREVIEW", true, 234 "Enables widgets in Launcher preview for the Wallpaper app."); 235 236 public static final BooleanFlag QUICK_WALLPAPER_PICKER = getDebugFlag( 237 "QUICK_WALLPAPER_PICKER", true, 238 "Shows quick wallpaper picker in long-press menu"); 239 240 public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag( 241 "ENABLE_BACK_SWIPE_HOME_ANIMATION", true, 242 "Enables home animation to icon when user swipes back."); 243 244 public static final BooleanFlag ENABLE_ICON_LABEL_AUTO_SCALING = getDebugFlag( 245 "ENABLE_ICON_LABEL_AUTO_SCALING", true, 246 "Enables scaling/spacing for icon labels to make more characters visible"); 247 initialize(Context context)248 public static void initialize(Context context) { 249 synchronized (sDebugFlags) { 250 for (DebugFlag flag : sDebugFlags) { 251 flag.initialize(context); 252 } 253 sDebugFlags.sort((f1, f2) -> f1.key.compareToIgnoreCase(f2.key)); 254 } 255 } 256 getDebugFlags()257 static List<DebugFlag> getDebugFlags() { 258 synchronized (sDebugFlags) { 259 return new ArrayList<>(sDebugFlags); 260 } 261 } 262 dump(PrintWriter pw)263 public static void dump(PrintWriter pw) { 264 pw.println("DeviceFlags:"); 265 synchronized (sDebugFlags) { 266 for (DebugFlag flag : sDebugFlags) { 267 if (flag instanceof DeviceFlag) { 268 pw.println(" " + flag.toString()); 269 } 270 } 271 } 272 pw.println("DebugFlags:"); 273 synchronized (sDebugFlags) { 274 for (DebugFlag flag : sDebugFlags) { 275 if (!(flag instanceof DeviceFlag)) { 276 pw.println(" " + flag.toString()); 277 } 278 } 279 } 280 } 281 282 public static class BooleanFlag { 283 284 public final String key; 285 public final boolean defaultValue; 286 BooleanFlag(String key, boolean defaultValue)287 public BooleanFlag(String key, boolean defaultValue) { 288 this.key = key; 289 this.defaultValue = defaultValue; 290 } 291 get()292 public boolean get() { 293 return defaultValue; 294 } 295 296 @Override toString()297 public String toString() { 298 return appendProps(new StringBuilder()).toString(); 299 } 300 appendProps(StringBuilder src)301 protected StringBuilder appendProps(StringBuilder src) { 302 return src.append(key).append(", defaultValue=").append(defaultValue); 303 } 304 } 305 306 public static class DebugFlag extends BooleanFlag { 307 308 public final String description; 309 protected boolean mCurrentValue; 310 DebugFlag(String key, boolean defaultValue, String description)311 public DebugFlag(String key, boolean defaultValue, String description) { 312 super(key, defaultValue); 313 this.description = description; 314 mCurrentValue = this.defaultValue; 315 synchronized (sDebugFlags) { 316 sDebugFlags.add(this); 317 } 318 } 319 320 @Override get()321 public boolean get() { 322 return mCurrentValue; 323 } 324 initialize(Context context)325 public void initialize(Context context) { 326 mCurrentValue = context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE) 327 .getBoolean(key, defaultValue); 328 } 329 330 @Override appendProps(StringBuilder src)331 protected StringBuilder appendProps(StringBuilder src) { 332 return super.appendProps(src).append(", mCurrentValue=").append(mCurrentValue); 333 } 334 } 335 getDebugFlag(String key, boolean defaultValue, String description)336 private static BooleanFlag getDebugFlag(String key, boolean defaultValue, String description) { 337 return Utilities.IS_DEBUG_DEVICE 338 ? new DebugFlag(key, defaultValue, description) 339 : new BooleanFlag(key, defaultValue); 340 } 341 } 342