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 * Hide back key in the Settings two pane design. 81 * @hide 82 */ 83 public static final String SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE = 84 "settings_hide_second_layer_page_navigate_up_button_in_two_pane"; 85 86 private static final Map<String, String> DEFAULT_FLAGS; 87 88 static { 89 DEFAULT_FLAGS = new HashMap<>(); 90 DEFAULT_FLAGS.put("settings_audio_switcher", "true"); 91 DEFAULT_FLAGS.put("settings_systemui_theme", "true"); DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false")92 DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false"); 93 DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false"); 94 DEFAULT_FLAGS.put("settings_skip_direction_mutable", "true"); DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "true")95 DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "true"); 96 DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "true"); 97 DEFAULT_FLAGS.put("settings_conditionals", "false"); 98 // This flags guards a feature introduced in R and will be removed in the next release 99 // (b/148367230). DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true")100 DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true"); 101 102 DEFAULT_FLAGS.put("settings_tether_all_in_one", "false"); 103 DEFAULT_FLAGS.put("settings_contextual_home", "false"); DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "true")104 DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true")105 DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true"); DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true")106 DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true"); 107 DEFAULT_FLAGS.put("settings_search_always_expand", "true"); DEFAULT_FLAGS.put(SETTINGS_APP_LOCALE_OPT_IN_ENABLED, "true")108 DEFAULT_FLAGS.put(SETTINGS_APP_LOCALE_OPT_IN_ENABLED, "true"); DEFAULT_FLAGS.put(SETTINGS_VOLUME_PANEL_IN_SYSTEMUI, "false")109 DEFAULT_FLAGS.put(SETTINGS_VOLUME_PANEL_IN_SYSTEMUI, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true")110 DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true"); DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true")111 DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true"); DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true")112 DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true"); 113 } 114 115 private static final Set<String> PERSISTENT_FLAGS; 116 static { 117 PERSISTENT_FLAGS = new HashSet<>(); 118 PERSISTENT_FLAGS.add(SETTINGS_APP_LOCALE_OPT_IN_ENABLED); 119 PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN); 120 PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS); 121 PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME); 122 PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE); 123 } 124 125 /** 126 * Whether or not a flag is enabled. 127 * 128 * @param feature the flag name 129 * @return true if the flag is enabled (either by default in system, or override by user) 130 */ isEnabled(Context context, String feature)131 public static boolean isEnabled(Context context, String feature) { 132 // Override precedence: 133 // Settings.Global -> sys.fflag.override.* -> static list 134 135 // Step 1: check if feature flag is set in Settings.Global. 136 String value; 137 if (context != null) { 138 value = Settings.Global.getString(context.getContentResolver(), feature); 139 if (!TextUtils.isEmpty(value)) { 140 return Boolean.parseBoolean(value); 141 } 142 } 143 144 // Step 2: check if feature flag has any override. 145 // Flag name: [persist.]sys.fflag.override.<feature> 146 value = SystemProperties.get(getSystemPropertyPrefix(feature) + feature); 147 if (!TextUtils.isEmpty(value)) { 148 return Boolean.parseBoolean(value); 149 } 150 // Step 3: check if feature flag has any default value. 151 value = getAllFeatureFlags().get(feature); 152 return Boolean.parseBoolean(value); 153 } 154 155 /** 156 * Override feature flag to new state. 157 */ setEnabled(Context context, String feature, boolean enabled)158 public static void setEnabled(Context context, String feature, boolean enabled) { 159 SystemProperties.set(getSystemPropertyPrefix(feature) + feature, 160 enabled ? "true" : "false"); 161 } 162 163 /** 164 * Returns all feature flags in their raw form. 165 */ getAllFeatureFlags()166 public static Map<String, String> getAllFeatureFlags() { 167 return DEFAULT_FLAGS; 168 } 169 getSystemPropertyPrefix(String feature)170 private static String getSystemPropertyPrefix(String feature) { 171 return PERSISTENT_FLAGS.contains(feature) ? PERSIST_PREFIX : FFLAG_OVERRIDE_PREFIX; 172 } 173 } 174