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 android.util; 18 19 import android.annotation.TestApi; 20 import android.content.Context; 21 import android.os.SystemProperties; 22 import android.provider.Settings; 23 import android.text.TextUtils; 24 25 import java.util.HashMap; 26 import java.util.HashSet; 27 import java.util.Map; 28 import java.util.Set; 29 30 /** 31 * Util class to get feature flag information. 32 * 33 * @hide 34 */ 35 @TestApi 36 public class FeatureFlagUtils { 37 38 public static final String FFLAG_PREFIX = "sys.fflag."; 39 public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override."; 40 public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX; 41 public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; 42 public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2"; 43 /** @hide */ 44 public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED = 45 "settings_do_not_restore_preserved"; 46 /** @hide */ 47 public static final String SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES 48 = "settings_use_new_backup_eligibility_rules"; 49 /** @hide */ 50 public static final String SETTINGS_ENABLE_SECURITY_HUB = "settings_enable_security_hub"; 51 /** @hide */ 52 public static final String SETTINGS_SUPPORT_LARGE_SCREEN = "settings_support_large_screen"; 53 54 /** 55 * Support locale opt-out and opt-in switch for per app's language. 56 * @hide 57 */ 58 public static final String SETTINGS_APP_LOCALE_OPT_IN_ENABLED = 59 "settings_app_locale_opt_in_enabled"; 60 61 /** 62 * Launch the Volume panel in SystemUI. 63 * @hide 64 */ 65 public static final String SETTINGS_VOLUME_PANEL_IN_SYSTEMUI = 66 "settings_volume_panel_in_systemui"; 67 68 /** @hide */ 69 public static final String SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS = 70 "settings_enable_monitor_phantom_procs"; 71 72 /** 73 * Support dark theme activation at Bedtime. 74 * @hide 75 */ 76 public static final String SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME = 77 "settings_app_allow_dark_theme_activation_at_bedtime"; 78 79 /** 80 * Flag to decouple bluetooth LE Audio Broadcast from Unicast 81 * If the flag is true, the broadcast feature will be enabled when the phone 82 * is connected to the BLE device. 83 * If the flag is false, it is not necessary to connect the BLE device. 84 * @hide 85 */ 86 public static final String SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST = 87 "settings_need_connected_ble_device_for_broadcast"; 88 89 /** 90 * Enable new language and keyboard settings UI 91 * @hide 92 */ 93 public static final String SETTINGS_NEW_KEYBOARD_UI = "settings_new_keyboard_ui"; 94 95 /** 96 * Enable new modifier key settings UI 97 * @hide 98 */ 99 public static final String SETTINGS_NEW_KEYBOARD_MODIFIER_KEY = 100 "settings_new_keyboard_modifier_key"; 101 102 /** 103 * Enable new trackpad settings UI 104 * @hide 105 */ 106 public static final String SETTINGS_NEW_KEYBOARD_TRACKPAD = "settings_new_keyboard_trackpad"; 107 108 /** 109 * Enable trackpad gesture settings UI 110 * @hide 111 */ 112 public static final String SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE = 113 "settings_new_keyboard_trackpad_gesture"; 114 115 /** 116 * Enable the new pages which is implemented with SPA. 117 * @hide 118 */ 119 public static final String SETTINGS_ENABLE_SPA = "settings_enable_spa"; 120 121 /** 122 * Enable new pages implemented with SPA besides the SPA pages controlled by the {@code 123 * settings_enable_spa} flag. 124 * @hide 125 */ 126 public static final String SETTINGS_ENABLE_SPA_PHASE2 = "settings_enable_spa_phase2"; 127 128 /** 129 * Enable the SPA metrics writing. 130 * @hide 131 */ 132 public static final String SETTINGS_ENABLE_SPA_METRICS = "settings_enable_spa_metrics"; 133 134 /** Flag to enable/disable adb log metrics 135 * @hide 136 */ 137 public static final String SETTINGS_ADB_METRICS_WRITER = "settings_adb_metrics_writer"; 138 139 /** 140 * Flag to show stylus-specific preferences in Connected Devices 141 * @hide 142 */ 143 public static final String SETTINGS_SHOW_STYLUS_PREFERENCES = 144 "settings_show_stylus_preferences"; 145 146 /** 147 * Flag to enable/disable biometrics enrollment v2 148 * @hide 149 */ 150 public static final String SETTINGS_BIOMETRICS2_ENROLLMENT = "settings_biometrics2_enrollment"; 151 152 /** 153 * Flag to enable/disable FingerprintSettings v2 154 * @hide 155 */ 156 public static final String SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS = 157 "settings_biometrics2_fingerprint"; 158 159 /** Flag to enable/disable entire page in Accessibility -> Hearing aids 160 * @hide 161 */ 162 public static final String SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE = 163 "settings_accessibility_hearing_aid_page"; 164 165 /** 166 * Flag to enable/disable preferring the AccessibilityMenu service in the system. 167 * @hide 168 */ 169 public static final String SETTINGS_PREFER_ACCESSIBILITY_MENU_IN_SYSTEM = 170 "settings_prefer_accessibility_menu_in_system"; 171 172 /** Flag to enable/disable audio routing change 173 * @hide 174 */ 175 public static final String SETTINGS_AUDIO_ROUTING = "settings_audio_routing"; 176 177 /** Flag to enable/disable flash notifications 178 * @hide 179 */ 180 public static final String SETTINGS_FLASH_NOTIFICATIONS = "settings_flash_notifications"; 181 182 /** 183 * Flag to disable/enable showing udfps enroll view in settings. If it's disabled, udfps enroll 184 * view is shown in system ui. 185 * @hide 186 */ 187 public static final String SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS = 188 "settings_show_udfps_enroll_in_settings"; 189 190 /** 191 * Flag to enable lock screen credentials transfer API in Android U. 192 * @hide 193 */ 194 public static final String SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API = 195 "settings_enable_lockscreen_transfer_api"; 196 197 /** 198 * Flag to enable remote device credential validation 199 * @hide 200 */ 201 public static final String SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION = 202 "settings_remote_device_credential_validation"; 203 204 205 private static final Map<String, String> DEFAULT_FLAGS; 206 207 static { 208 DEFAULT_FLAGS = new HashMap<>(); 209 DEFAULT_FLAGS.put("settings_audio_switcher", "true"); 210 DEFAULT_FLAGS.put("settings_systemui_theme", "true"); DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false")211 DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false"); 212 DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false"); 213 DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true"); DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "true")214 DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "true"); 215 DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "true"); 216 DEFAULT_FLAGS.put("settings_conditionals", "false"); 217 // This flags guards a feature introduced in R and will be removed in the next release 218 // (b/148367230). DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true")219 DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true"); 220 221 DEFAULT_FLAGS.put("settings_tether_all_in_one", "false"); 222 DEFAULT_FLAGS.put("settings_contextual_home", "false"); DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "true")223 DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true")224 DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true"); DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true")225 DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true"); 226 DEFAULT_FLAGS.put("settings_search_always_expand", "true"); DEFAULT_FLAGS.put(SETTINGS_APP_LOCALE_OPT_IN_ENABLED, "true")227 DEFAULT_FLAGS.put(SETTINGS_APP_LOCALE_OPT_IN_ENABLED, "true"); DEFAULT_FLAGS.put(SETTINGS_VOLUME_PANEL_IN_SYSTEMUI, "false")228 DEFAULT_FLAGS.put(SETTINGS_VOLUME_PANEL_IN_SYSTEMUI, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true")229 DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true"); DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true")230 DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true"); DEFAULT_FLAGS.put(SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, "true")231 DEFAULT_FLAGS.put(SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, "true"); DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "true")232 DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "true"); DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "true")233 DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "true"); DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "true")234 DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "true"); DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE, "false")235 DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "true")236 DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA_PHASE2, "false")237 DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA_PHASE2, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA_METRICS, "false")238 DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA_METRICS, "false"); DEFAULT_FLAGS.put(SETTINGS_ADB_METRICS_WRITER, "false")239 DEFAULT_FLAGS.put(SETTINGS_ADB_METRICS_WRITER, "false"); DEFAULT_FLAGS.put(SETTINGS_SHOW_STYLUS_PREFERENCES, "true")240 DEFAULT_FLAGS.put(SETTINGS_SHOW_STYLUS_PREFERENCES, "true"); DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_ENROLLMENT, "false")241 DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_ENROLLMENT, "false"); DEFAULT_FLAGS.put(SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE, "true")242 DEFAULT_FLAGS.put(SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE, "true"); DEFAULT_FLAGS.put(SETTINGS_PREFER_ACCESSIBILITY_MENU_IN_SYSTEM, "false")243 DEFAULT_FLAGS.put(SETTINGS_PREFER_ACCESSIBILITY_MENU_IN_SYSTEM, "false"); DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "false")244 DEFAULT_FLAGS.put(SETTINGS_AUDIO_ROUTING, "false"); DEFAULT_FLAGS.put(SETTINGS_FLASH_NOTIFICATIONS, "true")245 DEFAULT_FLAGS.put(SETTINGS_FLASH_NOTIFICATIONS, "true"); DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "true")246 DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "true")247 DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "true"); DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "true")248 DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "true"); DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS, "false")249 DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS, "false"); 250 } 251 252 private static final Set<String> PERSISTENT_FLAGS; 253 254 static { 255 PERSISTENT_FLAGS = new HashSet<>(); 256 PERSISTENT_FLAGS.add(SETTINGS_APP_LOCALE_OPT_IN_ENABLED); 257 PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN); 258 PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS); 259 PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME); 260 PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_UI); 261 PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY); 262 PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD); 263 PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE); 264 PERSISTENT_FLAGS.add(SETTINGS_ENABLE_SPA); 265 PERSISTENT_FLAGS.add(SETTINGS_ENABLE_SPA_PHASE2); 266 PERSISTENT_FLAGS.add(SETTINGS_PREFER_ACCESSIBILITY_MENU_IN_SYSTEM); 267 } 268 269 /** 270 * Whether or not a flag is enabled. 271 * 272 * @param feature the flag name 273 * @return true if the flag is enabled (either by default in system, or override by user) 274 */ isEnabled(Context context, String feature)275 public static boolean isEnabled(Context context, String feature) { 276 // Override precedence: 277 // Settings.Global -> sys.fflag.override.* -> static list 278 279 // Step 1: check if feature flag is set in Settings.Global. 280 String value; 281 if (context != null) { 282 value = Settings.Global.getString(context.getContentResolver(), feature); 283 if (!TextUtils.isEmpty(value)) { 284 return Boolean.parseBoolean(value); 285 } 286 } 287 288 // Step 2: check if feature flag has any override. 289 // Flag name: [persist.]sys.fflag.override.<feature> 290 value = SystemProperties.get(getSystemPropertyPrefix(feature) + feature); 291 if (!TextUtils.isEmpty(value)) { 292 return Boolean.parseBoolean(value); 293 } 294 // Step 3: check if feature flag has any default value. 295 value = getAllFeatureFlags().get(feature); 296 return Boolean.parseBoolean(value); 297 } 298 299 /** 300 * Override feature flag to new state. 301 */ setEnabled(Context context, String feature, boolean enabled)302 public static void setEnabled(Context context, String feature, boolean enabled) { 303 SystemProperties.set(getSystemPropertyPrefix(feature) + feature, 304 enabled ? "true" : "false"); 305 } 306 307 /** 308 * Returns all feature flags in their raw form. 309 */ getAllFeatureFlags()310 public static Map<String, String> getAllFeatureFlags() { 311 return DEFAULT_FLAGS; 312 } 313 getSystemPropertyPrefix(String feature)314 private static String getSystemPropertyPrefix(String feature) { 315 return PERSISTENT_FLAGS.contains(feature) ? PERSIST_PREFIX : FFLAG_OVERRIDE_PREFIX; 316 } 317 } 318