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 public static final BooleanFlag APPLY_CONFIG_AT_RUNTIME = getDebugFlag( 76 "APPLY_CONFIG_AT_RUNTIME", true, "Apply display changes dynamically"); 77 78 public static final BooleanFlag QUICKSTEP_SPRINGS = getDebugFlag( 79 "QUICKSTEP_SPRINGS", true, "Enable springs for quickstep animations"); 80 81 public static final BooleanFlag UNSTABLE_SPRINGS = getDebugFlag( 82 "UNSTABLE_SPRINGS", false, "Enable unstable springs for quickstep animations"); 83 84 public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag( 85 "KEYGUARD_ANIMATION", false, "Enable animation for keyguard going away on wallpaper"); 86 87 public static final BooleanFlag ADAPTIVE_ICON_WINDOW_ANIM = getDebugFlag( 88 "ADAPTIVE_ICON_WINDOW_ANIM", true, "Use adaptive icons for window animations."); 89 90 public static final BooleanFlag ENABLE_QUICKSTEP_LIVE_TILE = getDebugFlag( 91 "ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview"); 92 93 // Keep as DeviceFlag to allow remote disable in emergency. 94 public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag( 95 "ENABLE_SUGGESTED_ACTIONS_OVERVIEW", false, "Show chip hints on the overview screen"); 96 97 public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag( 98 "FOLDER_NAME_SUGGEST", true, 99 "Suggests folder names instead of blank text."); 100 101 public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag( 102 "FOLDER_NAME_MAJORITY_RANKING", true, 103 "Suggests folder names based on majority based ranking."); 104 105 public static final BooleanFlag APP_SEARCH_IMPROVEMENTS = new DeviceFlag( 106 "APP_SEARCH_IMPROVEMENTS", true, 107 "Adds localized title and keyword search and ranking"); 108 109 public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag( 110 "ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list"); 111 112 public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag( 113 "ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture"); 114 115 public static final BooleanFlag ENABLE_QUICK_CAPTURE_WINDOW = getDebugFlag( 116 "ENABLE_QUICK_CAPTURE_WINDOW", false, "Use window to host quick capture"); 117 118 public static final BooleanFlag FORCE_LOCAL_OVERSCROLL_PLUGIN = getDebugFlag( 119 "FORCE_LOCAL_OVERSCROLL_PLUGIN", false, 120 "Use a launcher-provided OverscrollPlugin if available"); 121 122 public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag( 123 "ASSISTANT_GIVES_LAUNCHER_FOCUS", false, 124 "Allow Launcher to handle nav bar gestures while Assistant is running over it"); 125 126 public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = getDebugFlag( 127 "ENABLE_HYBRID_HOTSEAT", true, "Fill gaps in hotseat with predicted apps"); 128 129 public static final BooleanFlag HOTSEAT_MIGRATE_TO_FOLDER = getDebugFlag( 130 "HOTSEAT_MIGRATE_TO_FOLDER", false, "Should move hotseat items into a folder"); 131 132 public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag( 133 "ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache"); 134 135 public static final BooleanFlag MULTI_DB_GRID_MIRATION_ALGO = getDebugFlag( 136 "MULTI_DB_GRID_MIRATION_ALGO", true, "Use the multi-db grid migration algorithm"); 137 138 public static final BooleanFlag ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER = getDebugFlag( 139 "ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true, "Show launcher preview in grid picker"); 140 141 public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag( 142 "ENABLE_OVERVIEW_ACTIONS", true, "Show app actions instead of the shelf in Overview." 143 + " As part of this decoupling, also distinguish swipe up from nav bar vs above it."); 144 145 // Keep as DeviceFlag for remote disable in emergency. 146 public static final BooleanFlag ENABLE_OVERVIEW_SELECTIONS = new DeviceFlag( 147 "ENABLE_OVERVIEW_SELECTIONS", true, "Show Select Mode button in Overview Actions"); 148 149 public static final BooleanFlag ENABLE_OVERVIEW_SHARE = getDebugFlag( 150 "ENABLE_OVERVIEW_SHARE", false, "Show Share button in Overview Actions"); 151 152 public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag( 153 "ENABLE_DATABASE_RESTORE", true, 154 "Enable database restore when new restore session is created"); 155 156 public static final BooleanFlag ENABLE_UNIVERSAL_SMARTSPACE = getDebugFlag( 157 "ENABLE_UNIVERSAL_SMARTSPACE", false, 158 "Replace Smartspace with a version rendered by System UI."); 159 160 public static final BooleanFlag ENABLE_LSQ_VELOCITY_PROVIDER = getDebugFlag( 161 "ENABLE_LSQ_VELOCITY_PROVIDER", true, 162 "Use Least Square algorithm for motion pause detection."); 163 164 public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS = 165 getDebugFlag( 166 "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false, 167 "Always use hardware optimization for folder animations."); 168 169 public static final BooleanFlag ENABLE_ALL_APPS_EDU = getDebugFlag( 170 "ENABLE_ALL_APPS_EDU", true, 171 "Shows user a tutorial on how to get to All Apps after X amount of attempts."); 172 173 public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag( 174 "SEPARATE_RECENTS_ACTIVITY", false, 175 "Uses a separate recents activity instead of using the integrated recents+Launcher UI"); 176 177 public static final BooleanFlag USER_EVENT_DISPATCHER = new DeviceFlag( 178 "USER_EVENT_DISPATCHER", true, "User event dispatcher collects logs."); 179 initialize(Context context)180 public static void initialize(Context context) { 181 synchronized (sDebugFlags) { 182 for (DebugFlag flag : sDebugFlags) { 183 flag.initialize(context); 184 } 185 sDebugFlags.sort((f1, f2) -> f1.key.compareToIgnoreCase(f2.key)); 186 } 187 } 188 getDebugFlags()189 static List<DebugFlag> getDebugFlags() { 190 synchronized (sDebugFlags) { 191 return new ArrayList<>(sDebugFlags); 192 } 193 } 194 dump(PrintWriter pw)195 public static void dump(PrintWriter pw) { 196 pw.println("DeviceFlags:"); 197 synchronized (sDebugFlags) { 198 for (DebugFlag flag : sDebugFlags) { 199 if (flag instanceof DeviceFlag) { 200 pw.println(" " + flag.toString()); 201 } 202 } 203 } 204 pw.println("DebugFlags:"); 205 synchronized (sDebugFlags) { 206 for (DebugFlag flag : sDebugFlags) { 207 if (!(flag instanceof DeviceFlag)) { 208 pw.println(" " + flag.toString()); 209 } 210 } 211 } 212 } 213 214 public static class BooleanFlag { 215 216 public final String key; 217 public boolean defaultValue; 218 BooleanFlag(String key, boolean defaultValue)219 public BooleanFlag(String key, boolean defaultValue) { 220 this.key = key; 221 this.defaultValue = defaultValue; 222 } 223 get()224 public boolean get() { 225 return defaultValue; 226 } 227 228 @Override toString()229 public String toString() { 230 return appendProps(new StringBuilder()).toString(); 231 } 232 appendProps(StringBuilder src)233 protected StringBuilder appendProps(StringBuilder src) { 234 return src.append(key).append(", defaultValue=").append(defaultValue); 235 } 236 addChangeListener(Context context, Runnable r)237 public void addChangeListener(Context context, Runnable r) { } 238 } 239 240 public static class DebugFlag extends BooleanFlag { 241 242 public final String description; 243 private boolean mCurrentValue; 244 DebugFlag(String key, boolean defaultValue, String description)245 public DebugFlag(String key, boolean defaultValue, String description) { 246 super(key, defaultValue); 247 this.description = description; 248 mCurrentValue = this.defaultValue; 249 synchronized (sDebugFlags) { 250 sDebugFlags.add(this); 251 } 252 } 253 254 @Override get()255 public boolean get() { 256 return mCurrentValue; 257 } 258 initialize(Context context)259 public void initialize(Context context) { 260 mCurrentValue = context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE) 261 .getBoolean(key, defaultValue); 262 } 263 264 @Override appendProps(StringBuilder src)265 protected StringBuilder appendProps(StringBuilder src) { 266 return super.appendProps(src).append(", mCurrentValue=").append(mCurrentValue); 267 } 268 } 269 getDebugFlag(String key, boolean defaultValue, String description)270 private static BooleanFlag getDebugFlag(String key, boolean defaultValue, String description) { 271 return Utilities.IS_DEBUG_DEVICE 272 ? new DebugFlag(key, defaultValue, description) 273 : new BooleanFlag(key, defaultValue); 274 } 275 } 276