Loading packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +11 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,11 @@ interface ResourceFlag<T> : Flag<T> { val resourceId: Int } interface SysPropFlag<T> : Flag<T> { val name: String val default: T } // Consider using the "parcelize" kotlin library. data class BooleanFlag @JvmOverloads constructor( Loading Loading @@ -66,6 +71,12 @@ data class ResourceBooleanFlag constructor( @BoolRes override val resourceId: Int ) : ResourceFlag<Boolean> data class SysPropBooleanFlag constructor( override val id: Int, override val name: String, override val default: Boolean = false ) : SysPropFlag<Boolean> data class StringFlag @JvmOverloads constructor( override val id: Int, override val default: String = "" Loading packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt +3 −3 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ class FlagManager constructor( * An action called on restart which takes as an argument whether the listeners requested * that the restart be suppressed */ var restartAction: Consumer<Boolean>? = null var onSettingsChangedAction: Consumer<Boolean>? = null var clearCacheAction: Consumer<Int>? = null private val listeners: MutableSet<PerFlagListener> = mutableSetOf() private val settingsObserver: ContentObserver = SettingsObserver() Loading Loading @@ -154,11 +154,11 @@ class FlagManager constructor( val idStr = parts[parts.size - 1] val id = try { idStr.toInt() } catch (e: NumberFormatException) { return } clearCacheAction?.accept(id) dispatchListenersAndMaybeRestart(id) dispatchListenersAndMaybeRestart(id, onSettingsChangedAction) } } fun dispatchListenersAndMaybeRestart(id: Int) { fun dispatchListenersAndMaybeRestart(id: Int, restartAction: Consumer<Boolean>?) { val filteredListeners: List<FlagListenable.Listener> = synchronized(listeners) { listeners.mapNotNull { if (it.id == id) it.listener else null } } Loading packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt +3 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ interface FeatureFlags : FlagListenable { /** Returns a boolean value for the given flag. */ fun isEnabled(flag: ResourceBooleanFlag): Boolean /** Returns a boolean value for the given flag. */ fun isEnabled(flag: SysPropBooleanFlag): Boolean /** Returns a string value for the given flag. */ fun getString(flag: StringFlag): String Loading packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java +44 −6 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import java.util.ArrayList; import java.util.Map; import java.util.Objects; import java.util.TreeMap; import java.util.function.Consumer; import java.util.function.Supplier; import javax.inject.Inject; Loading @@ -69,6 +70,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { private final FlagManager mFlagManager; private final SecureSettings mSecureSettings; private final Resources mResources; private final SystemPropertiesHelper mSystemProperties; private final Supplier<Map<Integer, Flag<?>>> mFlagsCollector; private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>(); private final Map<Integer, String> mStringFlagCache = new TreeMap<>(); Loading @@ -79,6 +81,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { FlagManager flagManager, Context context, SecureSettings secureSettings, SystemPropertiesHelper systemProperties, @Main Resources resources, DumpManager dumpManager, @Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector, Loading @@ -86,11 +89,12 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { mFlagManager = flagManager; mSecureSettings = secureSettings; mResources = resources; mSystemProperties = systemProperties; mFlagsCollector = flagsCollector != null ? flagsCollector : Flags::collectFlags; IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SET_FLAG); filter.addAction(ACTION_GET_FLAGS); flagManager.setRestartAction(this::restartSystemUI); flagManager.setOnSettingsChangedAction(this::restartSystemUI); flagManager.setClearCacheAction(this::removeFromCache); context.registerReceiver(mReceiver, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED); Loading Loading @@ -121,6 +125,17 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { return mBooleanFlagCache.get(id); } @Override public boolean isEnabled(@NonNull SysPropBooleanFlag flag) { int id = flag.getId(); if (!mBooleanFlagCache.containsKey(id)) { mBooleanFlagCache.put( id, mSystemProperties.getBoolean(flag.getName(), flag.getDefault())); } return mBooleanFlagCache.get(id); } @NonNull @Override public String getString(@NonNull StringFlag flag) { Loading Loading @@ -180,16 +195,28 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { mSecureSettings.putString(mFlagManager.idToSettingsKey(id), data); Log.i(TAG, "Set id " + id + " to " + value); removeFromCache(id); mFlagManager.dispatchListenersAndMaybeRestart(id); mFlagManager.dispatchListenersAndMaybeRestart(id, this::restartSystemUI); } private <T> void eraseFlag(Flag<T> flag) { if (flag instanceof SysPropFlag) { mSystemProperties.erase(((SysPropFlag<T>) flag).getName()); dispatchListenersAndMaybeRestart(flag.getId(), this::restartAndroid); } else { eraseFlag(flag.getId()); } } /** Erase a flag's overridden value if there is one. */ public void eraseFlag(int id) { private void eraseFlag(int id) { eraseInternal(id); removeFromCache(id); mFlagManager.dispatchListenersAndMaybeRestart(id); dispatchListenersAndMaybeRestart(id, this::restartSystemUI); } private void dispatchListenersAndMaybeRestart(int id, Consumer<Boolean> restartAction) { mFlagManager.dispatchListenersAndMaybeRestart(id, restartAction); } /** Works just like {@link #eraseFlag(int)} except that it doesn't restart SystemUI. */ private void eraseInternal(int id) { // We can't actually "erase" things from sysprops, but we can set them to empty! Loading Loading @@ -217,7 +244,11 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { System.exit(0); } private void restartAndroid() { private void restartAndroid(boolean requestSuppress) { if (requestSuppress) { Log.i(TAG, "Android Restart Suppressed"); return; } Log.i(TAG, "Restarting Android"); try { mBarService.restart(); Loading Loading @@ -273,7 +304,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { Flag<?> flag = flagMap.get(id); if (!extras.containsKey(EXTRA_VALUE)) { eraseFlag(id); eraseFlag(flag); return; } Loading @@ -282,6 +313,10 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE); } else if (flag instanceof ResourceBooleanFlag && value instanceof Boolean) { setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE); } else if (flag instanceof SysPropBooleanFlag && value instanceof Boolean) { // Store SysProp flags in SystemProperties where they can read by outside parties. mSystemProperties.setBoolean( ((SysPropBooleanFlag) flag).getName(), (Boolean) value); } else if (flag instanceof StringFlag && value instanceof String) { setFlagValue(id, (String) value, StringFlagSerializer.INSTANCE); } else if (flag instanceof ResourceStringFlag && value instanceof String) { Loading @@ -306,6 +341,9 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { if (f instanceof ResourceBooleanFlag) { return new BooleanFlag(f.getId(), isEnabled((ResourceBooleanFlag) f)); } if (f instanceof SysPropBooleanFlag) { return new BooleanFlag(f.getId(), isEnabled((SysPropBooleanFlag) f)); } // TODO: add support for other flag types. Log.w(TAG, "Unsupported Flag Type. Please file a bug."); Loading packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java +18 −1 Original line number Diff line number Diff line Loading @@ -43,11 +43,17 @@ import javax.inject.Inject; @SysUISingleton public class FeatureFlagsRelease implements FeatureFlags, Dumpable { private final Resources mResources; private final SystemPropertiesHelper mSystemProperties; SparseBooleanArray mBooleanCache = new SparseBooleanArray(); SparseArray<String> mStringCache = new SparseArray<>(); @Inject public FeatureFlagsRelease(@Main Resources resources, DumpManager dumpManager) { public FeatureFlagsRelease( @Main Resources resources, SystemPropertiesHelper systemProperties, DumpManager dumpManager) { mResources = resources; mSystemProperties = systemProperties; dumpManager.registerDumpable("SysUIFlags", this); } Loading @@ -72,6 +78,17 @@ public class FeatureFlagsRelease implements FeatureFlags, Dumpable { return mBooleanCache.valueAt(cacheIndex); } @Override public boolean isEnabled(SysPropBooleanFlag flag) { int cacheIndex = mBooleanCache.indexOfKey(flag.getId()); if (cacheIndex < 0) { return isEnabled( flag.getId(), mSystemProperties.getBoolean(flag.getName(), flag.getDefault())); } return mBooleanCache.valueAt(cacheIndex); } private boolean isEnabled(int key, boolean defaultValue) { mBooleanCache.append(key, defaultValue); return defaultValue; Loading Loading
packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +11 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,11 @@ interface ResourceFlag<T> : Flag<T> { val resourceId: Int } interface SysPropFlag<T> : Flag<T> { val name: String val default: T } // Consider using the "parcelize" kotlin library. data class BooleanFlag @JvmOverloads constructor( Loading Loading @@ -66,6 +71,12 @@ data class ResourceBooleanFlag constructor( @BoolRes override val resourceId: Int ) : ResourceFlag<Boolean> data class SysPropBooleanFlag constructor( override val id: Int, override val name: String, override val default: Boolean = false ) : SysPropFlag<Boolean> data class StringFlag @JvmOverloads constructor( override val id: Int, override val default: String = "" Loading
packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt +3 −3 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ class FlagManager constructor( * An action called on restart which takes as an argument whether the listeners requested * that the restart be suppressed */ var restartAction: Consumer<Boolean>? = null var onSettingsChangedAction: Consumer<Boolean>? = null var clearCacheAction: Consumer<Int>? = null private val listeners: MutableSet<PerFlagListener> = mutableSetOf() private val settingsObserver: ContentObserver = SettingsObserver() Loading Loading @@ -154,11 +154,11 @@ class FlagManager constructor( val idStr = parts[parts.size - 1] val id = try { idStr.toInt() } catch (e: NumberFormatException) { return } clearCacheAction?.accept(id) dispatchListenersAndMaybeRestart(id) dispatchListenersAndMaybeRestart(id, onSettingsChangedAction) } } fun dispatchListenersAndMaybeRestart(id: Int) { fun dispatchListenersAndMaybeRestart(id: Int, restartAction: Consumer<Boolean>?) { val filteredListeners: List<FlagListenable.Listener> = synchronized(listeners) { listeners.mapNotNull { if (it.id == id) it.listener else null } } Loading
packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt +3 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ interface FeatureFlags : FlagListenable { /** Returns a boolean value for the given flag. */ fun isEnabled(flag: ResourceBooleanFlag): Boolean /** Returns a boolean value for the given flag. */ fun isEnabled(flag: SysPropBooleanFlag): Boolean /** Returns a string value for the given flag. */ fun getString(flag: StringFlag): String Loading
packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java +44 −6 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import java.util.ArrayList; import java.util.Map; import java.util.Objects; import java.util.TreeMap; import java.util.function.Consumer; import java.util.function.Supplier; import javax.inject.Inject; Loading @@ -69,6 +70,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { private final FlagManager mFlagManager; private final SecureSettings mSecureSettings; private final Resources mResources; private final SystemPropertiesHelper mSystemProperties; private final Supplier<Map<Integer, Flag<?>>> mFlagsCollector; private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>(); private final Map<Integer, String> mStringFlagCache = new TreeMap<>(); Loading @@ -79,6 +81,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { FlagManager flagManager, Context context, SecureSettings secureSettings, SystemPropertiesHelper systemProperties, @Main Resources resources, DumpManager dumpManager, @Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector, Loading @@ -86,11 +89,12 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { mFlagManager = flagManager; mSecureSettings = secureSettings; mResources = resources; mSystemProperties = systemProperties; mFlagsCollector = flagsCollector != null ? flagsCollector : Flags::collectFlags; IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SET_FLAG); filter.addAction(ACTION_GET_FLAGS); flagManager.setRestartAction(this::restartSystemUI); flagManager.setOnSettingsChangedAction(this::restartSystemUI); flagManager.setClearCacheAction(this::removeFromCache); context.registerReceiver(mReceiver, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED); Loading Loading @@ -121,6 +125,17 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { return mBooleanFlagCache.get(id); } @Override public boolean isEnabled(@NonNull SysPropBooleanFlag flag) { int id = flag.getId(); if (!mBooleanFlagCache.containsKey(id)) { mBooleanFlagCache.put( id, mSystemProperties.getBoolean(flag.getName(), flag.getDefault())); } return mBooleanFlagCache.get(id); } @NonNull @Override public String getString(@NonNull StringFlag flag) { Loading Loading @@ -180,16 +195,28 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { mSecureSettings.putString(mFlagManager.idToSettingsKey(id), data); Log.i(TAG, "Set id " + id + " to " + value); removeFromCache(id); mFlagManager.dispatchListenersAndMaybeRestart(id); mFlagManager.dispatchListenersAndMaybeRestart(id, this::restartSystemUI); } private <T> void eraseFlag(Flag<T> flag) { if (flag instanceof SysPropFlag) { mSystemProperties.erase(((SysPropFlag<T>) flag).getName()); dispatchListenersAndMaybeRestart(flag.getId(), this::restartAndroid); } else { eraseFlag(flag.getId()); } } /** Erase a flag's overridden value if there is one. */ public void eraseFlag(int id) { private void eraseFlag(int id) { eraseInternal(id); removeFromCache(id); mFlagManager.dispatchListenersAndMaybeRestart(id); dispatchListenersAndMaybeRestart(id, this::restartSystemUI); } private void dispatchListenersAndMaybeRestart(int id, Consumer<Boolean> restartAction) { mFlagManager.dispatchListenersAndMaybeRestart(id, restartAction); } /** Works just like {@link #eraseFlag(int)} except that it doesn't restart SystemUI. */ private void eraseInternal(int id) { // We can't actually "erase" things from sysprops, but we can set them to empty! Loading Loading @@ -217,7 +244,11 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { System.exit(0); } private void restartAndroid() { private void restartAndroid(boolean requestSuppress) { if (requestSuppress) { Log.i(TAG, "Android Restart Suppressed"); return; } Log.i(TAG, "Restarting Android"); try { mBarService.restart(); Loading Loading @@ -273,7 +304,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { Flag<?> flag = flagMap.get(id); if (!extras.containsKey(EXTRA_VALUE)) { eraseFlag(id); eraseFlag(flag); return; } Loading @@ -282,6 +313,10 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE); } else if (flag instanceof ResourceBooleanFlag && value instanceof Boolean) { setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE); } else if (flag instanceof SysPropBooleanFlag && value instanceof Boolean) { // Store SysProp flags in SystemProperties where they can read by outside parties. mSystemProperties.setBoolean( ((SysPropBooleanFlag) flag).getName(), (Boolean) value); } else if (flag instanceof StringFlag && value instanceof String) { setFlagValue(id, (String) value, StringFlagSerializer.INSTANCE); } else if (flag instanceof ResourceStringFlag && value instanceof String) { Loading @@ -306,6 +341,9 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable { if (f instanceof ResourceBooleanFlag) { return new BooleanFlag(f.getId(), isEnabled((ResourceBooleanFlag) f)); } if (f instanceof SysPropBooleanFlag) { return new BooleanFlag(f.getId(), isEnabled((SysPropBooleanFlag) f)); } // TODO: add support for other flag types. Log.w(TAG, "Unsupported Flag Type. Please file a bug."); Loading
packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java +18 −1 Original line number Diff line number Diff line Loading @@ -43,11 +43,17 @@ import javax.inject.Inject; @SysUISingleton public class FeatureFlagsRelease implements FeatureFlags, Dumpable { private final Resources mResources; private final SystemPropertiesHelper mSystemProperties; SparseBooleanArray mBooleanCache = new SparseBooleanArray(); SparseArray<String> mStringCache = new SparseArray<>(); @Inject public FeatureFlagsRelease(@Main Resources resources, DumpManager dumpManager) { public FeatureFlagsRelease( @Main Resources resources, SystemPropertiesHelper systemProperties, DumpManager dumpManager) { mResources = resources; mSystemProperties = systemProperties; dumpManager.registerDumpable("SysUIFlags", this); } Loading @@ -72,6 +78,17 @@ public class FeatureFlagsRelease implements FeatureFlags, Dumpable { return mBooleanCache.valueAt(cacheIndex); } @Override public boolean isEnabled(SysPropBooleanFlag flag) { int cacheIndex = mBooleanCache.indexOfKey(flag.getId()); if (cacheIndex < 0) { return isEnabled( flag.getId(), mSystemProperties.getBoolean(flag.getName(), flag.getDefault())); } return mBooleanCache.valueAt(cacheIndex); } private boolean isEnabled(int key, boolean defaultValue) { mBooleanCache.append(key, defaultValue); return defaultValue; Loading