Merge "Step 1 of Removing Ids from Flags." into tm-qpr-dev am: b21f162dfe

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20960887

Change-Id: I25b17c22c2a83e67d3365ee5837f35460707bc14
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Dave Mankoff
2023-01-30 18:48:00 +00:00
committed by Automerger Merge Worker
18 changed files with 395 additions and 360 deletions

View File

@@ -47,10 +47,6 @@ interface ResourceFlag<T> : Flag<T> {
val resourceId: Int val resourceId: Int
} }
interface DeviceConfigFlag<T> : Flag<T> {
val default: T
}
interface SysPropFlag<T> : Flag<T> { interface SysPropFlag<T> : Flag<T> {
val default: T val default: T
} }
@@ -80,8 +76,8 @@ abstract class BooleanFlag constructor(
private constructor(parcel: Parcel) : this( private constructor(parcel: Parcel) : this(
id = parcel.readInt(), id = parcel.readInt(),
name = parcel.readString(), name = parcel.readString() ?: "",
namespace = parcel.readString(), namespace = parcel.readString() ?: "",
default = parcel.readBoolean(), default = parcel.readBoolean(),
teamfood = parcel.readBoolean(), teamfood = parcel.readBoolean(),
overridden = parcel.readBoolean() overridden = parcel.readBoolean()
@@ -136,21 +132,6 @@ data class ResourceBooleanFlag constructor(
override val teamfood: Boolean = false override val teamfood: Boolean = false
) : ResourceFlag<Boolean> ) : ResourceFlag<Boolean>
/**
* A Flag that can reads its overrides from DeviceConfig.
*
* This is generally useful for flags that come from or are used _outside_ of SystemUI.
*
* Prefer [UnreleasedFlag] and [ReleasedFlag].
*/
data class DeviceConfigBooleanFlag constructor(
override val id: Int,
override val name: String,
override val namespace: String,
override val default: Boolean = false,
override val teamfood: Boolean = false
) : DeviceConfigFlag<Boolean>
/** /**
* A Flag that can reads its overrides from System Properties. * A Flag that can reads its overrides from System Properties.
* *
@@ -186,8 +167,8 @@ data class StringFlag constructor(
private constructor(parcel: Parcel) : this( private constructor(parcel: Parcel) : this(
id = parcel.readInt(), id = parcel.readInt(),
name = parcel.readString(), name = parcel.readString() ?: "",
namespace = parcel.readString(), namespace = parcel.readString() ?: "",
default = parcel.readString() ?: "" default = parcel.readString() ?: ""
) )
@@ -226,8 +207,8 @@ data class IntFlag constructor(
private constructor(parcel: Parcel) : this( private constructor(parcel: Parcel) : this(
id = parcel.readInt(), id = parcel.readInt(),
name = parcel.readString(), name = parcel.readString() ?: "",
namespace = parcel.readString(), namespace = parcel.readString() ?: "",
default = parcel.readInt() default = parcel.readInt()
) )
@@ -266,8 +247,8 @@ data class LongFlag constructor(
private constructor(parcel: Parcel) : this( private constructor(parcel: Parcel) : this(
id = parcel.readInt(), id = parcel.readInt(),
name = parcel.readString(), name = parcel.readString() ?: "",
namespace = parcel.readString(), namespace = parcel.readString() ?: "",
default = parcel.readLong() default = parcel.readLong()
) )
@@ -298,8 +279,8 @@ data class FloatFlag constructor(
private constructor(parcel: Parcel) : this( private constructor(parcel: Parcel) : this(
id = parcel.readInt(), id = parcel.readInt(),
name = parcel.readString(), name = parcel.readString() ?: "",
namespace = parcel.readString(), namespace = parcel.readString() ?: "",
default = parcel.readFloat() default = parcel.readFloat()
) )
@@ -338,8 +319,8 @@ data class DoubleFlag constructor(
private constructor(parcel: Parcel) : this( private constructor(parcel: Parcel) : this(
id = parcel.readInt(), id = parcel.readInt(),
name = parcel.readString(), name = parcel.readString() ?: "",
namespace = parcel.readString(), namespace = parcel.readString() ?: "",
default = parcel.readDouble() default = parcel.readDouble()
) )

View File

@@ -34,7 +34,7 @@ interface FlagListenable {
/** An event representing the change */ /** An event representing the change */
interface FlagEvent { interface FlagEvent {
/** the id of the flag which changed */ /** the id of the flag which changed */
val flagId: Int val flagName: String
/** if all listeners alerted invoke this method, the restart will be skipped */ /** if all listeners alerted invoke this method, the restart will be skipped */
fun requestNoRestart() fun requestNoRestart()
} }

View File

@@ -39,7 +39,7 @@ class FlagManager constructor(
const val ACTION_GET_FLAGS = "com.android.systemui.action.GET_FLAGS" const val ACTION_GET_FLAGS = "com.android.systemui.action.GET_FLAGS"
const val FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS" const val FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS"
const val ACTION_SYSUI_STARTED = "com.android.systemui.STARTED" const val ACTION_SYSUI_STARTED = "com.android.systemui.STARTED"
const val EXTRA_ID = "id" const val EXTRA_NAME = "name"
const val EXTRA_VALUE = "value" const val EXTRA_VALUE = "value"
const val EXTRA_FLAGS = "flags" const val EXTRA_FLAGS = "flags"
private const val SETTINGS_PREFIX = "systemui/flags" private const val SETTINGS_PREFIX = "systemui/flags"
@@ -56,7 +56,7 @@ class FlagManager constructor(
* that the restart be suppressed * that the restart be suppressed
*/ */
var onSettingsChangedAction: Consumer<Boolean>? = null var onSettingsChangedAction: Consumer<Boolean>? = null
var clearCacheAction: Consumer<Int>? = null var clearCacheAction: Consumer<String>? = null
private val listeners: MutableSet<PerFlagListener> = mutableSetOf() private val listeners: MutableSet<PerFlagListener> = mutableSetOf()
private val settingsObserver: ContentObserver = SettingsObserver() private val settingsObserver: ContentObserver = SettingsObserver()
@@ -96,35 +96,42 @@ class FlagManager constructor(
* Returns the stored value or null if not set. * Returns the stored value or null if not set.
* This API is used by TheFlippinApp. * This API is used by TheFlippinApp.
*/ */
fun isEnabled(id: Int): Boolean? = readFlagValue(id, BooleanFlagSerializer) fun isEnabled(name: String): Boolean? = readFlagValue(name, BooleanFlagSerializer)
/** /**
* Sets the value of a boolean flag. * Sets the value of a boolean flag.
* This API is used by TheFlippinApp. * This API is used by TheFlippinApp.
*/ */
fun setFlagValue(id: Int, enabled: Boolean) { fun setFlagValue(name: String, enabled: Boolean) {
val intent = createIntent(id) val intent = createIntent(name)
intent.putExtra(EXTRA_VALUE, enabled) intent.putExtra(EXTRA_VALUE, enabled)
context.sendBroadcast(intent) context.sendBroadcast(intent)
} }
fun eraseFlag(id: Int) { fun eraseFlag(name: String) {
val intent = createIntent(id) val intent = createIntent(name)
context.sendBroadcast(intent) context.sendBroadcast(intent)
} }
/** Returns the stored value or null if not set. */ /** Returns the stored value or null if not set. */
// TODO(b/265188950): Remove method this once ids are fully deprecated.
fun <T> readFlagValue(id: Int, serializer: FlagSerializer<T>): T? { fun <T> readFlagValue(id: Int, serializer: FlagSerializer<T>): T? {
val data = settings.getString(idToSettingsKey(id)) val data = settings.getStringFromSecure(idToSettingsKey(id))
return serializer.fromSettingsData(data)
}
/** Returns the stored value or null if not set. */
fun <T> readFlagValue(name: String, serializer: FlagSerializer<T>): T? {
val data = settings.getString(nameToSettingsKey(name))
return serializer.fromSettingsData(data) return serializer.fromSettingsData(data)
} }
override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) { override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {
synchronized(listeners) { synchronized(listeners) {
val registerNeeded = listeners.isEmpty() val registerNeeded = listeners.isEmpty()
listeners.add(PerFlagListener(flag.id, listener)) listeners.add(PerFlagListener(flag.name, listener))
if (registerNeeded) { if (registerNeeded) {
settings.registerContentObserver(SETTINGS_PREFIX, true, settingsObserver) settings.registerContentObserver(SETTINGS_PREFIX, true, settingsObserver)
} }
@@ -143,38 +150,38 @@ class FlagManager constructor(
} }
} }
private fun createIntent(id: Int): Intent { private fun createIntent(name: String): Intent {
val intent = Intent(ACTION_SET_FLAG) val intent = Intent(ACTION_SET_FLAG)
intent.setPackage(RECEIVING_PACKAGE) intent.setPackage(RECEIVING_PACKAGE)
intent.putExtra(EXTRA_ID, id) intent.putExtra(EXTRA_NAME, name)
return intent return intent
} }
// TODO(b/265188950): Remove method this once ids are fully deprecated.
fun idToSettingsKey(id: Int): String { fun idToSettingsKey(id: Int): String {
return "$SETTINGS_PREFIX/$id" return "$SETTINGS_PREFIX/$id"
} }
fun nameToSettingsKey(name: String): String {
return "$SETTINGS_PREFIX/$name"
}
inner class SettingsObserver : ContentObserver(handler) { inner class SettingsObserver : ContentObserver(handler) {
override fun onChange(selfChange: Boolean, uri: Uri?) { override fun onChange(selfChange: Boolean, uri: Uri?) {
if (uri == null) { if (uri == null) {
return return
} }
val parts = uri.pathSegments val parts = uri.pathSegments
val idStr = parts[parts.size - 1] val name = parts[parts.size - 1]
val id = try { clearCacheAction?.accept(name)
idStr.toInt() dispatchListenersAndMaybeRestart(name, onSettingsChangedAction)
} catch (e: NumberFormatException) {
return
}
clearCacheAction?.accept(id)
dispatchListenersAndMaybeRestart(id, onSettingsChangedAction)
} }
} }
fun dispatchListenersAndMaybeRestart(id: Int, restartAction: Consumer<Boolean>?) { fun dispatchListenersAndMaybeRestart(name: String, restartAction: Consumer<Boolean>?) {
val filteredListeners: List<FlagListenable.Listener> = synchronized(listeners) { val filteredListeners: List<FlagListenable.Listener> = synchronized(listeners) {
listeners.mapNotNull { if (it.id == id) it.listener else null } listeners.mapNotNull { if (it.name == name) it.listener else null }
} }
// If there are no listeners, there's nothing to dispatch to, and nothing to suppress it. // If there are no listeners, there's nothing to dispatch to, and nothing to suppress it.
if (filteredListeners.isEmpty()) { if (filteredListeners.isEmpty()) {
@@ -185,7 +192,7 @@ class FlagManager constructor(
val suppressRestartList: List<Boolean> = filteredListeners.map { listener -> val suppressRestartList: List<Boolean> = filteredListeners.map { listener ->
var didRequestNoRestart = false var didRequestNoRestart = false
val event = object : FlagListenable.FlagEvent { val event = object : FlagListenable.FlagEvent {
override val flagId = id override val flagName = name
override fun requestNoRestart() { override fun requestNoRestart() {
didRequestNoRestart = true didRequestNoRestart = true
} }
@@ -198,7 +205,7 @@ class FlagManager constructor(
restartAction?.accept(suppressRestart) restartAction?.accept(suppressRestart)
} }
private data class PerFlagListener(val id: Int, val listener: FlagListenable.Listener) private data class PerFlagListener(val name: String, val listener: FlagListenable.Listener)
} }
class NoFlagResultsException : Exception( class NoFlagResultsException : Exception(

View File

@@ -22,7 +22,10 @@ import android.provider.Settings
class FlagSettingsHelper(private val contentResolver: ContentResolver) { class FlagSettingsHelper(private val contentResolver: ContentResolver) {
fun getString(key: String): String? = Settings.Secure.getString(contentResolver, key) // TODO(b/265188950): Remove method this once ids are fully deprecated.
fun getStringFromSecure(key: String): String? = Settings.Secure.getString(contentResolver, key)
fun getString(key: String): String? = Settings.Global.getString(contentResolver, key)
fun registerContentObserver( fun registerContentObserver(
name: String, name: String,

View File

@@ -35,7 +35,7 @@ object FlagsFactory {
teamfood: Boolean = false teamfood: Boolean = false
): UnreleasedFlag { ): UnreleasedFlag {
val flag = UnreleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood) val flag = UnreleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood)
FlagsFactory.checkForDupesAndAdd(flag) checkForDupesAndAdd(flag)
return flag return flag
} }
@@ -46,7 +46,7 @@ object FlagsFactory {
teamfood: Boolean = false teamfood: Boolean = false
): ReleasedFlag { ): ReleasedFlag {
val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood) val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood)
FlagsFactory.checkForDupesAndAdd(flag) checkForDupesAndAdd(flag)
return flag return flag
} }
@@ -65,7 +65,7 @@ object FlagsFactory {
resourceId = resourceId, resourceId = resourceId,
teamfood = teamfood teamfood = teamfood
) )
FlagsFactory.checkForDupesAndAdd(flag) checkForDupesAndAdd(flag)
return flag return flag
} }
@@ -77,18 +77,13 @@ object FlagsFactory {
): SysPropBooleanFlag { ): SysPropBooleanFlag {
val flag = val flag =
SysPropBooleanFlag(id = id, name = name, namespace = "systemui", default = default) SysPropBooleanFlag(id = id, name = name, namespace = "systemui", default = default)
FlagsFactory.checkForDupesAndAdd(flag) checkForDupesAndAdd(flag)
return flag return flag
} }
private fun checkForDupesAndAdd(flag: Flag<*>) { private fun checkForDupesAndAdd(flag: Flag<*>) {
if (flagMap.containsKey(flag.name)) { if (flagMap.containsKey(flag.name)) {
throw IllegalArgumentException("Name {flag.name} is already registered") throw IllegalArgumentException("Name {$flag.name} is already registered")
}
flagMap.forEach {
if (it.value.id == flag.id) {
throw IllegalArgumentException("Name {flag.id} is already registered")
}
} }
flagMap[flag.name] = flag flagMap[flag.name] = flag
} }

View File

@@ -34,7 +34,7 @@ class ChooserSelector @Inject constructor(
override fun start() { override fun start() {
coroutineScope.launch { coroutineScope.launch {
val listener = FlagListenable.Listener { event -> val listener = FlagListenable.Listener { event ->
if (event.flagId == Flags.CHOOSER_UNBUNDLED.id) { if (event.flagName == Flags.CHOOSER_UNBUNDLED.name) {
launch { updateUnbundledChooserEnabled() } launch { updateUnbundledChooserEnabled() }
event.requestNoRestart() event.requestNoRestart()
} }

View File

@@ -19,7 +19,7 @@ package com.android.systemui.flags;
import static com.android.systemui.flags.FlagManager.ACTION_GET_FLAGS; import static com.android.systemui.flags.FlagManager.ACTION_GET_FLAGS;
import static com.android.systemui.flags.FlagManager.ACTION_SET_FLAG; import static com.android.systemui.flags.FlagManager.ACTION_SET_FLAG;
import static com.android.systemui.flags.FlagManager.EXTRA_FLAGS; import static com.android.systemui.flags.FlagManager.EXTRA_FLAGS;
import static com.android.systemui.flags.FlagManager.EXTRA_ID; import static com.android.systemui.flags.FlagManager.EXTRA_NAME;
import static com.android.systemui.flags.FlagManager.EXTRA_VALUE; import static com.android.systemui.flags.FlagManager.EXTRA_VALUE;
import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS; import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS;
@@ -39,6 +39,7 @@ import androidx.annotation.Nullable;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.settings.SecureSettings;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -72,14 +73,15 @@ public class FeatureFlagsDebug implements FeatureFlags {
private final FlagManager mFlagManager; private final FlagManager mFlagManager;
private final Context mContext; private final Context mContext;
private final GlobalSettings mGlobalSettings;
private final SecureSettings mSecureSettings; private final SecureSettings mSecureSettings;
private final Resources mResources; private final Resources mResources;
private final SystemPropertiesHelper mSystemProperties; private final SystemPropertiesHelper mSystemProperties;
private final ServerFlagReader mServerFlagReader; private final ServerFlagReader mServerFlagReader;
private final Map<Integer, Flag<?>> mAllFlags; private final Map<String, Flag<?>> mAllFlags;
private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>(); private final Map<String, Boolean> mBooleanFlagCache = new TreeMap<>();
private final Map<Integer, String> mStringFlagCache = new TreeMap<>(); private final Map<String, String> mStringFlagCache = new TreeMap<>();
private final Map<Integer, Integer> mIntFlagCache = new TreeMap<>(); private final Map<String, Integer> mIntFlagCache = new TreeMap<>();
private final Restarter mRestarter; private final Restarter mRestarter;
private final ServerFlagReader.ChangeListener mOnPropertiesChanged = private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
@@ -94,14 +96,16 @@ public class FeatureFlagsDebug implements FeatureFlags {
public FeatureFlagsDebug( public FeatureFlagsDebug(
FlagManager flagManager, FlagManager flagManager,
Context context, Context context,
GlobalSettings globalSettings,
SecureSettings secureSettings, SecureSettings secureSettings,
SystemPropertiesHelper systemProperties, SystemPropertiesHelper systemProperties,
@Main Resources resources, @Main Resources resources,
ServerFlagReader serverFlagReader, ServerFlagReader serverFlagReader,
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags, @Named(ALL_FLAGS) Map<String, Flag<?>> allFlags,
Restarter restarter) { Restarter restarter) {
mFlagManager = flagManager; mFlagManager = flagManager;
mContext = context; mContext = context;
mGlobalSettings = globalSettings;
mSecureSettings = secureSettings; mSecureSettings = secureSettings;
mResources = resources; mResources = resources;
mSystemProperties = systemProperties; mSystemProperties = systemProperties;
@@ -133,96 +137,103 @@ public class FeatureFlagsDebug implements FeatureFlags {
} }
private boolean isEnabledInternal(@NotNull BooleanFlag flag) { private boolean isEnabledInternal(@NotNull BooleanFlag flag) {
int id = flag.getId(); String name = flag.getName();
if (!mBooleanFlagCache.containsKey(id)) { if (!mBooleanFlagCache.containsKey(name)) {
mBooleanFlagCache.put(id, mBooleanFlagCache.put(name,
readBooleanFlagInternal(flag, flag.getDefault())); readBooleanFlagInternal(flag, flag.getDefault()));
} }
return mBooleanFlagCache.get(id); return mBooleanFlagCache.get(name);
} }
@Override @Override
public boolean isEnabled(@NonNull ResourceBooleanFlag flag) { public boolean isEnabled(@NonNull ResourceBooleanFlag flag) {
int id = flag.getId(); String name = flag.getName();
if (!mBooleanFlagCache.containsKey(id)) { if (!mBooleanFlagCache.containsKey(name)) {
mBooleanFlagCache.put(id, mBooleanFlagCache.put(name,
readBooleanFlagInternal(flag, mResources.getBoolean(flag.getResourceId()))); readBooleanFlagInternal(flag, mResources.getBoolean(flag.getResourceId())));
} }
return mBooleanFlagCache.get(id); return mBooleanFlagCache.get(name);
} }
@Override @Override
public boolean isEnabled(@NonNull SysPropBooleanFlag flag) { public boolean isEnabled(@NonNull SysPropBooleanFlag flag) {
int id = flag.getId(); String name = flag.getName();
if (!mBooleanFlagCache.containsKey(id)) { if (!mBooleanFlagCache.containsKey(name)) {
// Use #readFlagValue to get the default. That will allow it to fall through to // Use #readFlagValue to get the default. That will allow it to fall through to
// teamfood if need be. // teamfood if need be.
mBooleanFlagCache.put( mBooleanFlagCache.put(
id, name,
mSystemProperties.getBoolean( mSystemProperties.getBoolean(
flag.getName(), flag.getName(),
readBooleanFlagInternal(flag, flag.getDefault()))); readBooleanFlagInternal(flag, flag.getDefault())));
} }
return mBooleanFlagCache.get(id); return mBooleanFlagCache.get(name);
} }
@NonNull @NonNull
@Override @Override
public String getString(@NonNull StringFlag flag) { public String getString(@NonNull StringFlag flag) {
int id = flag.getId(); String name = flag.getName();
if (!mStringFlagCache.containsKey(id)) { if (!mStringFlagCache.containsKey(name)) {
mStringFlagCache.put(id, mStringFlagCache.put(name,
readFlagValueInternal(id, flag.getDefault(), StringFlagSerializer.INSTANCE)); readFlagValueInternal(
flag.getId(), name, flag.getDefault(), StringFlagSerializer.INSTANCE));
} }
return mStringFlagCache.get(id); return mStringFlagCache.get(name);
} }
@NonNull @NonNull
@Override @Override
public String getString(@NonNull ResourceStringFlag flag) { public String getString(@NonNull ResourceStringFlag flag) {
int id = flag.getId(); String name = flag.getName();
if (!mStringFlagCache.containsKey(id)) { if (!mStringFlagCache.containsKey(name)) {
mStringFlagCache.put(id, mStringFlagCache.put(name,
readFlagValueInternal(id, mResources.getString(flag.getResourceId()), readFlagValueInternal(
flag.getId(), name, mResources.getString(flag.getResourceId()),
StringFlagSerializer.INSTANCE)); StringFlagSerializer.INSTANCE));
} }
return mStringFlagCache.get(id); return mStringFlagCache.get(name);
} }
@NonNull @NonNull
@Override @Override
public int getInt(@NonNull IntFlag flag) { public int getInt(@NonNull IntFlag flag) {
int id = flag.getId(); String name = flag.getName();
if (!mIntFlagCache.containsKey(id)) { if (!mIntFlagCache.containsKey(name)) {
mIntFlagCache.put(id, mIntFlagCache.put(name,
readFlagValueInternal(id, flag.getDefault(), IntFlagSerializer.INSTANCE)); readFlagValueInternal(
flag.getId(), name, flag.getDefault(), IntFlagSerializer.INSTANCE));
} }
return mIntFlagCache.get(id); return mIntFlagCache.get(name);
} }
@NonNull @NonNull
@Override @Override
public int getInt(@NonNull ResourceIntFlag flag) { public int getInt(@NonNull ResourceIntFlag flag) {
int id = flag.getId(); String name = flag.getName();
if (!mIntFlagCache.containsKey(id)) { if (!mIntFlagCache.containsKey(name)) {
mIntFlagCache.put(id, mIntFlagCache.put(name,
readFlagValueInternal(id, mResources.getInteger(flag.getResourceId()), readFlagValueInternal(
flag.getId(), name, mResources.getInteger(flag.getResourceId()),
IntFlagSerializer.INSTANCE)); IntFlagSerializer.INSTANCE));
} }
return mIntFlagCache.get(id); return mIntFlagCache.get(name);
} }
/** Specific override for Boolean flags that checks against the teamfood list.*/ /** Specific override for Boolean flags that checks against the teamfood list.*/
private boolean readBooleanFlagInternal(Flag<Boolean> flag, boolean defaultValue) { private boolean readBooleanFlagInternal(Flag<Boolean> flag, boolean defaultValue) {
Boolean result = readBooleanFlagOverride(flag.getId()); Boolean result = readBooleanFlagOverride(flag.getName());
if (result == null) {
result = readBooleanFlagOverride(flag.getId());
}
boolean hasServerOverride = mServerFlagReader.hasOverride( boolean hasServerOverride = mServerFlagReader.hasOverride(
flag.getNamespace(), flag.getName()); flag.getNamespace(), flag.getName());
@@ -231,7 +242,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
if (!hasServerOverride if (!hasServerOverride
&& !defaultValue && !defaultValue
&& result == null && result == null
&& flag.getId() != Flags.TEAMFOOD.getId() && !flag.getName().equals(Flags.TEAMFOOD.getName())
&& flag.getTeamfood()) { && flag.getTeamfood()) {
return isEnabled(Flags.TEAMFOOD); return isEnabled(Flags.TEAMFOOD);
} }
@@ -244,16 +255,31 @@ public class FeatureFlagsDebug implements FeatureFlags {
return readFlagValueInternal(id, BooleanFlagSerializer.INSTANCE); return readFlagValueInternal(id, BooleanFlagSerializer.INSTANCE);
} }
private Boolean readBooleanFlagOverride(String name) {
return readFlagValueInternal(name, BooleanFlagSerializer.INSTANCE);
}
// TODO(b/265188950): Remove id from this method once ids are fully deprecated.
@NonNull @NonNull
private <T> T readFlagValueInternal( private <T> T readFlagValueInternal(
int id, @NonNull T defaultValue, FlagSerializer<T> serializer) { int id, String name, @NonNull T defaultValue, FlagSerializer<T> serializer) {
requireNonNull(defaultValue, "defaultValue"); requireNonNull(defaultValue, "defaultValue");
T result = readFlagValueInternal(id, serializer); T resultForName = readFlagValueInternal(name, serializer);
return result == null ? defaultValue : result; if (resultForName == null) {
T resultForId = readFlagValueInternal(id, serializer);
if (resultForId == null) {
return defaultValue;
} else {
setFlagValue(name, resultForId, serializer);
return resultForId;
}
}
return resultForName;
} }
/** Returns the stored value or null if not set. */ /** Returns the stored value or null if not set. */
// TODO(b/265188950): Remove method this once ids are fully deprecated.
@Nullable @Nullable
private <T> T readFlagValueInternal(int id, FlagSerializer<T> serializer) { private <T> T readFlagValueInternal(int id, FlagSerializer<T> serializer) {
try { try {
@@ -264,51 +290,71 @@ public class FeatureFlagsDebug implements FeatureFlags {
return null; return null;
} }
private <T> void setFlagValue(int id, @NonNull T value, FlagSerializer<T> serializer) { /** Returns the stored value or null if not set. */
@Nullable
private <T> T readFlagValueInternal(String name, FlagSerializer<T> serializer) {
try {
return mFlagManager.readFlagValue(name, serializer);
} catch (Exception e) {
eraseInternal(name);
}
return null;
}
private <T> void setFlagValue(String name, @NonNull T value, FlagSerializer<T> serializer) {
requireNonNull(value, "Cannot set a null value"); requireNonNull(value, "Cannot set a null value");
T currentValue = readFlagValueInternal(id, serializer); T currentValue = readFlagValueInternal(name, serializer);
if (Objects.equals(currentValue, value)) { if (Objects.equals(currentValue, value)) {
Log.i(TAG, "Flag id " + id + " is already " + value); Log.i(TAG, "Flag id " + name + " is already " + value);
return; return;
} }
final String data = serializer.toSettingsData(value); final String data = serializer.toSettingsData(value);
if (data == null) { if (data == null) {
Log.w(TAG, "Failed to set id " + id + " to " + value); Log.w(TAG, "Failed to set id " + name + " to " + value);
return; return;
} }
mSecureSettings.putStringForUser(mFlagManager.idToSettingsKey(id), data, mGlobalSettings.putStringForUser(mFlagManager.nameToSettingsKey(name), data,
UserHandle.USER_CURRENT); UserHandle.USER_CURRENT);
Log.i(TAG, "Set id " + id + " to " + value); Log.i(TAG, "Set id " + name + " to " + value);
removeFromCache(id); removeFromCache(name);
mFlagManager.dispatchListenersAndMaybeRestart(id, this::restartSystemUI); mFlagManager.dispatchListenersAndMaybeRestart(name, this::restartSystemUI);
} }
<T> void eraseFlag(Flag<T> flag) { <T> void eraseFlag(Flag<T> flag) {
if (flag instanceof SysPropFlag) { if (flag instanceof SysPropFlag) {
mSystemProperties.erase(((SysPropFlag<T>) flag).getName()); mSystemProperties.erase(((SysPropFlag<T>) flag).getName());
dispatchListenersAndMaybeRestart(flag.getId(), this::restartAndroid); dispatchListenersAndMaybeRestart(flag.getName(), this::restartAndroid);
} else { } else {
eraseFlag(flag.getId()); eraseFlag(flag.getName());
} }
} }
/** Erase a flag's overridden value if there is one. */ /** Erase a flag's overridden value if there is one. */
private void eraseFlag(int id) { private void eraseFlag(String name) {
eraseInternal(id); eraseInternal(name);
removeFromCache(id); removeFromCache(name);
dispatchListenersAndMaybeRestart(id, this::restartSystemUI); dispatchListenersAndMaybeRestart(name, this::restartSystemUI);
} }
private void dispatchListenersAndMaybeRestart(int id, Consumer<Boolean> restartAction) { private void dispatchListenersAndMaybeRestart(String name, Consumer<Boolean> restartAction) {
mFlagManager.dispatchListenersAndMaybeRestart(id, restartAction); mFlagManager.dispatchListenersAndMaybeRestart(name, restartAction);
} }
/** Works just like {@link #eraseFlag(int)} except that it doesn't restart SystemUI. */ /** Works just like {@link #eraseFlag(String)} except that it doesn't restart SystemUI. */
// TODO(b/265188950): Remove method this once ids are fully deprecated.
private void eraseInternal(int id) { private void eraseInternal(int id) {
// We can't actually "erase" things from sysprops, but we can set them to empty! // We can't actually "erase" things from settings, but we can set them to empty!
mSecureSettings.putStringForUser(mFlagManager.idToSettingsKey(id), "", mGlobalSettings.putStringForUser(mFlagManager.idToSettingsKey(id), "",
UserHandle.USER_CURRENT); UserHandle.USER_CURRENT);
Log.i(TAG, "Erase id " + id); Log.i(TAG, "Erase name " + id);
}
/** Works just like {@link #eraseFlag(String)} except that it doesn't restart SystemUI. */
private void eraseInternal(String name) {
// We can't actually "erase" things from settings, but we can set them to empty!
mGlobalSettings.putStringForUser(mFlagManager.nameToSettingsKey(name), "",
UserHandle.USER_CURRENT);
Log.i(TAG, "Erase name " + name);
} }
@Override @Override
@@ -339,13 +385,13 @@ public class FeatureFlagsDebug implements FeatureFlags {
void setBooleanFlagInternal(Flag<?> flag, boolean value) { void setBooleanFlagInternal(Flag<?> flag, boolean value) {
if (flag instanceof BooleanFlag) { if (flag instanceof BooleanFlag) {
setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); setFlagValue(flag.getName(), value, BooleanFlagSerializer.INSTANCE);
} else if (flag instanceof ResourceBooleanFlag) { } else if (flag instanceof ResourceBooleanFlag) {
setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); setFlagValue(flag.getName(), value, BooleanFlagSerializer.INSTANCE);
} else if (flag instanceof SysPropBooleanFlag) { } else if (flag instanceof SysPropBooleanFlag) {
// Store SysProp flags in SystemProperties where they can read by outside parties. // Store SysProp flags in SystemProperties where they can read by outside parties.
mSystemProperties.setBoolean(((SysPropBooleanFlag) flag).getName(), value); mSystemProperties.setBoolean(((SysPropBooleanFlag) flag).getName(), value);
dispatchListenersAndMaybeRestart(flag.getId(), dispatchListenersAndMaybeRestart(flag.getName(),
FeatureFlagsDebug.this::restartAndroid); FeatureFlagsDebug.this::restartAndroid);
} else { } else {
throw new IllegalArgumentException("Unknown flag type"); throw new IllegalArgumentException("Unknown flag type");
@@ -354,9 +400,9 @@ public class FeatureFlagsDebug implements FeatureFlags {
void setStringFlagInternal(Flag<?> flag, String value) { void setStringFlagInternal(Flag<?> flag, String value) {
if (flag instanceof StringFlag) { if (flag instanceof StringFlag) {
setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE); setFlagValue(flag.getName(), value, StringFlagSerializer.INSTANCE);
} else if (flag instanceof ResourceStringFlag) { } else if (flag instanceof ResourceStringFlag) {
setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE); setFlagValue(flag.getName(), value, StringFlagSerializer.INSTANCE);
} else { } else {
throw new IllegalArgumentException("Unknown flag type"); throw new IllegalArgumentException("Unknown flag type");
} }
@@ -364,9 +410,9 @@ public class FeatureFlagsDebug implements FeatureFlags {
void setIntFlagInternal(Flag<?> flag, int value) { void setIntFlagInternal(Flag<?> flag, int value) {
if (flag instanceof IntFlag) { if (flag instanceof IntFlag) {
setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE); setFlagValue(flag.getName(), value, IntFlagSerializer.INSTANCE);
} else if (flag instanceof ResourceIntFlag) { } else if (flag instanceof ResourceIntFlag) {
setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE); setFlagValue(flag.getName(), value, IntFlagSerializer.INSTANCE);
} else { } else {
throw new IllegalArgumentException("Unknown flag type"); throw new IllegalArgumentException("Unknown flag type");
} }
@@ -405,17 +451,17 @@ public class FeatureFlagsDebug implements FeatureFlags {
Log.w(TAG, "No extras"); Log.w(TAG, "No extras");
return; return;
} }
int id = extras.getInt(EXTRA_ID); String name = extras.getString(EXTRA_NAME);
if (id <= 0) { if (name == null || name.isEmpty()) {
Log.w(TAG, "ID not set or less than or equal to 0: " + id); Log.w(TAG, "NAME not set or is empty: " + name);
return; return;
} }
if (!mAllFlags.containsKey(id)) { if (!mAllFlags.containsKey(name)) {
Log.w(TAG, "Tried to set unknown id: " + id); Log.w(TAG, "Tried to set unknown name: " + name);
return; return;
} }
Flag<?> flag = mAllFlags.get(id); Flag<?> flag = mAllFlags.get(name);
if (!extras.containsKey(EXTRA_VALUE)) { if (!extras.containsKey(EXTRA_VALUE)) {
eraseFlag(flag); eraseFlag(flag);
@@ -452,13 +498,16 @@ public class FeatureFlagsDebug implements FeatureFlags {
if (f instanceof ReleasedFlag) { if (f instanceof ReleasedFlag) {
enabled = isEnabled((ReleasedFlag) f); enabled = isEnabled((ReleasedFlag) f);
overridden = readBooleanFlagOverride(f.getId()) != null; overridden = readBooleanFlagOverride(f.getName()) != null
|| readBooleanFlagOverride(f.getId()) != null;
} else if (f instanceof UnreleasedFlag) { } else if (f instanceof UnreleasedFlag) {
enabled = isEnabled((UnreleasedFlag) f); enabled = isEnabled((UnreleasedFlag) f);
overridden = readBooleanFlagOverride(f.getId()) != null; overridden = readBooleanFlagOverride(f.getName()) != null
|| readBooleanFlagOverride(f.getId()) != null;
} else if (f instanceof ResourceBooleanFlag) { } else if (f instanceof ResourceBooleanFlag) {
enabled = isEnabled((ResourceBooleanFlag) f); enabled = isEnabled((ResourceBooleanFlag) f);
overridden = readBooleanFlagOverride(f.getId()) != null; overridden = readBooleanFlagOverride(f.getName()) != null
|| readBooleanFlagOverride(f.getId()) != null;
} else if (f instanceof SysPropBooleanFlag) { } else if (f instanceof SysPropBooleanFlag) {
// TODO(b/223379190): Teamfood not supported for sysprop flags yet. // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
enabled = isEnabled((SysPropBooleanFlag) f); enabled = isEnabled((SysPropBooleanFlag) f);
@@ -480,9 +529,9 @@ public class FeatureFlagsDebug implements FeatureFlags {
} }
}; };
private void removeFromCache(int id) { private void removeFromCache(String name) {
mBooleanFlagCache.remove(id); mBooleanFlagCache.remove(name);
mStringFlagCache.remove(id); mStringFlagCache.remove(name);
} }
@Override @Override

View File

@@ -21,18 +21,16 @@ import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import android.content.res.Resources; import android.content.res.Resources;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.DeviceConfigProxy;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
@@ -50,12 +48,11 @@ public class FeatureFlagsRelease implements FeatureFlags {
private final Resources mResources; private final Resources mResources;
private final SystemPropertiesHelper mSystemProperties; private final SystemPropertiesHelper mSystemProperties;
private final DeviceConfigProxy mDeviceConfigProxy;
private final ServerFlagReader mServerFlagReader; private final ServerFlagReader mServerFlagReader;
private final Restarter mRestarter; private final Restarter mRestarter;
private final Map<Integer, Flag<?>> mAllFlags; private final Map<String, Flag<?>> mAllFlags;
SparseBooleanArray mBooleanCache = new SparseBooleanArray(); private final Map<String, Boolean> mBooleanCache = new HashMap<>();
SparseArray<String> mStringCache = new SparseArray<>(); private final Map<String, String> mStringCache = new HashMap<>();
private final ServerFlagReader.ChangeListener mOnPropertiesChanged = private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
new ServerFlagReader.ChangeListener() { new ServerFlagReader.ChangeListener() {
@@ -69,13 +66,11 @@ public class FeatureFlagsRelease implements FeatureFlags {
public FeatureFlagsRelease( public FeatureFlagsRelease(
@Main Resources resources, @Main Resources resources,
SystemPropertiesHelper systemProperties, SystemPropertiesHelper systemProperties,
DeviceConfigProxy deviceConfigProxy,
ServerFlagReader serverFlagReader, ServerFlagReader serverFlagReader,
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags, @Named(ALL_FLAGS) Map<String, Flag<?>> allFlags,
Restarter restarter) { Restarter restarter) {
mResources = resources; mResources = resources;
mSystemProperties = systemProperties; mSystemProperties = systemProperties;
mDeviceConfigProxy = deviceConfigProxy;
mServerFlagReader = serverFlagReader; mServerFlagReader = serverFlagReader;
mAllFlags = allFlags; mAllFlags = allFlags;
mRestarter = restarter; mRestarter = restarter;
@@ -106,50 +101,48 @@ public class FeatureFlagsRelease implements FeatureFlags {
@Override @Override
public boolean isEnabled(ResourceBooleanFlag flag) { public boolean isEnabled(ResourceBooleanFlag flag) {
int cacheIndex = mBooleanCache.indexOfKey(flag.getId()); if (!mBooleanCache.containsKey(flag.getName())) {
if (cacheIndex < 0) { return isEnabled(flag.getName(), mResources.getBoolean(flag.getResourceId()));
return isEnabled(flag.getId(), mResources.getBoolean(flag.getResourceId()));
} }
return mBooleanCache.valueAt(cacheIndex); return mBooleanCache.get(flag.getName());
} }
@Override @Override
public boolean isEnabled(SysPropBooleanFlag flag) { public boolean isEnabled(SysPropBooleanFlag flag) {
int cacheIndex = mBooleanCache.indexOfKey(flag.getId()); if (!mBooleanCache.containsKey(flag.getName())) {
if (cacheIndex < 0) {
return isEnabled( return isEnabled(
flag.getId(), mSystemProperties.getBoolean(flag.getName(), flag.getDefault())); flag.getName(),
mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
} }
return mBooleanCache.valueAt(cacheIndex); return mBooleanCache.get(flag.getName());
} }
private boolean isEnabled(int key, boolean defaultValue) { private boolean isEnabled(String name, boolean defaultValue) {
mBooleanCache.append(key, defaultValue); mBooleanCache.put(name, defaultValue);
return defaultValue; return defaultValue;
} }
@NonNull @NonNull
@Override @Override
public String getString(@NonNull StringFlag flag) { public String getString(@NonNull StringFlag flag) {
return getString(flag.getId(), flag.getDefault()); return getString(flag.getName(), flag.getDefault());
} }
@NonNull @NonNull
@Override @Override
public String getString(@NonNull ResourceStringFlag flag) { public String getString(@NonNull ResourceStringFlag flag) {
int cacheIndex = mStringCache.indexOfKey(flag.getId()); if (!mStringCache.containsKey(flag.getName())) {
if (cacheIndex < 0) { return getString(flag.getName(),
return getString(flag.getId(),
requireNonNull(mResources.getString(flag.getResourceId()))); requireNonNull(mResources.getString(flag.getResourceId())));
} }
return mStringCache.valueAt(cacheIndex); return mStringCache.get(flag.getName());
} }
private String getString(int key, String defaultValue) { private String getString(String name, String defaultValue) {
mStringCache.append(key, defaultValue); mStringCache.put(name, defaultValue);
return defaultValue; return defaultValue;
} }
@@ -169,11 +162,17 @@ public class FeatureFlagsRelease implements FeatureFlags {
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("can override: false"); pw.println("can override: false");
Map<String, Flag<?>> knownFlags = FlagsFactory.INSTANCE.getKnownFlags(); Map<String, Flag<?>> knownFlags = FlagsFactory.INSTANCE.getKnownFlags();
pw.println("Booleans: ");
for (Map.Entry<String, Flag<?>> nameToFlag : knownFlags.entrySet()) { for (Map.Entry<String, Flag<?>> nameToFlag : knownFlags.entrySet()) {
Flag<?> flag = nameToFlag.getValue(); Flag<?> flag = nameToFlag.getValue();
int id = flag.getId(); if (!(flag instanceof BooleanFlag)
|| !(flag instanceof ResourceBooleanFlag)
|| !(flag instanceof SysPropBooleanFlag)) {
continue;
}
boolean def = false; boolean def = false;
if (mBooleanCache.indexOfKey(flag.getId()) < 0) { if (!mBooleanCache.containsKey(flag.getName())) {
if (flag instanceof SysPropBooleanFlag) { if (flag instanceof SysPropBooleanFlag) {
SysPropBooleanFlag f = (SysPropBooleanFlag) flag; SysPropBooleanFlag f = (SysPropBooleanFlag) flag;
def = mSystemProperties.getBoolean(f.getName(), f.getDefault()); def = mSystemProperties.getBoolean(f.getName(), f.getDefault());
@@ -185,15 +184,32 @@ public class FeatureFlagsRelease implements FeatureFlags {
def = f.getDefault(); def = f.getDefault();
} }
} }
pw.println(" sysui_flag_" + id + ": " + (mBooleanCache.get(id, def))); pw.println(
" " + flag.getName() + ": "
+ (mBooleanCache.getOrDefault(flag.getName(), def)));
} }
int numStrings = mStringCache.size();
pw.println("Strings: " + numStrings); pw.println("Strings: ");
for (int i = 0; i < numStrings; i++) { for (Map.Entry<String, Flag<?>> nameToFlag : knownFlags.entrySet()) {
final int id = mStringCache.keyAt(i); Flag<?> flag = nameToFlag.getValue();
final String value = mStringCache.valueAt(i); if (!(flag instanceof StringFlag)
final int length = value.length(); || !(flag instanceof ResourceStringFlag)) {
pw.println(" sysui_flag_" + id + ": [length=" + length + "] \"" + value + "\""); continue;
}
String def = "";
if (!mBooleanCache.containsKey(flag.getName())) {
if (flag instanceof ResourceStringFlag) {
ResourceStringFlag f = (ResourceStringFlag) flag;
def = mResources.getString(f.getResourceId());
} else if (flag instanceof StringFlag) {
StringFlag f = (StringFlag) flag;
def = f.getDefault();
}
}
String value = mStringCache.getOrDefault(flag.getName(), def);
pw.println(
" " + flag.getName() + ": [length=" + value.length() + "] \"" + value + "\"");
} }
} }
} }

View File

@@ -39,12 +39,12 @@ public class FlagCommand implements Command {
private final List<String> mOffCommands = List.of("false", "off", "0", "disable"); private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
private final List<String> mSetCommands = List.of("set", "put"); private final List<String> mSetCommands = List.of("set", "put");
private final FeatureFlagsDebug mFeatureFlags; private final FeatureFlagsDebug mFeatureFlags;
private final Map<Integer, Flag<?>> mAllFlags; private final Map<String, Flag<?>> mAllFlags;
@Inject @Inject
FlagCommand( FlagCommand(
FeatureFlagsDebug featureFlags, FeatureFlagsDebug featureFlags,
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags @Named(ALL_FLAGS) Map<String, Flag<?>> allFlags
) { ) {
mFeatureFlags = featureFlags; mFeatureFlags = featureFlags;
mAllFlags = allFlags; mAllFlags = allFlags;
@@ -53,30 +53,22 @@ public class FlagCommand implements Command {
@Override @Override
public void execute(@NonNull PrintWriter pw, @NonNull List<String> args) { public void execute(@NonNull PrintWriter pw, @NonNull List<String> args) {
if (args.size() == 0) { if (args.size() == 0) {
pw.println("Error: no flag id supplied"); pw.println("Error: no flag name supplied");
help(pw); help(pw);
pw.println(); pw.println();
printKnownFlags(pw); printKnownFlags(pw);
return; return;
} }
int id = 0; String name = args.get(0);
try { if (!mAllFlags.containsKey(name)) {
id = Integer.parseInt(args.get(0)); pw.println("Unknown flag name: " + name);
if (!mAllFlags.containsKey(id)) {
pw.println("Unknown flag id: " + id);
pw.println(); pw.println();
printKnownFlags(pw); printKnownFlags(pw);
return; return;
} }
} catch (NumberFormatException e) {
id = flagNameToId(args.get(0)); Flag<?> flag = mAllFlags.get(name);
if (id == 0) {
pw.println("Invalid flag. Must an integer id or flag name: " + args.get(0));
return;
}
}
Flag<?> flag = mAllFlags.get(id);
String cmd = ""; String cmd = "";
if (args.size() > 1) { if (args.size() > 1) {
@@ -117,7 +109,7 @@ public class FlagCommand implements Command {
return; return;
} }
pw.println("Flag " + id + " is " + newValue); pw.println("Flag " + name + " is " + newValue);
pw.flush(); // Next command will restart sysui, so flush before we do so. pw.flush(); // Next command will restart sysui, so flush before we do so.
if (shouldSet) { if (shouldSet) {
mFeatureFlags.setBooleanFlagInternal(flag, newValue); mFeatureFlags.setBooleanFlagInternal(flag, newValue);
@@ -136,11 +128,11 @@ public class FlagCommand implements Command {
return; return;
} }
String value = args.get(2); String value = args.get(2);
pw.println("Setting Flag " + id + " to " + value); pw.println("Setting Flag " + name + " to " + value);
pw.flush(); // Next command will restart sysui, so flush before we do so. pw.flush(); // Next command will restart sysui, so flush before we do so.
mFeatureFlags.setStringFlagInternal(flag, args.get(2)); mFeatureFlags.setStringFlagInternal(flag, args.get(2));
} else { } else {
pw.println("Flag " + id + " is " + getStringFlag(flag)); pw.println("Flag " + name + " is " + getStringFlag(flag));
} }
return; return;
} else if (isIntFlag(flag)) { } else if (isIntFlag(flag)) {
@@ -155,11 +147,11 @@ public class FlagCommand implements Command {
return; return;
} }
int value = Integer.parseInt(args.get(2)); int value = Integer.parseInt(args.get(2));
pw.println("Setting Flag " + id + " to " + value); pw.println("Setting Flag " + name + " to " + value);
pw.flush(); // Next command will restart sysui, so flush before we do so. pw.flush(); // Next command will restart sysui, so flush before we do so.
mFeatureFlags.setIntFlagInternal(flag, value); mFeatureFlags.setIntFlagInternal(flag, value);
} else { } else {
pw.println("Flag " + id + " is " + getIntFlag(flag)); pw.println("Flag " + name + " is " + getIntFlag(flag));
} }
return; return;
} }
@@ -182,8 +174,7 @@ public class FlagCommand implements Command {
private boolean isBooleanFlag(Flag<?> flag) { private boolean isBooleanFlag(Flag<?> flag) {
return (flag instanceof BooleanFlag) return (flag instanceof BooleanFlag)
|| (flag instanceof ResourceBooleanFlag) || (flag instanceof ResourceBooleanFlag)
|| (flag instanceof SysPropFlag) || (flag instanceof SysPropFlag);
|| (flag instanceof DeviceConfigBooleanFlag);
} }
private boolean isBooleanFlagEnabled(Flag<?> flag) { private boolean isBooleanFlagEnabled(Flag<?> flag) {
@@ -252,15 +243,14 @@ public class FlagCommand implements Command {
for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) { for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
pw.print(" "); pw.print(" ");
} }
pw.println("ID Value"); pw.println(" Value");
for (int i = 0; i < longestFieldName; i++) { for (int i = 0; i < longestFieldName; i++) {
pw.print("="); pw.print("=");
} }
pw.println(" ==== ========"); pw.println(" ========");
for (String fieldName : fields.keySet()) { for (String fieldName : fields.keySet()) {
Flag<?> flag = fields.get(fieldName); Flag<?> flag = fields.get(fieldName);
int id = flag.getId(); if (!mAllFlags.containsKey(flag.getName())) {
if (id == 0 || !mAllFlags.containsKey(id)) {
continue; continue;
} }
pw.print(fieldName); pw.print(fieldName);
@@ -268,9 +258,9 @@ public class FlagCommand implements Command {
for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) { for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) {
pw.print(" "); pw.print(" ");
} }
pw.printf("%-4d ", id); pw.print(" ");
if (isBooleanFlag(flag)) { if (isBooleanFlag(flag)) {
pw.println(isBooleanFlagEnabled(mAllFlags.get(id))); pw.println(isBooleanFlagEnabled(flag));
} else if (isStringFlag(flag)) { } else if (isStringFlag(flag)) {
pw.println(getStringFlag(flag)); pw.println(getStringFlag(flag));
} else if (isIntFlag(flag)) { } else if (isIntFlag(flag)) {

View File

@@ -28,8 +28,8 @@ interface FlagsCommonModule {
@JvmStatic @JvmStatic
@Provides @Provides
@Named(ALL_FLAGS) @Named(ALL_FLAGS)
fun providesAllFlags(): Map<Int, Flag<*>> { fun providesAllFlags(): Map<String, Flag<*>> {
return FlagsFactory.knownFlags.map { it.value.id to it.value }.toMap() return FlagsFactory.knownFlags
} }
} }
} }

View File

@@ -54,10 +54,11 @@ class ServerFlagReaderImpl @Inject constructor(
return return
} }
for ((listener, flags) in listeners) { for ((listener, flags) in listeners) {
propLoop@ for (propName in properties.keyset) { propLoop@ for (propName in properties.keyset) {
for (flag in flags) { for (flag in flags) {
if (propName == getServerOverrideName(flag.id)) { if (propName == getServerOverrideName(flag.id) || propName == flag.name) {
listener.onChange() listener.onChange()
break@propLoop break@propLoop
} }

View File

@@ -148,7 +148,7 @@ class ChooserSelectorTest : SysuiTestCase() {
// Act // Act
whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id)) flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.name))
// Assert // Assert
verify(mockPackageManager, times(2)).setComponentEnabledSetting( verify(mockPackageManager, times(2)).setComponentEnabledSetting(
@@ -175,7 +175,7 @@ class ChooserSelectorTest : SysuiTestCase() {
// Act // Act
whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id)) flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.name))
// Assert // Assert
verify(mockPackageManager, times(2)).setComponentEnabledSetting( verify(mockPackageManager, times(2)).setComponentEnabledSetting(
@@ -198,13 +198,13 @@ class ChooserSelectorTest : SysuiTestCase() {
// Act // Act
whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id + 1)) flagListener.value.onFlagChanged(TestFlagEvent("other flag"))
// Assert // Assert
verifyZeroInteractions(mockPackageManager) verifyZeroInteractions(mockPackageManager)
} }
private class TestFlagEvent(override val flagId: Int) : FlagListenable.FlagEvent { private class TestFlagEvent(override val flagName: String) : FlagListenable.FlagEvent {
override fun requestNoRestart() {} override fun requestNoRestart() {}
} }
} }

View File

@@ -125,7 +125,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
flags.set(unreleasedFlag, false) flags.set(unreleasedFlag, false)
flags.set(unreleasedFlag, false) flags.set(unreleasedFlag, false)
listener.verifyInOrder(unreleasedFlag.id, unreleasedFlag.id) listener.verifyInOrder(unreleasedFlag.name, unreleasedFlag.name)
} }
@Test @Test
@@ -137,7 +137,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
flags.set(stringFlag, "Test") flags.set(stringFlag, "Test")
flags.set(stringFlag, "Test") flags.set(stringFlag, "Test")
listener.verifyInOrder(stringFlag.id) listener.verifyInOrder(stringFlag.name)
} }
@Test @Test
@@ -149,7 +149,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
flags.removeListener(listener) flags.removeListener(listener)
flags.set(unreleasedFlag, false) flags.set(unreleasedFlag, false)
listener.verifyInOrder(unreleasedFlag.id) listener.verifyInOrder(unreleasedFlag.name)
} }
@Test @Test
@@ -162,7 +162,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
flags.removeListener(listener) flags.removeListener(listener)
flags.set(stringFlag, "Other") flags.set(stringFlag, "Other")
listener.verifyInOrder(stringFlag.id) listener.verifyInOrder(stringFlag.name)
} }
@Test @Test
@@ -175,7 +175,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
flags.set(releasedFlag, true) flags.set(releasedFlag, true)
flags.set(unreleasedFlag, true) flags.set(unreleasedFlag, true)
listener.verifyInOrder(releasedFlag.id, unreleasedFlag.id) listener.verifyInOrder(releasedFlag.name, unreleasedFlag.name)
} }
@Test @Test
@@ -191,7 +191,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
flags.set(releasedFlag, false) flags.set(releasedFlag, false)
flags.set(unreleasedFlag, false) flags.set(unreleasedFlag, false)
listener.verifyInOrder(releasedFlag.id, unreleasedFlag.id) listener.verifyInOrder(releasedFlag.name, unreleasedFlag.name)
} }
@Test @Test
@@ -204,8 +204,8 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
flags.set(releasedFlag, true) flags.set(releasedFlag, true)
listener1.verifyInOrder(releasedFlag.id) listener1.verifyInOrder(releasedFlag.name)
listener2.verifyInOrder(releasedFlag.id) listener2.verifyInOrder(releasedFlag.name)
} }
@Test @Test
@@ -220,18 +220,18 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
flags.removeListener(listener2) flags.removeListener(listener2)
flags.set(releasedFlag, false) flags.set(releasedFlag, false)
listener1.verifyInOrder(releasedFlag.id, releasedFlag.id) listener1.verifyInOrder(releasedFlag.name, releasedFlag.name)
listener2.verifyInOrder(releasedFlag.id) listener2.verifyInOrder(releasedFlag.name)
} }
class VerifyingListener : FlagListenable.Listener { class VerifyingListener : FlagListenable.Listener {
var flagEventIds = mutableListOf<Int>() var flagEventNames = mutableListOf<String>()
override fun onFlagChanged(event: FlagListenable.FlagEvent) { override fun onFlagChanged(event: FlagListenable.FlagEvent) {
flagEventIds.add(event.flagId) flagEventNames.add(event.flagName)
} }
fun verifyInOrder(vararg eventIds: Int) { fun verifyInOrder(vararg eventNames: String) {
assertThat(flagEventIds).containsExactlyElementsIn(eventIds.asList()) assertThat(flagEventNames).containsExactlyElementsIn(eventNames.asList())
} }
} }
} }

View File

@@ -23,12 +23,11 @@ import android.content.res.Resources
import android.content.res.Resources.NotFoundException import android.content.res.Resources.NotFoundException
import android.test.suitebuilder.annotation.SmallTest import android.test.suitebuilder.annotation.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.DeviceConfigProxyFake
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.withArgCaptor import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SecureSettings
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import org.junit.Assert import org.junit.Assert
@@ -62,21 +61,20 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Mock @Mock
private lateinit var mockContext: Context private lateinit var mockContext: Context
@Mock @Mock
private lateinit var globalSettings: GlobalSettings
@Mock
private lateinit var secureSettings: SecureSettings private lateinit var secureSettings: SecureSettings
@Mock @Mock
private lateinit var systemProperties: SystemPropertiesHelper private lateinit var systemProperties: SystemPropertiesHelper
@Mock @Mock
private lateinit var resources: Resources private lateinit var resources: Resources
@Mock @Mock
private lateinit var commandRegistry: CommandRegistry
@Mock
private lateinit var restarter: Restarter private lateinit var restarter: Restarter
private val flagMap = mutableMapOf<Int, Flag<*>>() private val flagMap = mutableMapOf<String, Flag<*>>()
private lateinit var broadcastReceiver: BroadcastReceiver private lateinit var broadcastReceiver: BroadcastReceiver
private lateinit var clearCacheAction: Consumer<Int> private lateinit var clearCacheAction: Consumer<String>
private val serverFlagReader = ServerFlagReaderFake() private val serverFlagReader = ServerFlagReaderFake()
private val deviceConfig = DeviceConfigProxyFake()
private val teamfoodableFlagA = UnreleasedFlag( private val teamfoodableFlagA = UnreleasedFlag(
500, name = "a", namespace = "test", teamfood = true 500, name = "a", namespace = "test", teamfood = true
) )
@@ -87,11 +85,13 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Before @Before
fun setup() { fun setup() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
flagMap.put(teamfoodableFlagA.id, teamfoodableFlagA) flagMap.put(Flags.TEAMFOOD.name, Flags.TEAMFOOD)
flagMap.put(teamfoodableFlagB.id, teamfoodableFlagB) flagMap.put(teamfoodableFlagA.name, teamfoodableFlagA)
flagMap.put(teamfoodableFlagB.name, teamfoodableFlagB)
mFeatureFlagsDebug = FeatureFlagsDebug( mFeatureFlagsDebug = FeatureFlagsDebug(
flagManager, flagManager,
mockContext, mockContext,
globalSettings,
secureSettings, secureSettings,
systemProperties, systemProperties,
resources, resources,
@@ -110,14 +110,14 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
clearCacheAction = withArgCaptor { clearCacheAction = withArgCaptor {
verify(flagManager).clearCacheAction = capture() verify(flagManager).clearCacheAction = capture()
} }
whenever(flagManager.idToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" } whenever(flagManager.nameToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" }
} }
@Test @Test
fun readBooleanFlag() { fun readBooleanFlag() {
// Remember that the TEAMFOOD flag is id#1 and has special behavior. // Remember that the TEAMFOOD flag is id#1 and has special behavior.
whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true) whenever(flagManager.readFlagValue<Boolean>(eq("3"), any())).thenReturn(true)
whenever(flagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false) whenever(flagManager.readFlagValue<Boolean>(eq("4"), any())).thenReturn(false)
assertThat( assertThat(
mFeatureFlagsDebug.isEnabled( mFeatureFlagsDebug.isEnabled(
@@ -141,7 +141,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
mFeatureFlagsDebug.isEnabled( mFeatureFlagsDebug.isEnabled(
ReleasedFlag( ReleasedFlag(
4, 4,
name = "3", name = "4",
namespace = "test" namespace = "test"
) )
) )
@@ -150,7 +150,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
mFeatureFlagsDebug.isEnabled( mFeatureFlagsDebug.isEnabled(
UnreleasedFlag( UnreleasedFlag(
5, 5,
name = "4", name = "5",
namespace = "test" namespace = "test"
) )
) )
@@ -159,7 +159,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test @Test
fun teamFoodFlag_False() { fun teamFoodFlag_False() {
whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(false) whenever(flagManager.readFlagValue<Boolean>(
eq(Flags.TEAMFOOD.name), any())).thenReturn(false)
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse()
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
@@ -170,7 +171,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test @Test
fun teamFoodFlag_True() { fun teamFoodFlag_True() {
whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true) whenever(flagManager.readFlagValue<Boolean>(
eq(Flags.TEAMFOOD.name), any())).thenReturn(true)
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
@@ -181,11 +183,12 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test @Test
fun teamFoodFlag_Overridden() { fun teamFoodFlag_Overridden() {
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any())) whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.name), any()))
.thenReturn(true) .thenReturn(true)
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any())) whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.name), any()))
.thenReturn(false) .thenReturn(false)
whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true) whenever(flagManager.readFlagValue<Boolean>(
eq(Flags.TEAMFOOD.name), any())).thenReturn(true)
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse() assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()
@@ -202,8 +205,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
whenever(resources.getBoolean(1004)).thenAnswer { throw NameNotFoundException() } whenever(resources.getBoolean(1004)).thenAnswer { throw NameNotFoundException() }
whenever(resources.getBoolean(1005)).thenAnswer { throw NameNotFoundException() } whenever(resources.getBoolean(1005)).thenAnswer { throw NameNotFoundException() }
whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true) whenever(flagManager.readFlagValue<Boolean>(eq("3"), any())).thenReturn(true)
whenever(flagManager.readFlagValue<Boolean>(eq(5), any())).thenReturn(false) whenever(flagManager.readFlagValue<Boolean>(eq("5"), any())).thenReturn(false)
assertThat( assertThat(
mFeatureFlagsDebug.isEnabled( mFeatureFlagsDebug.isEnabled(
@@ -255,8 +258,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test @Test
fun readStringFlag() { fun readStringFlag() {
whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo") whenever(flagManager.readFlagValue<String>(eq("3"), any())).thenReturn("foo")
whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar") whenever(flagManager.readFlagValue<String>(eq("4"), any())).thenReturn("bar")
assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "1", "test", "biz"))).isEqualTo("biz") assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "1", "test", "biz"))).isEqualTo("biz")
assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "2", "test", "baz"))).isEqualTo("baz") assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "2", "test", "baz"))).isEqualTo("baz")
assertThat(mFeatureFlagsDebug.getString(StringFlag(3, "3", "test", "buz"))).isEqualTo("foo") assertThat(mFeatureFlagsDebug.getString(StringFlag(3, "3", "test", "buz"))).isEqualTo("foo")
@@ -272,9 +275,9 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
whenever(resources.getString(1005)).thenAnswer { throw NameNotFoundException() } whenever(resources.getString(1005)).thenAnswer { throw NameNotFoundException() }
whenever(resources.getString(1006)).thenAnswer { throw NameNotFoundException() } whenever(resources.getString(1006)).thenAnswer { throw NameNotFoundException() }
whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("override3") whenever(flagManager.readFlagValue<String>(eq("3"), any())).thenReturn("override3")
whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("override4") whenever(flagManager.readFlagValue<String>(eq("4"), any())).thenReturn("override4")
whenever(flagManager.readFlagValue<String>(eq(6), any())).thenReturn("override6") whenever(flagManager.readFlagValue<String>(eq("6"), any())).thenReturn("override6")
assertThat( assertThat(
mFeatureFlagsDebug.getString( mFeatureFlagsDebug.getString(
@@ -322,8 +325,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
@Test @Test
fun readIntFlag() { fun readIntFlag() {
whenever(flagManager.readFlagValue<Int>(eq(3), any())).thenReturn(22) whenever(flagManager.readFlagValue<Int>(eq("3"), any())).thenReturn(22)
whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(48) whenever(flagManager.readFlagValue<Int>(eq("4"), any())).thenReturn(48)
assertThat(mFeatureFlagsDebug.getInt(IntFlag(1, "1", "test", 12))).isEqualTo(12) assertThat(mFeatureFlagsDebug.getInt(IntFlag(1, "1", "test", 12))).isEqualTo(12)
assertThat(mFeatureFlagsDebug.getInt(IntFlag(2, "2", "test", 93))).isEqualTo(93) assertThat(mFeatureFlagsDebug.getInt(IntFlag(2, "2", "test", 93))).isEqualTo(93)
assertThat(mFeatureFlagsDebug.getInt(IntFlag(3, "3", "test", 8))).isEqualTo(22) assertThat(mFeatureFlagsDebug.getInt(IntFlag(3, "3", "test", 8))).isEqualTo(22)
@@ -368,12 +371,12 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
broadcastReceiver.onReceive(mockContext, Intent()) broadcastReceiver.onReceive(mockContext, Intent())
broadcastReceiver.onReceive(mockContext, Intent("invalid action")) broadcastReceiver.onReceive(mockContext, Intent("invalid action"))
broadcastReceiver.onReceive(mockContext, Intent(FlagManager.ACTION_SET_FLAG)) broadcastReceiver.onReceive(mockContext, Intent(FlagManager.ACTION_SET_FLAG))
setByBroadcast(0, false) // unknown id does nothing setByBroadcast("0", false) // unknown id does nothing
setByBroadcast(1, "string") // wrong type does nothing setByBroadcast("1", "string") // wrong type does nothing
setByBroadcast(2, 123) // wrong type does nothing setByBroadcast("2", 123) // wrong type does nothing
setByBroadcast(3, false) // wrong type does nothing setByBroadcast("3", false) // wrong type does nothing
setByBroadcast(4, 123) // wrong type does nothing setByBroadcast("4", 123) // wrong type does nothing
verifyNoMoreInteractions(flagManager, secureSettings) verifyNoMoreInteractions(flagManager, globalSettings)
} }
@Test @Test
@@ -383,16 +386,16 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
// trying to erase an id not in the map does nothing // trying to erase an id not in the map does nothing
broadcastReceiver.onReceive( broadcastReceiver.onReceive(
mockContext, mockContext,
Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_ID, 0) Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_NAME, "")
) )
verifyNoMoreInteractions(flagManager, secureSettings) verifyNoMoreInteractions(flagManager, globalSettings)
// valid id with no value puts empty string in the setting // valid id with no value puts empty string in the setting
broadcastReceiver.onReceive( broadcastReceiver.onReceive(
mockContext, mockContext,
Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_ID, 1) Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_NAME, "1")
) )
verifyPutData(1, "", numReads = 0) verifyPutData("1", "", numReads = 0)
} }
@Test @Test
@@ -402,51 +405,51 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
addFlag(ResourceBooleanFlag(3, "3", "test", 1003)) addFlag(ResourceBooleanFlag(3, "3", "test", 1003))
addFlag(ResourceBooleanFlag(4, "4", "test", 1004)) addFlag(ResourceBooleanFlag(4, "4", "test", 1004))
setByBroadcast(1, false) setByBroadcast("1", false)
verifyPutData(1, "{\"type\":\"boolean\",\"value\":false}") verifyPutData("1", "{\"type\":\"boolean\",\"value\":false}")
setByBroadcast(2, true) setByBroadcast("2", true)
verifyPutData(2, "{\"type\":\"boolean\",\"value\":true}") verifyPutData("2", "{\"type\":\"boolean\",\"value\":true}")
setByBroadcast(3, false) setByBroadcast("3", false)
verifyPutData(3, "{\"type\":\"boolean\",\"value\":false}") verifyPutData("3", "{\"type\":\"boolean\",\"value\":false}")
setByBroadcast(4, true) setByBroadcast("4", true)
verifyPutData(4, "{\"type\":\"boolean\",\"value\":true}") verifyPutData("4", "{\"type\":\"boolean\",\"value\":true}")
} }
@Test @Test
fun setStringFlag() { fun setStringFlag() {
addFlag(StringFlag(1, "flag1", "1", "test")) addFlag(StringFlag(1, "1", "1", "test"))
addFlag(ResourceStringFlag(2, "2", "test", 1002)) addFlag(ResourceStringFlag(2, "2", "test", 1002))
setByBroadcast(1, "override1") setByBroadcast("1", "override1")
verifyPutData(1, "{\"type\":\"string\",\"value\":\"override1\"}") verifyPutData("1", "{\"type\":\"string\",\"value\":\"override1\"}")
setByBroadcast(2, "override2") setByBroadcast("2", "override2")
verifyPutData(2, "{\"type\":\"string\",\"value\":\"override2\"}") verifyPutData("2", "{\"type\":\"string\",\"value\":\"override2\"}")
} }
@Test @Test
fun setFlag_ClearsCache() { fun setFlag_ClearsCache() {
val flag1 = addFlag(StringFlag(1, "1", "test", "flag1")) val flag1 = addFlag(StringFlag(1, "1", "test", "flag1"))
whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("original") whenever(flagManager.readFlagValue<String>(eq("1"), any())).thenReturn("original")
// gets the flag & cache it // gets the flag & cache it
assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original") assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original")
verify(flagManager).readFlagValue(eq(1), eq(StringFlagSerializer)) verify(flagManager, times(1)).readFlagValue(eq("1"), eq(StringFlagSerializer))
// hit the cache // hit the cache
assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original") assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original")
verifyNoMoreInteractions(flagManager) verifyNoMoreInteractions(flagManager)
// set the flag // set the flag
setByBroadcast(1, "new") setByBroadcast("1", "new")
verifyPutData(1, "{\"type\":\"string\",\"value\":\"new\"}", numReads = 2) verifyPutData("1", "{\"type\":\"string\",\"value\":\"new\"}", numReads = 2)
whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("new") whenever(flagManager.readFlagValue<String>(eq("1"), any())).thenReturn("new")
assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("new") assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("new")
verify(flagManager, times(3)).readFlagValue(eq(1), eq(StringFlagSerializer)) verify(flagManager, times(3)).readFlagValue(eq("1"), eq(StringFlagSerializer))
} }
@Test @Test
@@ -463,7 +466,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
val flag = UnreleasedFlag(100, name = "100", namespace = "test") val flag = UnreleasedFlag(100, name = "100", namespace = "test")
serverFlagReader.setFlagValue(flag.namespace, flag.name, true) serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
assertThat(mFeatureFlagsDebug.isEnabled(flag)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(flag)).isTrue()
} }
@@ -503,26 +505,26 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(dump).contains(" sysui_flag_7: [length=9] \"override7\"\n") assertThat(dump).contains(" sysui_flag_7: [length=9] \"override7\"\n")
} }
private fun verifyPutData(id: Int, data: String, numReads: Int = 1) { private fun verifyPutData(name: String, data: String, numReads: Int = 1) {
inOrder(flagManager, secureSettings).apply { inOrder(flagManager, globalSettings).apply {
verify(flagManager, times(numReads)).readFlagValue(eq(id), any<FlagSerializer<*>>()) verify(flagManager, times(numReads)).readFlagValue(eq(name), any<FlagSerializer<*>>())
verify(flagManager).idToSettingsKey(eq(id)) verify(flagManager).nameToSettingsKey(eq(name))
verify(secureSettings).putStringForUser(eq("key-$id"), eq(data), anyInt()) verify(globalSettings).putStringForUser(eq("key-$name"), eq(data), anyInt())
verify(flagManager).dispatchListenersAndMaybeRestart(eq(id), any()) verify(flagManager).dispatchListenersAndMaybeRestart(eq(name), any())
}.verifyNoMoreInteractions() }.verifyNoMoreInteractions()
verifyNoMoreInteractions(flagManager, secureSettings) verifyNoMoreInteractions(flagManager, globalSettings)
} }
private fun setByBroadcast(id: Int, value: Serializable?) { private fun setByBroadcast(name: String, value: Serializable?) {
val intent = Intent(FlagManager.ACTION_SET_FLAG) val intent = Intent(FlagManager.ACTION_SET_FLAG)
intent.putExtra(FlagManager.EXTRA_ID, id) intent.putExtra(FlagManager.EXTRA_NAME, name)
intent.putExtra(FlagManager.EXTRA_VALUE, value) intent.putExtra(FlagManager.EXTRA_VALUE, value)
broadcastReceiver.onReceive(mockContext, intent) broadcastReceiver.onReceive(mockContext, intent)
} }
private fun <F : Flag<*>> addFlag(flag: F): F { private fun <F : Flag<*>> addFlag(flag: F): F {
val old = flagMap.put(flag.id, flag) val old = flagMap.put(flag.name, flag)
check(old == null) { "Flag ${flag.id} already registered" } check(old == null) { "Flag ${flag.name} already registered" }
return flag return flag
} }

View File

@@ -19,7 +19,6 @@ import android.content.pm.PackageManager.NameNotFoundException
import android.content.res.Resources import android.content.res.Resources
import android.test.suitebuilder.annotation.SmallTest import android.test.suitebuilder.annotation.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.util.DeviceConfigProxyFake
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows import org.junit.Assert.assertThrows
import org.junit.Before import org.junit.Before
@@ -39,9 +38,8 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
@Mock private lateinit var mResources: Resources @Mock private lateinit var mResources: Resources
@Mock private lateinit var mSystemProperties: SystemPropertiesHelper @Mock private lateinit var mSystemProperties: SystemPropertiesHelper
@Mock private lateinit var restarter: Restarter @Mock private lateinit var restarter: Restarter
private val flagMap = mutableMapOf<Int, Flag<*>>() private val flagMap = mutableMapOf<String, Flag<*>>()
private val serverFlagReader = ServerFlagReaderFake() private val serverFlagReader = ServerFlagReaderFake()
private val deviceConfig = DeviceConfigProxyFake()
@Before @Before
fun setup() { fun setup() {
@@ -49,7 +47,6 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
mFeatureFlagsRelease = FeatureFlagsRelease( mFeatureFlagsRelease = FeatureFlagsRelease(
mResources, mResources,
mSystemProperties, mSystemProperties,
deviceConfig,
serverFlagReader, serverFlagReader,
flagMap, flagMap,
restarter) restarter)

View File

@@ -32,7 +32,7 @@ class FlagCommandTest : SysuiTestCase() {
@Mock private lateinit var featureFlags: FeatureFlagsDebug @Mock private lateinit var featureFlags: FeatureFlagsDebug
@Mock private lateinit var pw: PrintWriter @Mock private lateinit var pw: PrintWriter
private val flagMap = mutableMapOf<Int, Flag<*>>() private val flagMap = mutableMapOf<String, Flag<*>>()
private val flagA = UnreleasedFlag(500, "500", "test") private val flagA = UnreleasedFlag(500, "500", "test")
private val flagB = ReleasedFlag(501, "501", "test") private val flagB = ReleasedFlag(501, "501", "test")
private val stringFlag = StringFlag(502, "502", "test", "abracadabra") private val stringFlag = StringFlag(502, "502", "test", "abracadabra")
@@ -53,59 +53,59 @@ class FlagCommandTest : SysuiTestCase() {
(invocation.getArgument(0) as IntFlag).default (invocation.getArgument(0) as IntFlag).default
} }
flagMap.put(flagA.id, flagA) flagMap.put(flagA.name, flagA)
flagMap.put(flagB.id, flagB) flagMap.put(flagB.name, flagB)
flagMap.put(stringFlag.id, stringFlag) flagMap.put(stringFlag.name, stringFlag)
flagMap.put(intFlag.id, intFlag) flagMap.put(intFlag.name, intFlag)
cmd = FlagCommand(featureFlags, flagMap) cmd = FlagCommand(featureFlags, flagMap)
} }
@Test @Test
fun readBooleanFlagCommand() { fun readBooleanFlagCommand() {
cmd.execute(pw, listOf(flagA.id.toString())) cmd.execute(pw, listOf(flagA.name))
Mockito.verify(featureFlags).isEnabled(flagA) Mockito.verify(featureFlags).isEnabled(flagA)
} }
@Test @Test
fun readStringFlagCommand() { fun readStringFlagCommand() {
cmd.execute(pw, listOf(stringFlag.id.toString())) cmd.execute(pw, listOf(stringFlag.name))
Mockito.verify(featureFlags).getString(stringFlag) Mockito.verify(featureFlags).getString(stringFlag)
} }
@Test @Test
fun readIntFlag() { fun readIntFlag() {
cmd.execute(pw, listOf(intFlag.id.toString())) cmd.execute(pw, listOf(intFlag.name))
Mockito.verify(featureFlags).getInt(intFlag) Mockito.verify(featureFlags).getInt(intFlag)
} }
@Test @Test
fun setBooleanFlagCommand() { fun setBooleanFlagCommand() {
cmd.execute(pw, listOf(flagB.id.toString(), "on")) cmd.execute(pw, listOf(flagB.name, "on"))
Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, true) Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, true)
} }
@Test @Test
fun setStringFlagCommand() { fun setStringFlagCommand() {
cmd.execute(pw, listOf(stringFlag.id.toString(), "set", "foobar")) cmd.execute(pw, listOf(stringFlag.name, "set", "foobar"))
Mockito.verify(featureFlags).setStringFlagInternal(stringFlag, "foobar") Mockito.verify(featureFlags).setStringFlagInternal(stringFlag, "foobar")
} }
@Test @Test
fun setIntFlag() { fun setIntFlag() {
cmd.execute(pw, listOf(intFlag.id.toString(), "put", "123")) cmd.execute(pw, listOf(intFlag.name, "put", "123"))
Mockito.verify(featureFlags).setIntFlagInternal(intFlag, 123) Mockito.verify(featureFlags).setIntFlagInternal(intFlag, 123)
} }
@Test @Test
fun toggleBooleanFlagCommand() { fun toggleBooleanFlagCommand() {
cmd.execute(pw, listOf(flagB.id.toString(), "toggle")) cmd.execute(pw, listOf(flagB.name, "toggle"))
Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, false) Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, false)
} }
@Test @Test
fun eraseFlagCommand() { fun eraseFlagCommand() {
cmd.execute(pw, listOf(flagA.id.toString(), "erase")) cmd.execute(pw, listOf(flagA.name, "erase"))
Mockito.verify(featureFlags).eraseFlag(flagA) Mockito.verify(featureFlags).eraseFlag(flagA)
} }
} }

View File

@@ -87,14 +87,14 @@ class FlagManagerTest : SysuiTestCase() {
@Test @Test
fun testObserverClearsCache() { fun testObserverClearsCache() {
val listener = mock<FlagListenable.Listener>() val listener = mock<FlagListenable.Listener>()
val clearCacheAction = mock<Consumer<Int>>() val clearCacheAction = mock<Consumer<String>>()
mFlagManager.clearCacheAction = clearCacheAction mFlagManager.clearCacheAction = clearCacheAction
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener) mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener)
val observer = withArgCaptor<ContentObserver> { val observer = withArgCaptor<ContentObserver> {
verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture()) verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture())
} }
observer.onChange(false, flagUri(1)) observer.onChange(false, flagUri(1))
verify(clearCacheAction).accept(eq(1)) verify(clearCacheAction).accept(eq("1"))
} }
@Test @Test
@@ -110,14 +110,14 @@ class FlagManagerTest : SysuiTestCase() {
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> { val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener1).onFlagChanged(capture()) verify(listener1).onFlagChanged(capture())
} }
assertThat(flagEvent1.flagId).isEqualTo(1) assertThat(flagEvent1.flagName).isEqualTo("1")
verifyNoMoreInteractions(listener1, listener10) verifyNoMoreInteractions(listener1, listener10)
observer.onChange(false, flagUri(10)) observer.onChange(false, flagUri(10))
val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> { val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener10).onFlagChanged(capture()) verify(listener10).onFlagChanged(capture())
} }
assertThat(flagEvent10.flagId).isEqualTo(10) assertThat(flagEvent10.flagName).isEqualTo("10")
verifyNoMoreInteractions(listener1, listener10) verifyNoMoreInteractions(listener1, listener10)
} }
@@ -130,18 +130,18 @@ class FlagManagerTest : SysuiTestCase() {
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1) mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1)
mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10) mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10)
mFlagManager.dispatchListenersAndMaybeRestart(1, null) mFlagManager.dispatchListenersAndMaybeRestart("1", null)
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> { val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener1).onFlagChanged(capture()) verify(listener1).onFlagChanged(capture())
} }
assertThat(flagEvent1.flagId).isEqualTo(1) assertThat(flagEvent1.flagName).isEqualTo("1")
verifyNoMoreInteractions(listener1, listener10) verifyNoMoreInteractions(listener1, listener10)
mFlagManager.dispatchListenersAndMaybeRestart(10, null) mFlagManager.dispatchListenersAndMaybeRestart("10", null)
val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> { val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener10).onFlagChanged(capture()) verify(listener10).onFlagChanged(capture())
} }
assertThat(flagEvent10.flagId).isEqualTo(10) assertThat(flagEvent10.flagName).isEqualTo("10")
verifyNoMoreInteractions(listener1, listener10) verifyNoMoreInteractions(listener1, listener10)
} }
@@ -151,25 +151,25 @@ class FlagManagerTest : SysuiTestCase() {
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener) mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener)
mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener) mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener)
mFlagManager.dispatchListenersAndMaybeRestart(1, null) mFlagManager.dispatchListenersAndMaybeRestart("1", null)
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> { val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener).onFlagChanged(capture()) verify(listener).onFlagChanged(capture())
} }
assertThat(flagEvent1.flagId).isEqualTo(1) assertThat(flagEvent1.flagName).isEqualTo("1")
verifyNoMoreInteractions(listener) verifyNoMoreInteractions(listener)
mFlagManager.dispatchListenersAndMaybeRestart(10, null) mFlagManager.dispatchListenersAndMaybeRestart("10", null)
val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> { val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> {
verify(listener, times(2)).onFlagChanged(capture()) verify(listener, times(2)).onFlagChanged(capture())
} }
assertThat(flagEvent10.flagId).isEqualTo(10) assertThat(flagEvent10.flagName).isEqualTo("10")
verifyNoMoreInteractions(listener) verifyNoMoreInteractions(listener)
} }
@Test @Test
fun testRestartWithNoListeners() { fun testRestartWithNoListeners() {
val restartAction = mock<Consumer<Boolean>>() val restartAction = mock<Consumer<Boolean>>()
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction) mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
verify(restartAction).accept(eq(false)) verify(restartAction).accept(eq(false))
verifyNoMoreInteractions(restartAction) verifyNoMoreInteractions(restartAction)
} }
@@ -180,7 +180,7 @@ class FlagManagerTest : SysuiTestCase() {
mFlagManager.addListener(ReleasedFlag(1, "1", "test")) { event -> mFlagManager.addListener(ReleasedFlag(1, "1", "test")) { event ->
event.requestNoRestart() event.requestNoRestart()
} }
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction) mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
verify(restartAction).accept(eq(true)) verify(restartAction).accept(eq(true))
verifyNoMoreInteractions(restartAction) verifyNoMoreInteractions(restartAction)
} }
@@ -191,7 +191,7 @@ class FlagManagerTest : SysuiTestCase() {
mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event -> mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event ->
event.requestNoRestart() event.requestNoRestart()
} }
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction) mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
verify(restartAction).accept(eq(false)) verify(restartAction).accept(eq(false))
verifyNoMoreInteractions(restartAction) verifyNoMoreInteractions(restartAction)
} }
@@ -205,7 +205,7 @@ class FlagManagerTest : SysuiTestCase() {
mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { mFlagManager.addListener(ReleasedFlag(10, "10", "test")) {
// do not request // do not request
} }
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction) mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
verify(restartAction).accept(eq(false)) verify(restartAction).accept(eq(false))
verifyNoMoreInteractions(restartAction) verifyNoMoreInteractions(restartAction)
} }
@@ -214,31 +214,31 @@ class FlagManagerTest : SysuiTestCase() {
fun testReadBooleanFlag() { fun testReadBooleanFlag() {
// test that null string returns null // test that null string returns null
whenever(mFlagSettingsHelper.getString(any())).thenReturn(null) whenever(mFlagSettingsHelper.getString(any())).thenReturn(null)
assertThat(mFlagManager.readFlagValue(1, BooleanFlagSerializer)).isNull() assertThat(mFlagManager.readFlagValue("1", BooleanFlagSerializer)).isNull()
// test that empty string returns null // test that empty string returns null
whenever(mFlagSettingsHelper.getString(any())).thenReturn("") whenever(mFlagSettingsHelper.getString(any())).thenReturn("")
assertThat(mFlagManager.readFlagValue(1, BooleanFlagSerializer)).isNull() assertThat(mFlagManager.readFlagValue("1", BooleanFlagSerializer)).isNull()
// test false // test false
whenever(mFlagSettingsHelper.getString(any())) whenever(mFlagSettingsHelper.getString(any()))
.thenReturn("{\"type\":\"boolean\",\"value\":false}") .thenReturn("{\"type\":\"boolean\",\"value\":false}")
assertThat(mFlagManager.readFlagValue(1, BooleanFlagSerializer)).isFalse() assertThat(mFlagManager.readFlagValue("1", BooleanFlagSerializer)).isFalse()
// test true // test true
whenever(mFlagSettingsHelper.getString(any())) whenever(mFlagSettingsHelper.getString(any()))
.thenReturn("{\"type\":\"boolean\",\"value\":true}") .thenReturn("{\"type\":\"boolean\",\"value\":true}")
assertThat(mFlagManager.readFlagValue(1, BooleanFlagSerializer)).isTrue() assertThat(mFlagManager.readFlagValue("1", BooleanFlagSerializer)).isTrue()
// Reading a value of a different type should just return null // Reading a value of a different type should just return null
whenever(mFlagSettingsHelper.getString(any())) whenever(mFlagSettingsHelper.getString(any()))
.thenReturn("{\"type\":\"string\",\"value\":\"foo\"}") .thenReturn("{\"type\":\"string\",\"value\":\"foo\"}")
assertThat(mFlagManager.readFlagValue(1, BooleanFlagSerializer)).isNull() assertThat(mFlagManager.readFlagValue("1", BooleanFlagSerializer)).isNull()
// Reading a value that isn't json should throw an exception // Reading a value that isn't json should throw an exception
assertThrows(InvalidFlagStorageException::class.java) { assertThrows(InvalidFlagStorageException::class.java) {
whenever(mFlagSettingsHelper.getString(any())).thenReturn("1") whenever(mFlagSettingsHelper.getString(any())).thenReturn("1")
mFlagManager.readFlagValue(1, BooleanFlagSerializer) mFlagManager.readFlagValue("1", BooleanFlagSerializer)
} }
} }
@@ -257,31 +257,31 @@ class FlagManagerTest : SysuiTestCase() {
fun testReadStringFlag() { fun testReadStringFlag() {
// test that null string returns null // test that null string returns null
whenever(mFlagSettingsHelper.getString(any())).thenReturn(null) whenever(mFlagSettingsHelper.getString(any())).thenReturn(null)
assertThat(mFlagManager.readFlagValue(1, StringFlagSerializer)).isNull() assertThat(mFlagManager.readFlagValue("1", StringFlagSerializer)).isNull()
// test that empty string returns null // test that empty string returns null
whenever(mFlagSettingsHelper.getString(any())).thenReturn("") whenever(mFlagSettingsHelper.getString(any())).thenReturn("")
assertThat(mFlagManager.readFlagValue(1, StringFlagSerializer)).isNull() assertThat(mFlagManager.readFlagValue("1", StringFlagSerializer)).isNull()
// test json with the empty string value returns empty string // test json with the empty string value returns empty string
whenever(mFlagSettingsHelper.getString(any())) whenever(mFlagSettingsHelper.getString(any()))
.thenReturn("{\"type\":\"string\",\"value\":\"\"}") .thenReturn("{\"type\":\"string\",\"value\":\"\"}")
assertThat(mFlagManager.readFlagValue(1, StringFlagSerializer)).isEqualTo("") assertThat(mFlagManager.readFlagValue("1", StringFlagSerializer)).isEqualTo("")
// test string with value is returned // test string with value is returned
whenever(mFlagSettingsHelper.getString(any())) whenever(mFlagSettingsHelper.getString(any()))
.thenReturn("{\"type\":\"string\",\"value\":\"foo\"}") .thenReturn("{\"type\":\"string\",\"value\":\"foo\"}")
assertThat(mFlagManager.readFlagValue(1, StringFlagSerializer)).isEqualTo("foo") assertThat(mFlagManager.readFlagValue("1", StringFlagSerializer)).isEqualTo("foo")
// Reading a value of a different type should just return null // Reading a value of a different type should just return null
whenever(mFlagSettingsHelper.getString(any())) whenever(mFlagSettingsHelper.getString(any()))
.thenReturn("{\"type\":\"boolean\",\"value\":false}") .thenReturn("{\"type\":\"boolean\",\"value\":false}")
assertThat(mFlagManager.readFlagValue(1, StringFlagSerializer)).isNull() assertThat(mFlagManager.readFlagValue("1", StringFlagSerializer)).isNull()
// Reading a value that isn't json should throw an exception // Reading a value that isn't json should throw an exception
assertThrows(InvalidFlagStorageException::class.java) { assertThrows(InvalidFlagStorageException::class.java) {
whenever(mFlagSettingsHelper.getString(any())).thenReturn("1") whenever(mFlagSettingsHelper.getString(any())).thenReturn("1")
mFlagManager.readFlagValue(1, StringFlagSerializer) mFlagManager.readFlagValue("1", StringFlagSerializer)
} }
} }

View File

@@ -38,12 +38,6 @@ class FakeFeatureFlags : FeatureFlags {
} }
} }
fun set(flag: DeviceConfigBooleanFlag, value: Boolean) {
if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
notifyFlagChanged(flag)
}
}
fun set(flag: ResourceBooleanFlag, value: Boolean) { fun set(flag: ResourceBooleanFlag, value: Boolean) {
if (booleanFlags.put(flag.id, value)?.let { value != it } != false) { if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
notifyFlagChanged(flag) notifyFlagChanged(flag)
@@ -73,7 +67,7 @@ class FakeFeatureFlags : FeatureFlags {
listeners.forEach { listener -> listeners.forEach { listener ->
listener.onFlagChanged( listener.onFlagChanged(
object : FlagListenable.FlagEvent { object : FlagListenable.FlagEvent {
override val flagId = flag.id override val flagName = flag.name
override fun requestNoRestart() {} override fun requestNoRestart() {}
} }
) )