Merge "Step 1 of Removing Ids from Flags." into tm-qpr-dev
This commit is contained in:
@@ -47,10 +47,6 @@ interface ResourceFlag<T> : Flag<T> {
|
||||
val resourceId: Int
|
||||
}
|
||||
|
||||
interface DeviceConfigFlag<T> : Flag<T> {
|
||||
val default: T
|
||||
}
|
||||
|
||||
interface SysPropFlag<T> : Flag<T> {
|
||||
val default: T
|
||||
}
|
||||
@@ -80,8 +76,8 @@ abstract class BooleanFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
name = parcel.readString() ?: "",
|
||||
namespace = parcel.readString() ?: "",
|
||||
default = parcel.readBoolean(),
|
||||
teamfood = parcel.readBoolean(),
|
||||
overridden = parcel.readBoolean()
|
||||
@@ -136,21 +132,6 @@ data class ResourceBooleanFlag constructor(
|
||||
override val teamfood: Boolean = false
|
||||
) : 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.
|
||||
*
|
||||
@@ -186,8 +167,8 @@ data class StringFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
name = parcel.readString() ?: "",
|
||||
namespace = parcel.readString() ?: "",
|
||||
default = parcel.readString() ?: ""
|
||||
)
|
||||
|
||||
@@ -226,8 +207,8 @@ data class IntFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
name = parcel.readString() ?: "",
|
||||
namespace = parcel.readString() ?: "",
|
||||
default = parcel.readInt()
|
||||
)
|
||||
|
||||
@@ -266,8 +247,8 @@ data class LongFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
name = parcel.readString() ?: "",
|
||||
namespace = parcel.readString() ?: "",
|
||||
default = parcel.readLong()
|
||||
)
|
||||
|
||||
@@ -298,8 +279,8 @@ data class FloatFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
name = parcel.readString() ?: "",
|
||||
namespace = parcel.readString() ?: "",
|
||||
default = parcel.readFloat()
|
||||
)
|
||||
|
||||
@@ -338,8 +319,8 @@ data class DoubleFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
name = parcel.readString() ?: "",
|
||||
namespace = parcel.readString() ?: "",
|
||||
default = parcel.readDouble()
|
||||
)
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ interface FlagListenable {
|
||||
/** An event representing the change */
|
||||
interface FlagEvent {
|
||||
/** 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 */
|
||||
fun requestNoRestart()
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class FlagManager constructor(
|
||||
const val ACTION_GET_FLAGS = "com.android.systemui.action.GET_FLAGS"
|
||||
const val FLAGS_PERMISSION = "com.android.systemui.permission.FLAGS"
|
||||
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_FLAGS = "flags"
|
||||
private const val SETTINGS_PREFIX = "systemui/flags"
|
||||
@@ -56,7 +56,7 @@ class FlagManager constructor(
|
||||
* that the restart be suppressed
|
||||
*/
|
||||
var onSettingsChangedAction: Consumer<Boolean>? = null
|
||||
var clearCacheAction: Consumer<Int>? = null
|
||||
var clearCacheAction: Consumer<String>? = null
|
||||
private val listeners: MutableSet<PerFlagListener> = mutableSetOf()
|
||||
private val settingsObserver: ContentObserver = SettingsObserver()
|
||||
|
||||
@@ -96,35 +96,42 @@ class FlagManager constructor(
|
||||
* Returns the stored value or null if not set.
|
||||
* 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.
|
||||
* This API is used by TheFlippinApp.
|
||||
*/
|
||||
fun setFlagValue(id: Int, enabled: Boolean) {
|
||||
val intent = createIntent(id)
|
||||
fun setFlagValue(name: String, enabled: Boolean) {
|
||||
val intent = createIntent(name)
|
||||
intent.putExtra(EXTRA_VALUE, enabled)
|
||||
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
fun eraseFlag(id: Int) {
|
||||
val intent = createIntent(id)
|
||||
fun eraseFlag(name: String) {
|
||||
val intent = createIntent(name)
|
||||
|
||||
context.sendBroadcast(intent)
|
||||
}
|
||||
|
||||
/** 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? {
|
||||
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)
|
||||
}
|
||||
|
||||
override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {
|
||||
synchronized(listeners) {
|
||||
val registerNeeded = listeners.isEmpty()
|
||||
listeners.add(PerFlagListener(flag.id, listener))
|
||||
listeners.add(PerFlagListener(flag.name, listener))
|
||||
if (registerNeeded) {
|
||||
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)
|
||||
intent.setPackage(RECEIVING_PACKAGE)
|
||||
intent.putExtra(EXTRA_ID, id)
|
||||
intent.putExtra(EXTRA_NAME, name)
|
||||
|
||||
return intent
|
||||
}
|
||||
|
||||
// TODO(b/265188950): Remove method this once ids are fully deprecated.
|
||||
fun idToSettingsKey(id: Int): String {
|
||||
return "$SETTINGS_PREFIX/$id"
|
||||
}
|
||||
|
||||
fun nameToSettingsKey(name: String): String {
|
||||
return "$SETTINGS_PREFIX/$name"
|
||||
}
|
||||
|
||||
inner class SettingsObserver : ContentObserver(handler) {
|
||||
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
||||
if (uri == null) {
|
||||
return
|
||||
}
|
||||
val parts = uri.pathSegments
|
||||
val idStr = parts[parts.size - 1]
|
||||
val id = try {
|
||||
idStr.toInt()
|
||||
} catch (e: NumberFormatException) {
|
||||
return
|
||||
}
|
||||
clearCacheAction?.accept(id)
|
||||
dispatchListenersAndMaybeRestart(id, onSettingsChangedAction)
|
||||
val name = parts[parts.size - 1]
|
||||
clearCacheAction?.accept(name)
|
||||
dispatchListenersAndMaybeRestart(name, onSettingsChangedAction)
|
||||
}
|
||||
}
|
||||
|
||||
fun dispatchListenersAndMaybeRestart(id: Int, restartAction: Consumer<Boolean>?) {
|
||||
fun dispatchListenersAndMaybeRestart(name: String, restartAction: Consumer<Boolean>?) {
|
||||
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 (filteredListeners.isEmpty()) {
|
||||
@@ -185,7 +192,7 @@ class FlagManager constructor(
|
||||
val suppressRestartList: List<Boolean> = filteredListeners.map { listener ->
|
||||
var didRequestNoRestart = false
|
||||
val event = object : FlagListenable.FlagEvent {
|
||||
override val flagId = id
|
||||
override val flagName = name
|
||||
override fun requestNoRestart() {
|
||||
didRequestNoRestart = true
|
||||
}
|
||||
@@ -198,7 +205,7 @@ class FlagManager constructor(
|
||||
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(
|
||||
|
||||
@@ -22,7 +22,10 @@ import android.provider.Settings
|
||||
|
||||
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(
|
||||
name: String,
|
||||
|
||||
@@ -35,7 +35,7 @@ object FlagsFactory {
|
||||
teamfood: Boolean = false
|
||||
): UnreleasedFlag {
|
||||
val flag = UnreleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood)
|
||||
FlagsFactory.checkForDupesAndAdd(flag)
|
||||
checkForDupesAndAdd(flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ object FlagsFactory {
|
||||
teamfood: Boolean = false
|
||||
): ReleasedFlag {
|
||||
val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood)
|
||||
FlagsFactory.checkForDupesAndAdd(flag)
|
||||
checkForDupesAndAdd(flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ object FlagsFactory {
|
||||
resourceId = resourceId,
|
||||
teamfood = teamfood
|
||||
)
|
||||
FlagsFactory.checkForDupesAndAdd(flag)
|
||||
checkForDupesAndAdd(flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
@@ -77,18 +77,13 @@ object FlagsFactory {
|
||||
): SysPropBooleanFlag {
|
||||
val flag =
|
||||
SysPropBooleanFlag(id = id, name = name, namespace = "systemui", default = default)
|
||||
FlagsFactory.checkForDupesAndAdd(flag)
|
||||
checkForDupesAndAdd(flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
private fun checkForDupesAndAdd(flag: Flag<*>) {
|
||||
if (flagMap.containsKey(flag.name)) {
|
||||
throw IllegalArgumentException("Name {flag.name} is already registered")
|
||||
}
|
||||
flagMap.forEach {
|
||||
if (it.value.id == flag.id) {
|
||||
throw IllegalArgumentException("Name {flag.id} is already registered")
|
||||
}
|
||||
throw IllegalArgumentException("Name {$flag.name} is already registered")
|
||||
}
|
||||
flagMap[flag.name] = flag
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class ChooserSelector @Inject constructor(
|
||||
override fun start() {
|
||||
coroutineScope.launch {
|
||||
val listener = FlagListenable.Listener { event ->
|
||||
if (event.flagId == Flags.CHOOSER_UNBUNDLED.id) {
|
||||
if (event.flagName == Flags.CHOOSER_UNBUNDLED.name) {
|
||||
launch { updateUnbundledChooserEnabled() }
|
||||
event.requestNoRestart()
|
||||
}
|
||||
|
||||
@@ -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_SET_FLAG;
|
||||
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.FlagsCommonModule.ALL_FLAGS;
|
||||
|
||||
@@ -39,6 +39,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.util.settings.GlobalSettings;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -72,14 +73,15 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
|
||||
private final FlagManager mFlagManager;
|
||||
private final Context mContext;
|
||||
private final GlobalSettings mGlobalSettings;
|
||||
private final SecureSettings mSecureSettings;
|
||||
private final Resources mResources;
|
||||
private final SystemPropertiesHelper mSystemProperties;
|
||||
private final ServerFlagReader mServerFlagReader;
|
||||
private final Map<Integer, Flag<?>> mAllFlags;
|
||||
private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
|
||||
private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
|
||||
private final Map<Integer, Integer> mIntFlagCache = new TreeMap<>();
|
||||
private final Map<String, Flag<?>> mAllFlags;
|
||||
private final Map<String, Boolean> mBooleanFlagCache = new TreeMap<>();
|
||||
private final Map<String, String> mStringFlagCache = new TreeMap<>();
|
||||
private final Map<String, Integer> mIntFlagCache = new TreeMap<>();
|
||||
private final Restarter mRestarter;
|
||||
|
||||
private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
|
||||
@@ -94,14 +96,16 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
public FeatureFlagsDebug(
|
||||
FlagManager flagManager,
|
||||
Context context,
|
||||
GlobalSettings globalSettings,
|
||||
SecureSettings secureSettings,
|
||||
SystemPropertiesHelper systemProperties,
|
||||
@Main Resources resources,
|
||||
ServerFlagReader serverFlagReader,
|
||||
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
|
||||
@Named(ALL_FLAGS) Map<String, Flag<?>> allFlags,
|
||||
Restarter restarter) {
|
||||
mFlagManager = flagManager;
|
||||
mContext = context;
|
||||
mGlobalSettings = globalSettings;
|
||||
mSecureSettings = secureSettings;
|
||||
mResources = resources;
|
||||
mSystemProperties = systemProperties;
|
||||
@@ -133,96 +137,103 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
}
|
||||
|
||||
private boolean isEnabledInternal(@NotNull BooleanFlag flag) {
|
||||
int id = flag.getId();
|
||||
if (!mBooleanFlagCache.containsKey(id)) {
|
||||
mBooleanFlagCache.put(id,
|
||||
String name = flag.getName();
|
||||
if (!mBooleanFlagCache.containsKey(name)) {
|
||||
mBooleanFlagCache.put(name,
|
||||
readBooleanFlagInternal(flag, flag.getDefault()));
|
||||
}
|
||||
|
||||
return mBooleanFlagCache.get(id);
|
||||
return mBooleanFlagCache.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(@NonNull ResourceBooleanFlag flag) {
|
||||
int id = flag.getId();
|
||||
if (!mBooleanFlagCache.containsKey(id)) {
|
||||
mBooleanFlagCache.put(id,
|
||||
String name = flag.getName();
|
||||
if (!mBooleanFlagCache.containsKey(name)) {
|
||||
mBooleanFlagCache.put(name,
|
||||
readBooleanFlagInternal(flag, mResources.getBoolean(flag.getResourceId())));
|
||||
}
|
||||
|
||||
return mBooleanFlagCache.get(id);
|
||||
return mBooleanFlagCache.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(@NonNull SysPropBooleanFlag flag) {
|
||||
int id = flag.getId();
|
||||
if (!mBooleanFlagCache.containsKey(id)) {
|
||||
String name = flag.getName();
|
||||
if (!mBooleanFlagCache.containsKey(name)) {
|
||||
// Use #readFlagValue to get the default. That will allow it to fall through to
|
||||
// teamfood if need be.
|
||||
mBooleanFlagCache.put(
|
||||
id,
|
||||
name,
|
||||
mSystemProperties.getBoolean(
|
||||
flag.getName(),
|
||||
readBooleanFlagInternal(flag, flag.getDefault())));
|
||||
}
|
||||
|
||||
return mBooleanFlagCache.get(id);
|
||||
return mBooleanFlagCache.get(name);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getString(@NonNull StringFlag flag) {
|
||||
int id = flag.getId();
|
||||
if (!mStringFlagCache.containsKey(id)) {
|
||||
mStringFlagCache.put(id,
|
||||
readFlagValueInternal(id, flag.getDefault(), StringFlagSerializer.INSTANCE));
|
||||
String name = flag.getName();
|
||||
if (!mStringFlagCache.containsKey(name)) {
|
||||
mStringFlagCache.put(name,
|
||||
readFlagValueInternal(
|
||||
flag.getId(), name, flag.getDefault(), StringFlagSerializer.INSTANCE));
|
||||
}
|
||||
|
||||
return mStringFlagCache.get(id);
|
||||
return mStringFlagCache.get(name);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getString(@NonNull ResourceStringFlag flag) {
|
||||
int id = flag.getId();
|
||||
if (!mStringFlagCache.containsKey(id)) {
|
||||
mStringFlagCache.put(id,
|
||||
readFlagValueInternal(id, mResources.getString(flag.getResourceId()),
|
||||
String name = flag.getName();
|
||||
if (!mStringFlagCache.containsKey(name)) {
|
||||
mStringFlagCache.put(name,
|
||||
readFlagValueInternal(
|
||||
flag.getId(), name, mResources.getString(flag.getResourceId()),
|
||||
StringFlagSerializer.INSTANCE));
|
||||
}
|
||||
|
||||
return mStringFlagCache.get(id);
|
||||
return mStringFlagCache.get(name);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public int getInt(@NonNull IntFlag flag) {
|
||||
int id = flag.getId();
|
||||
if (!mIntFlagCache.containsKey(id)) {
|
||||
mIntFlagCache.put(id,
|
||||
readFlagValueInternal(id, flag.getDefault(), IntFlagSerializer.INSTANCE));
|
||||
String name = flag.getName();
|
||||
if (!mIntFlagCache.containsKey(name)) {
|
||||
mIntFlagCache.put(name,
|
||||
readFlagValueInternal(
|
||||
flag.getId(), name, flag.getDefault(), IntFlagSerializer.INSTANCE));
|
||||
}
|
||||
|
||||
return mIntFlagCache.get(id);
|
||||
return mIntFlagCache.get(name);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public int getInt(@NonNull ResourceIntFlag flag) {
|
||||
int id = flag.getId();
|
||||
if (!mIntFlagCache.containsKey(id)) {
|
||||
mIntFlagCache.put(id,
|
||||
readFlagValueInternal(id, mResources.getInteger(flag.getResourceId()),
|
||||
String name = flag.getName();
|
||||
if (!mIntFlagCache.containsKey(name)) {
|
||||
mIntFlagCache.put(name,
|
||||
readFlagValueInternal(
|
||||
flag.getId(), name, mResources.getInteger(flag.getResourceId()),
|
||||
IntFlagSerializer.INSTANCE));
|
||||
}
|
||||
|
||||
return mIntFlagCache.get(id);
|
||||
return mIntFlagCache.get(name);
|
||||
}
|
||||
|
||||
/** Specific override for Boolean flags that checks against the teamfood list.*/
|
||||
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(
|
||||
flag.getNamespace(), flag.getName());
|
||||
|
||||
@@ -231,7 +242,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
if (!hasServerOverride
|
||||
&& !defaultValue
|
||||
&& result == null
|
||||
&& flag.getId() != Flags.TEAMFOOD.getId()
|
||||
&& !flag.getName().equals(Flags.TEAMFOOD.getName())
|
||||
&& flag.getTeamfood()) {
|
||||
return isEnabled(Flags.TEAMFOOD);
|
||||
}
|
||||
@@ -244,16 +255,31 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
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
|
||||
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");
|
||||
T result = readFlagValueInternal(id, serializer);
|
||||
return result == null ? defaultValue : result;
|
||||
T resultForName = readFlagValueInternal(name, serializer);
|
||||
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. */
|
||||
// TODO(b/265188950): Remove method this once ids are fully deprecated.
|
||||
@Nullable
|
||||
private <T> T readFlagValueInternal(int id, FlagSerializer<T> serializer) {
|
||||
try {
|
||||
@@ -264,51 +290,71 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
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");
|
||||
T currentValue = readFlagValueInternal(id, serializer);
|
||||
T currentValue = readFlagValueInternal(name, serializer);
|
||||
if (Objects.equals(currentValue, value)) {
|
||||
Log.i(TAG, "Flag id " + id + " is already " + value);
|
||||
Log.i(TAG, "Flag id " + name + " is already " + value);
|
||||
return;
|
||||
}
|
||||
final String data = serializer.toSettingsData(value);
|
||||
if (data == null) {
|
||||
Log.w(TAG, "Failed to set id " + id + " to " + value);
|
||||
Log.w(TAG, "Failed to set id " + name + " to " + value);
|
||||
return;
|
||||
}
|
||||
mSecureSettings.putStringForUser(mFlagManager.idToSettingsKey(id), data,
|
||||
mGlobalSettings.putStringForUser(mFlagManager.nameToSettingsKey(name), data,
|
||||
UserHandle.USER_CURRENT);
|
||||
Log.i(TAG, "Set id " + id + " to " + value);
|
||||
removeFromCache(id);
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(id, this::restartSystemUI);
|
||||
Log.i(TAG, "Set id " + name + " to " + value);
|
||||
removeFromCache(name);
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(name, this::restartSystemUI);
|
||||
}
|
||||
|
||||
<T> void eraseFlag(Flag<T> flag) {
|
||||
if (flag instanceof SysPropFlag) {
|
||||
mSystemProperties.erase(((SysPropFlag<T>) flag).getName());
|
||||
dispatchListenersAndMaybeRestart(flag.getId(), this::restartAndroid);
|
||||
dispatchListenersAndMaybeRestart(flag.getName(), this::restartAndroid);
|
||||
} else {
|
||||
eraseFlag(flag.getId());
|
||||
eraseFlag(flag.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/** Erase a flag's overridden value if there is one. */
|
||||
private void eraseFlag(int id) {
|
||||
eraseInternal(id);
|
||||
removeFromCache(id);
|
||||
dispatchListenersAndMaybeRestart(id, this::restartSystemUI);
|
||||
private void eraseFlag(String name) {
|
||||
eraseInternal(name);
|
||||
removeFromCache(name);
|
||||
dispatchListenersAndMaybeRestart(name, this::restartSystemUI);
|
||||
}
|
||||
|
||||
private void dispatchListenersAndMaybeRestart(int id, Consumer<Boolean> restartAction) {
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(id, restartAction);
|
||||
private void dispatchListenersAndMaybeRestart(String name, Consumer<Boolean> 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) {
|
||||
// We can't actually "erase" things from sysprops, but we can set them to empty!
|
||||
mSecureSettings.putStringForUser(mFlagManager.idToSettingsKey(id), "",
|
||||
// We can't actually "erase" things from settings, but we can set them to empty!
|
||||
mGlobalSettings.putStringForUser(mFlagManager.idToSettingsKey(id), "",
|
||||
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
|
||||
@@ -339,13 +385,13 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
|
||||
void setBooleanFlagInternal(Flag<?> flag, boolean value) {
|
||||
if (flag instanceof BooleanFlag) {
|
||||
setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
|
||||
setFlagValue(flag.getName(), value, BooleanFlagSerializer.INSTANCE);
|
||||
} else if (flag instanceof ResourceBooleanFlag) {
|
||||
setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
|
||||
setFlagValue(flag.getName(), value, BooleanFlagSerializer.INSTANCE);
|
||||
} else if (flag instanceof SysPropBooleanFlag) {
|
||||
// Store SysProp flags in SystemProperties where they can read by outside parties.
|
||||
mSystemProperties.setBoolean(((SysPropBooleanFlag) flag).getName(), value);
|
||||
dispatchListenersAndMaybeRestart(flag.getId(),
|
||||
dispatchListenersAndMaybeRestart(flag.getName(),
|
||||
FeatureFlagsDebug.this::restartAndroid);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown flag type");
|
||||
@@ -354,9 +400,9 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
|
||||
void setStringFlagInternal(Flag<?> flag, String value) {
|
||||
if (flag instanceof StringFlag) {
|
||||
setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE);
|
||||
setFlagValue(flag.getName(), value, StringFlagSerializer.INSTANCE);
|
||||
} else if (flag instanceof ResourceStringFlag) {
|
||||
setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE);
|
||||
setFlagValue(flag.getName(), value, StringFlagSerializer.INSTANCE);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown flag type");
|
||||
}
|
||||
@@ -364,9 +410,9 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
|
||||
void setIntFlagInternal(Flag<?> flag, int value) {
|
||||
if (flag instanceof IntFlag) {
|
||||
setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE);
|
||||
setFlagValue(flag.getName(), value, IntFlagSerializer.INSTANCE);
|
||||
} else if (flag instanceof ResourceIntFlag) {
|
||||
setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE);
|
||||
setFlagValue(flag.getName(), value, IntFlagSerializer.INSTANCE);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown flag type");
|
||||
}
|
||||
@@ -405,17 +451,17 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
Log.w(TAG, "No extras");
|
||||
return;
|
||||
}
|
||||
int id = extras.getInt(EXTRA_ID);
|
||||
if (id <= 0) {
|
||||
Log.w(TAG, "ID not set or less than or equal to 0: " + id);
|
||||
String name = extras.getString(EXTRA_NAME);
|
||||
if (name == null || name.isEmpty()) {
|
||||
Log.w(TAG, "NAME not set or is empty: " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mAllFlags.containsKey(id)) {
|
||||
Log.w(TAG, "Tried to set unknown id: " + id);
|
||||
if (!mAllFlags.containsKey(name)) {
|
||||
Log.w(TAG, "Tried to set unknown name: " + name);
|
||||
return;
|
||||
}
|
||||
Flag<?> flag = mAllFlags.get(id);
|
||||
Flag<?> flag = mAllFlags.get(name);
|
||||
|
||||
if (!extras.containsKey(EXTRA_VALUE)) {
|
||||
eraseFlag(flag);
|
||||
@@ -452,13 +498,16 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
|
||||
if (f instanceof ReleasedFlag) {
|
||||
enabled = isEnabled((ReleasedFlag) f);
|
||||
overridden = readBooleanFlagOverride(f.getId()) != null;
|
||||
overridden = readBooleanFlagOverride(f.getName()) != null
|
||||
|| readBooleanFlagOverride(f.getId()) != null;
|
||||
} else if (f instanceof UnreleasedFlag) {
|
||||
enabled = isEnabled((UnreleasedFlag) f);
|
||||
overridden = readBooleanFlagOverride(f.getId()) != null;
|
||||
overridden = readBooleanFlagOverride(f.getName()) != null
|
||||
|| readBooleanFlagOverride(f.getId()) != null;
|
||||
} else if (f instanceof ResourceBooleanFlag) {
|
||||
enabled = isEnabled((ResourceBooleanFlag) f);
|
||||
overridden = readBooleanFlagOverride(f.getId()) != null;
|
||||
overridden = readBooleanFlagOverride(f.getName()) != null
|
||||
|| readBooleanFlagOverride(f.getId()) != null;
|
||||
} else if (f instanceof SysPropBooleanFlag) {
|
||||
// TODO(b/223379190): Teamfood not supported for sysprop flags yet.
|
||||
enabled = isEnabled((SysPropBooleanFlag) f);
|
||||
@@ -480,9 +529,9 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
}
|
||||
};
|
||||
|
||||
private void removeFromCache(int id) {
|
||||
mBooleanFlagCache.remove(id);
|
||||
mStringFlagCache.remove(id);
|
||||
private void removeFromCache(String name) {
|
||||
mBooleanFlagCache.remove(name);
|
||||
mStringFlagCache.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,18 +21,16 @@ import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.util.DeviceConfigProxy;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -50,12 +48,11 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
||||
|
||||
private final Resources mResources;
|
||||
private final SystemPropertiesHelper mSystemProperties;
|
||||
private final DeviceConfigProxy mDeviceConfigProxy;
|
||||
private final ServerFlagReader mServerFlagReader;
|
||||
private final Restarter mRestarter;
|
||||
private final Map<Integer, Flag<?>> mAllFlags;
|
||||
SparseBooleanArray mBooleanCache = new SparseBooleanArray();
|
||||
SparseArray<String> mStringCache = new SparseArray<>();
|
||||
private final Map<String, Flag<?>> mAllFlags;
|
||||
private final Map<String, Boolean> mBooleanCache = new HashMap<>();
|
||||
private final Map<String, String> mStringCache = new HashMap<>();
|
||||
|
||||
private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
|
||||
new ServerFlagReader.ChangeListener() {
|
||||
@@ -69,13 +66,11 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
||||
public FeatureFlagsRelease(
|
||||
@Main Resources resources,
|
||||
SystemPropertiesHelper systemProperties,
|
||||
DeviceConfigProxy deviceConfigProxy,
|
||||
ServerFlagReader serverFlagReader,
|
||||
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
|
||||
@Named(ALL_FLAGS) Map<String, Flag<?>> allFlags,
|
||||
Restarter restarter) {
|
||||
mResources = resources;
|
||||
mSystemProperties = systemProperties;
|
||||
mDeviceConfigProxy = deviceConfigProxy;
|
||||
mServerFlagReader = serverFlagReader;
|
||||
mAllFlags = allFlags;
|
||||
mRestarter = restarter;
|
||||
@@ -106,50 +101,48 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(ResourceBooleanFlag flag) {
|
||||
int cacheIndex = mBooleanCache.indexOfKey(flag.getId());
|
||||
if (cacheIndex < 0) {
|
||||
return isEnabled(flag.getId(), mResources.getBoolean(flag.getResourceId()));
|
||||
if (!mBooleanCache.containsKey(flag.getName())) {
|
||||
return isEnabled(flag.getName(), mResources.getBoolean(flag.getResourceId()));
|
||||
}
|
||||
|
||||
return mBooleanCache.valueAt(cacheIndex);
|
||||
return mBooleanCache.get(flag.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(SysPropBooleanFlag flag) {
|
||||
int cacheIndex = mBooleanCache.indexOfKey(flag.getId());
|
||||
if (cacheIndex < 0) {
|
||||
if (!mBooleanCache.containsKey(flag.getName())) {
|
||||
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) {
|
||||
mBooleanCache.append(key, defaultValue);
|
||||
private boolean isEnabled(String name, boolean defaultValue) {
|
||||
mBooleanCache.put(name, defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getString(@NonNull StringFlag flag) {
|
||||
return getString(flag.getId(), flag.getDefault());
|
||||
return getString(flag.getName(), flag.getDefault());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getString(@NonNull ResourceStringFlag flag) {
|
||||
int cacheIndex = mStringCache.indexOfKey(flag.getId());
|
||||
if (cacheIndex < 0) {
|
||||
return getString(flag.getId(),
|
||||
if (!mStringCache.containsKey(flag.getName())) {
|
||||
return getString(flag.getName(),
|
||||
requireNonNull(mResources.getString(flag.getResourceId())));
|
||||
}
|
||||
|
||||
return mStringCache.valueAt(cacheIndex);
|
||||
return mStringCache.get(flag.getName());
|
||||
}
|
||||
|
||||
private String getString(int key, String defaultValue) {
|
||||
mStringCache.append(key, defaultValue);
|
||||
private String getString(String name, String defaultValue) {
|
||||
mStringCache.put(name, defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@@ -169,11 +162,17 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
||||
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
|
||||
pw.println("can override: false");
|
||||
Map<String, Flag<?>> knownFlags = FlagsFactory.INSTANCE.getKnownFlags();
|
||||
pw.println("Booleans: ");
|
||||
for (Map.Entry<String, Flag<?>> nameToFlag : knownFlags.entrySet()) {
|
||||
Flag<?> flag = nameToFlag.getValue();
|
||||
int id = flag.getId();
|
||||
if (!(flag instanceof BooleanFlag)
|
||||
|| !(flag instanceof ResourceBooleanFlag)
|
||||
|| !(flag instanceof SysPropBooleanFlag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean def = false;
|
||||
if (mBooleanCache.indexOfKey(flag.getId()) < 0) {
|
||||
if (!mBooleanCache.containsKey(flag.getName())) {
|
||||
if (flag instanceof SysPropBooleanFlag) {
|
||||
SysPropBooleanFlag f = (SysPropBooleanFlag) flag;
|
||||
def = mSystemProperties.getBoolean(f.getName(), f.getDefault());
|
||||
@@ -185,15 +184,32 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
||||
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);
|
||||
for (int i = 0; i < numStrings; i++) {
|
||||
final int id = mStringCache.keyAt(i);
|
||||
final String value = mStringCache.valueAt(i);
|
||||
final int length = value.length();
|
||||
pw.println(" sysui_flag_" + id + ": [length=" + length + "] \"" + value + "\"");
|
||||
|
||||
pw.println("Strings: ");
|
||||
for (Map.Entry<String, Flag<?>> nameToFlag : knownFlags.entrySet()) {
|
||||
Flag<?> flag = nameToFlag.getValue();
|
||||
if (!(flag instanceof StringFlag)
|
||||
|| !(flag instanceof ResourceStringFlag)) {
|
||||
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 + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ public class FlagCommand implements Command {
|
||||
private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
|
||||
private final List<String> mSetCommands = List.of("set", "put");
|
||||
private final FeatureFlagsDebug mFeatureFlags;
|
||||
private final Map<Integer, Flag<?>> mAllFlags;
|
||||
private final Map<String, Flag<?>> mAllFlags;
|
||||
|
||||
@Inject
|
||||
FlagCommand(
|
||||
FeatureFlagsDebug featureFlags,
|
||||
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags
|
||||
@Named(ALL_FLAGS) Map<String, Flag<?>> allFlags
|
||||
) {
|
||||
mFeatureFlags = featureFlags;
|
||||
mAllFlags = allFlags;
|
||||
@@ -53,30 +53,22 @@ public class FlagCommand implements Command {
|
||||
@Override
|
||||
public void execute(@NonNull PrintWriter pw, @NonNull List<String> args) {
|
||||
if (args.size() == 0) {
|
||||
pw.println("Error: no flag id supplied");
|
||||
pw.println("Error: no flag name supplied");
|
||||
help(pw);
|
||||
pw.println();
|
||||
printKnownFlags(pw);
|
||||
return;
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
try {
|
||||
id = Integer.parseInt(args.get(0));
|
||||
if (!mAllFlags.containsKey(id)) {
|
||||
pw.println("Unknown flag id: " + id);
|
||||
pw.println();
|
||||
printKnownFlags(pw);
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
id = flagNameToId(args.get(0));
|
||||
if (id == 0) {
|
||||
pw.println("Invalid flag. Must an integer id or flag name: " + args.get(0));
|
||||
return;
|
||||
}
|
||||
String name = args.get(0);
|
||||
if (!mAllFlags.containsKey(name)) {
|
||||
pw.println("Unknown flag name: " + name);
|
||||
pw.println();
|
||||
printKnownFlags(pw);
|
||||
return;
|
||||
}
|
||||
Flag<?> flag = mAllFlags.get(id);
|
||||
|
||||
Flag<?> flag = mAllFlags.get(name);
|
||||
|
||||
String cmd = "";
|
||||
if (args.size() > 1) {
|
||||
@@ -117,7 +109,7 @@ public class FlagCommand implements Command {
|
||||
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.
|
||||
if (shouldSet) {
|
||||
mFeatureFlags.setBooleanFlagInternal(flag, newValue);
|
||||
@@ -136,11 +128,11 @@ public class FlagCommand implements Command {
|
||||
return;
|
||||
}
|
||||
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.
|
||||
mFeatureFlags.setStringFlagInternal(flag, args.get(2));
|
||||
} else {
|
||||
pw.println("Flag " + id + " is " + getStringFlag(flag));
|
||||
pw.println("Flag " + name + " is " + getStringFlag(flag));
|
||||
}
|
||||
return;
|
||||
} else if (isIntFlag(flag)) {
|
||||
@@ -155,11 +147,11 @@ public class FlagCommand implements Command {
|
||||
return;
|
||||
}
|
||||
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.
|
||||
mFeatureFlags.setIntFlagInternal(flag, value);
|
||||
} else {
|
||||
pw.println("Flag " + id + " is " + getIntFlag(flag));
|
||||
pw.println("Flag " + name + " is " + getIntFlag(flag));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -182,8 +174,7 @@ public class FlagCommand implements Command {
|
||||
private boolean isBooleanFlag(Flag<?> flag) {
|
||||
return (flag instanceof BooleanFlag)
|
||||
|| (flag instanceof ResourceBooleanFlag)
|
||||
|| (flag instanceof SysPropFlag)
|
||||
|| (flag instanceof DeviceConfigBooleanFlag);
|
||||
|| (flag instanceof SysPropFlag);
|
||||
}
|
||||
|
||||
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++) {
|
||||
pw.print(" ");
|
||||
}
|
||||
pw.println("ID Value");
|
||||
pw.println(" Value");
|
||||
for (int i = 0; i < longestFieldName; i++) {
|
||||
pw.print("=");
|
||||
}
|
||||
pw.println(" ==== ========");
|
||||
pw.println(" ========");
|
||||
for (String fieldName : fields.keySet()) {
|
||||
Flag<?> flag = fields.get(fieldName);
|
||||
int id = flag.getId();
|
||||
if (id == 0 || !mAllFlags.containsKey(id)) {
|
||||
if (!mAllFlags.containsKey(flag.getName())) {
|
||||
continue;
|
||||
}
|
||||
pw.print(fieldName);
|
||||
@@ -268,9 +258,9 @@ public class FlagCommand implements Command {
|
||||
for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) {
|
||||
pw.print(" ");
|
||||
}
|
||||
pw.printf("%-4d ", id);
|
||||
pw.print(" ");
|
||||
if (isBooleanFlag(flag)) {
|
||||
pw.println(isBooleanFlagEnabled(mAllFlags.get(id)));
|
||||
pw.println(isBooleanFlagEnabled(flag));
|
||||
} else if (isStringFlag(flag)) {
|
||||
pw.println(getStringFlag(flag));
|
||||
} else if (isIntFlag(flag)) {
|
||||
|
||||
@@ -28,8 +28,8 @@ interface FlagsCommonModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Named(ALL_FLAGS)
|
||||
fun providesAllFlags(): Map<Int, Flag<*>> {
|
||||
return FlagsFactory.knownFlags.map { it.value.id to it.value }.toMap()
|
||||
fun providesAllFlags(): Map<String, Flag<*>> {
|
||||
return FlagsFactory.knownFlags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,10 +54,11 @@ class ServerFlagReaderImpl @Inject constructor(
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
for ((listener, flags) in listeners) {
|
||||
propLoop@ for (propName in properties.keyset) {
|
||||
for (flag in flags) {
|
||||
if (propName == getServerOverrideName(flag.id)) {
|
||||
if (propName == getServerOverrideName(flag.id) || propName == flag.name) {
|
||||
listener.onChange()
|
||||
break@propLoop
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ class ChooserSelectorTest : SysuiTestCase() {
|
||||
|
||||
// Act
|
||||
whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
|
||||
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id))
|
||||
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.name))
|
||||
|
||||
// Assert
|
||||
verify(mockPackageManager, times(2)).setComponentEnabledSetting(
|
||||
@@ -175,7 +175,7 @@ class ChooserSelectorTest : SysuiTestCase() {
|
||||
|
||||
// Act
|
||||
whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
|
||||
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id))
|
||||
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.name))
|
||||
|
||||
// Assert
|
||||
verify(mockPackageManager, times(2)).setComponentEnabledSetting(
|
||||
@@ -198,13 +198,13 @@ class ChooserSelectorTest : SysuiTestCase() {
|
||||
|
||||
// Act
|
||||
whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
|
||||
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id + 1))
|
||||
flagListener.value.onFlagChanged(TestFlagEvent("other flag"))
|
||||
|
||||
// Assert
|
||||
verifyZeroInteractions(mockPackageManager)
|
||||
}
|
||||
|
||||
private class TestFlagEvent(override val flagId: Int) : FlagListenable.FlagEvent {
|
||||
private class TestFlagEvent(override val flagName: String) : FlagListenable.FlagEvent {
|
||||
override fun requestNoRestart() {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
flags.set(unreleasedFlag, false)
|
||||
flags.set(unreleasedFlag, false)
|
||||
|
||||
listener.verifyInOrder(unreleasedFlag.id, unreleasedFlag.id)
|
||||
listener.verifyInOrder(unreleasedFlag.name, unreleasedFlag.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -137,7 +137,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
flags.set(stringFlag, "Test")
|
||||
flags.set(stringFlag, "Test")
|
||||
|
||||
listener.verifyInOrder(stringFlag.id)
|
||||
listener.verifyInOrder(stringFlag.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -149,7 +149,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
flags.removeListener(listener)
|
||||
flags.set(unreleasedFlag, false)
|
||||
|
||||
listener.verifyInOrder(unreleasedFlag.id)
|
||||
listener.verifyInOrder(unreleasedFlag.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -162,7 +162,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
flags.removeListener(listener)
|
||||
flags.set(stringFlag, "Other")
|
||||
|
||||
listener.verifyInOrder(stringFlag.id)
|
||||
listener.verifyInOrder(stringFlag.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -175,7 +175,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
flags.set(releasedFlag, true)
|
||||
flags.set(unreleasedFlag, true)
|
||||
|
||||
listener.verifyInOrder(releasedFlag.id, unreleasedFlag.id)
|
||||
listener.verifyInOrder(releasedFlag.name, unreleasedFlag.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -191,7 +191,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
flags.set(releasedFlag, false)
|
||||
flags.set(unreleasedFlag, false)
|
||||
|
||||
listener.verifyInOrder(releasedFlag.id, unreleasedFlag.id)
|
||||
listener.verifyInOrder(releasedFlag.name, unreleasedFlag.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -204,8 +204,8 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
|
||||
flags.set(releasedFlag, true)
|
||||
|
||||
listener1.verifyInOrder(releasedFlag.id)
|
||||
listener2.verifyInOrder(releasedFlag.id)
|
||||
listener1.verifyInOrder(releasedFlag.name)
|
||||
listener2.verifyInOrder(releasedFlag.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -220,18 +220,18 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
flags.removeListener(listener2)
|
||||
flags.set(releasedFlag, false)
|
||||
|
||||
listener1.verifyInOrder(releasedFlag.id, releasedFlag.id)
|
||||
listener2.verifyInOrder(releasedFlag.id)
|
||||
listener1.verifyInOrder(releasedFlag.name, releasedFlag.name)
|
||||
listener2.verifyInOrder(releasedFlag.name)
|
||||
}
|
||||
|
||||
class VerifyingListener : FlagListenable.Listener {
|
||||
var flagEventIds = mutableListOf<Int>()
|
||||
var flagEventNames = mutableListOf<String>()
|
||||
override fun onFlagChanged(event: FlagListenable.FlagEvent) {
|
||||
flagEventIds.add(event.flagId)
|
||||
flagEventNames.add(event.flagName)
|
||||
}
|
||||
|
||||
fun verifyInOrder(vararg eventIds: Int) {
|
||||
assertThat(flagEventIds).containsExactlyElementsIn(eventIds.asList())
|
||||
fun verifyInOrder(vararg eventNames: String) {
|
||||
assertThat(flagEventNames).containsExactlyElementsIn(eventNames.asList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,11 @@ import android.content.res.Resources
|
||||
import android.content.res.Resources.NotFoundException
|
||||
import android.test.suitebuilder.annotation.SmallTest
|
||||
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.eq
|
||||
import com.android.systemui.util.mockito.nullable
|
||||
import com.android.systemui.util.mockito.withArgCaptor
|
||||
import com.android.systemui.util.settings.GlobalSettings
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Assert
|
||||
@@ -62,21 +61,20 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var mockContext: Context
|
||||
@Mock
|
||||
private lateinit var globalSettings: GlobalSettings
|
||||
@Mock
|
||||
private lateinit var secureSettings: SecureSettings
|
||||
@Mock
|
||||
private lateinit var systemProperties: SystemPropertiesHelper
|
||||
@Mock
|
||||
private lateinit var resources: Resources
|
||||
@Mock
|
||||
private lateinit var commandRegistry: CommandRegistry
|
||||
@Mock
|
||||
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 clearCacheAction: Consumer<Int>
|
||||
private lateinit var clearCacheAction: Consumer<String>
|
||||
private val serverFlagReader = ServerFlagReaderFake()
|
||||
|
||||
private val deviceConfig = DeviceConfigProxyFake()
|
||||
private val teamfoodableFlagA = UnreleasedFlag(
|
||||
500, name = "a", namespace = "test", teamfood = true
|
||||
)
|
||||
@@ -87,11 +85,13 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
flagMap.put(teamfoodableFlagA.id, teamfoodableFlagA)
|
||||
flagMap.put(teamfoodableFlagB.id, teamfoodableFlagB)
|
||||
flagMap.put(Flags.TEAMFOOD.name, Flags.TEAMFOOD)
|
||||
flagMap.put(teamfoodableFlagA.name, teamfoodableFlagA)
|
||||
flagMap.put(teamfoodableFlagB.name, teamfoodableFlagB)
|
||||
mFeatureFlagsDebug = FeatureFlagsDebug(
|
||||
flagManager,
|
||||
mockContext,
|
||||
globalSettings,
|
||||
secureSettings,
|
||||
systemProperties,
|
||||
resources,
|
||||
@@ -110,14 +110,14 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
clearCacheAction = withArgCaptor {
|
||||
verify(flagManager).clearCacheAction = capture()
|
||||
}
|
||||
whenever(flagManager.idToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" }
|
||||
whenever(flagManager.nameToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readBooleanFlag() {
|
||||
// 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(4), any())).thenReturn(false)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq("3"), any())).thenReturn(true)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq("4"), any())).thenReturn(false)
|
||||
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
@@ -141,7 +141,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
ReleasedFlag(
|
||||
4,
|
||||
name = "3",
|
||||
name = "4",
|
||||
namespace = "test"
|
||||
)
|
||||
)
|
||||
@@ -150,7 +150,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
UnreleasedFlag(
|
||||
5,
|
||||
name = "4",
|
||||
name = "5",
|
||||
namespace = "test"
|
||||
)
|
||||
)
|
||||
@@ -159,7 +159,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
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(teamfoodableFlagB)).isTrue()
|
||||
|
||||
@@ -170,7 +171,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
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(teamfoodableFlagB)).isTrue()
|
||||
|
||||
@@ -181,11 +183,12 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun teamFoodFlag_Overridden() {
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any()))
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.name), any()))
|
||||
.thenReturn(true)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any()))
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.name), any()))
|
||||
.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(teamfoodableFlagB)).isFalse()
|
||||
|
||||
@@ -202,8 +205,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
whenever(resources.getBoolean(1004)).thenAnswer { throw NameNotFoundException() }
|
||||
whenever(resources.getBoolean(1005)).thenAnswer { throw NameNotFoundException() }
|
||||
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(5), any())).thenReturn(false)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq("3"), any())).thenReturn(true)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq("5"), any())).thenReturn(false)
|
||||
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
@@ -255,8 +258,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun readStringFlag() {
|
||||
whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo")
|
||||
whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar")
|
||||
whenever(flagManager.readFlagValue<String>(eq("3"), any())).thenReturn("foo")
|
||||
whenever(flagManager.readFlagValue<String>(eq("4"), any())).thenReturn("bar")
|
||||
assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "1", "test", "biz"))).isEqualTo("biz")
|
||||
assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "2", "test", "baz"))).isEqualTo("baz")
|
||||
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(1006)).thenAnswer { throw NameNotFoundException() }
|
||||
|
||||
whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("override3")
|
||||
whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("override4")
|
||||
whenever(flagManager.readFlagValue<String>(eq(6), any())).thenReturn("override6")
|
||||
whenever(flagManager.readFlagValue<String>(eq("3"), any())).thenReturn("override3")
|
||||
whenever(flagManager.readFlagValue<String>(eq("4"), any())).thenReturn("override4")
|
||||
whenever(flagManager.readFlagValue<String>(eq("6"), any())).thenReturn("override6")
|
||||
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.getString(
|
||||
@@ -322,8 +325,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun readIntFlag() {
|
||||
whenever(flagManager.readFlagValue<Int>(eq(3), any())).thenReturn(22)
|
||||
whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(48)
|
||||
whenever(flagManager.readFlagValue<Int>(eq("3"), any())).thenReturn(22)
|
||||
whenever(flagManager.readFlagValue<Int>(eq("4"), any())).thenReturn(48)
|
||||
assertThat(mFeatureFlagsDebug.getInt(IntFlag(1, "1", "test", 12))).isEqualTo(12)
|
||||
assertThat(mFeatureFlagsDebug.getInt(IntFlag(2, "2", "test", 93))).isEqualTo(93)
|
||||
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("invalid action"))
|
||||
broadcastReceiver.onReceive(mockContext, Intent(FlagManager.ACTION_SET_FLAG))
|
||||
setByBroadcast(0, false) // unknown id does nothing
|
||||
setByBroadcast(1, "string") // wrong type does nothing
|
||||
setByBroadcast(2, 123) // wrong type does nothing
|
||||
setByBroadcast(3, false) // wrong type does nothing
|
||||
setByBroadcast(4, 123) // wrong type does nothing
|
||||
verifyNoMoreInteractions(flagManager, secureSettings)
|
||||
setByBroadcast("0", false) // unknown id does nothing
|
||||
setByBroadcast("1", "string") // wrong type does nothing
|
||||
setByBroadcast("2", 123) // wrong type does nothing
|
||||
setByBroadcast("3", false) // wrong type does nothing
|
||||
setByBroadcast("4", 123) // wrong type does nothing
|
||||
verifyNoMoreInteractions(flagManager, globalSettings)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -383,16 +386,16 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
// trying to erase an id not in the map does nothing
|
||||
broadcastReceiver.onReceive(
|
||||
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
|
||||
broadcastReceiver.onReceive(
|
||||
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
|
||||
@@ -402,51 +405,51 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
addFlag(ResourceBooleanFlag(3, "3", "test", 1003))
|
||||
addFlag(ResourceBooleanFlag(4, "4", "test", 1004))
|
||||
|
||||
setByBroadcast(1, false)
|
||||
verifyPutData(1, "{\"type\":\"boolean\",\"value\":false}")
|
||||
setByBroadcast("1", false)
|
||||
verifyPutData("1", "{\"type\":\"boolean\",\"value\":false}")
|
||||
|
||||
setByBroadcast(2, true)
|
||||
verifyPutData(2, "{\"type\":\"boolean\",\"value\":true}")
|
||||
setByBroadcast("2", true)
|
||||
verifyPutData("2", "{\"type\":\"boolean\",\"value\":true}")
|
||||
|
||||
setByBroadcast(3, false)
|
||||
verifyPutData(3, "{\"type\":\"boolean\",\"value\":false}")
|
||||
setByBroadcast("3", false)
|
||||
verifyPutData("3", "{\"type\":\"boolean\",\"value\":false}")
|
||||
|
||||
setByBroadcast(4, true)
|
||||
verifyPutData(4, "{\"type\":\"boolean\",\"value\":true}")
|
||||
setByBroadcast("4", true)
|
||||
verifyPutData("4", "{\"type\":\"boolean\",\"value\":true}")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setStringFlag() {
|
||||
addFlag(StringFlag(1, "flag1", "1", "test"))
|
||||
addFlag(StringFlag(1, "1", "1", "test"))
|
||||
addFlag(ResourceStringFlag(2, "2", "test", 1002))
|
||||
|
||||
setByBroadcast(1, "override1")
|
||||
verifyPutData(1, "{\"type\":\"string\",\"value\":\"override1\"}")
|
||||
setByBroadcast("1", "override1")
|
||||
verifyPutData("1", "{\"type\":\"string\",\"value\":\"override1\"}")
|
||||
|
||||
setByBroadcast(2, "override2")
|
||||
verifyPutData(2, "{\"type\":\"string\",\"value\":\"override2\"}")
|
||||
setByBroadcast("2", "override2")
|
||||
verifyPutData("2", "{\"type\":\"string\",\"value\":\"override2\"}")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setFlag_ClearsCache() {
|
||||
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
|
||||
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
|
||||
assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original")
|
||||
verifyNoMoreInteractions(flagManager)
|
||||
|
||||
// set the flag
|
||||
setByBroadcast(1, "new")
|
||||
verifyPutData(1, "{\"type\":\"string\",\"value\":\"new\"}", numReads = 2)
|
||||
whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("new")
|
||||
setByBroadcast("1", "new")
|
||||
verifyPutData("1", "{\"type\":\"string\",\"value\":\"new\"}", numReads = 2)
|
||||
whenever(flagManager.readFlagValue<String>(eq("1"), any())).thenReturn("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
|
||||
@@ -463,7 +466,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
val flag = UnreleasedFlag(100, name = "100", namespace = "test")
|
||||
|
||||
serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
|
||||
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(flag)).isTrue()
|
||||
}
|
||||
|
||||
@@ -503,26 +505,26 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
assertThat(dump).contains(" sysui_flag_7: [length=9] \"override7\"\n")
|
||||
}
|
||||
|
||||
private fun verifyPutData(id: Int, data: String, numReads: Int = 1) {
|
||||
inOrder(flagManager, secureSettings).apply {
|
||||
verify(flagManager, times(numReads)).readFlagValue(eq(id), any<FlagSerializer<*>>())
|
||||
verify(flagManager).idToSettingsKey(eq(id))
|
||||
verify(secureSettings).putStringForUser(eq("key-$id"), eq(data), anyInt())
|
||||
verify(flagManager).dispatchListenersAndMaybeRestart(eq(id), any())
|
||||
private fun verifyPutData(name: String, data: String, numReads: Int = 1) {
|
||||
inOrder(flagManager, globalSettings).apply {
|
||||
verify(flagManager, times(numReads)).readFlagValue(eq(name), any<FlagSerializer<*>>())
|
||||
verify(flagManager).nameToSettingsKey(eq(name))
|
||||
verify(globalSettings).putStringForUser(eq("key-$name"), eq(data), anyInt())
|
||||
verify(flagManager).dispatchListenersAndMaybeRestart(eq(name), any())
|
||||
}.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)
|
||||
intent.putExtra(FlagManager.EXTRA_ID, id)
|
||||
intent.putExtra(FlagManager.EXTRA_NAME, name)
|
||||
intent.putExtra(FlagManager.EXTRA_VALUE, value)
|
||||
broadcastReceiver.onReceive(mockContext, intent)
|
||||
}
|
||||
|
||||
private fun <F : Flag<*>> addFlag(flag: F): F {
|
||||
val old = flagMap.put(flag.id, flag)
|
||||
check(old == null) { "Flag ${flag.id} already registered" }
|
||||
val old = flagMap.put(flag.name, flag)
|
||||
check(old == null) { "Flag ${flag.name} already registered" }
|
||||
return flag
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import android.content.pm.PackageManager.NameNotFoundException
|
||||
import android.content.res.Resources
|
||||
import android.test.suitebuilder.annotation.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.util.DeviceConfigProxyFake
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Before
|
||||
@@ -39,9 +38,8 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
|
||||
@Mock private lateinit var mResources: Resources
|
||||
@Mock private lateinit var mSystemProperties: SystemPropertiesHelper
|
||||
@Mock private lateinit var restarter: Restarter
|
||||
private val flagMap = mutableMapOf<Int, Flag<*>>()
|
||||
private val flagMap = mutableMapOf<String, Flag<*>>()
|
||||
private val serverFlagReader = ServerFlagReaderFake()
|
||||
private val deviceConfig = DeviceConfigProxyFake()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
@@ -49,7 +47,6 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
|
||||
mFeatureFlagsRelease = FeatureFlagsRelease(
|
||||
mResources,
|
||||
mSystemProperties,
|
||||
deviceConfig,
|
||||
serverFlagReader,
|
||||
flagMap,
|
||||
restarter)
|
||||
|
||||
@@ -32,7 +32,7 @@ class FlagCommandTest : SysuiTestCase() {
|
||||
|
||||
@Mock private lateinit var featureFlags: FeatureFlagsDebug
|
||||
@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 flagB = ReleasedFlag(501, "501", "test")
|
||||
private val stringFlag = StringFlag(502, "502", "test", "abracadabra")
|
||||
@@ -53,59 +53,59 @@ class FlagCommandTest : SysuiTestCase() {
|
||||
(invocation.getArgument(0) as IntFlag).default
|
||||
}
|
||||
|
||||
flagMap.put(flagA.id, flagA)
|
||||
flagMap.put(flagB.id, flagB)
|
||||
flagMap.put(stringFlag.id, stringFlag)
|
||||
flagMap.put(intFlag.id, intFlag)
|
||||
flagMap.put(flagA.name, flagA)
|
||||
flagMap.put(flagB.name, flagB)
|
||||
flagMap.put(stringFlag.name, stringFlag)
|
||||
flagMap.put(intFlag.name, intFlag)
|
||||
|
||||
cmd = FlagCommand(featureFlags, flagMap)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readBooleanFlagCommand() {
|
||||
cmd.execute(pw, listOf(flagA.id.toString()))
|
||||
cmd.execute(pw, listOf(flagA.name))
|
||||
Mockito.verify(featureFlags).isEnabled(flagA)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readStringFlagCommand() {
|
||||
cmd.execute(pw, listOf(stringFlag.id.toString()))
|
||||
cmd.execute(pw, listOf(stringFlag.name))
|
||||
Mockito.verify(featureFlags).getString(stringFlag)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readIntFlag() {
|
||||
cmd.execute(pw, listOf(intFlag.id.toString()))
|
||||
cmd.execute(pw, listOf(intFlag.name))
|
||||
Mockito.verify(featureFlags).getInt(intFlag)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setBooleanFlagCommand() {
|
||||
cmd.execute(pw, listOf(flagB.id.toString(), "on"))
|
||||
cmd.execute(pw, listOf(flagB.name, "on"))
|
||||
Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, true)
|
||||
}
|
||||
|
||||
@Test
|
||||
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")
|
||||
}
|
||||
|
||||
@Test
|
||||
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)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun toggleBooleanFlagCommand() {
|
||||
cmd.execute(pw, listOf(flagB.id.toString(), "toggle"))
|
||||
cmd.execute(pw, listOf(flagB.name, "toggle"))
|
||||
Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun eraseFlagCommand() {
|
||||
cmd.execute(pw, listOf(flagA.id.toString(), "erase"))
|
||||
cmd.execute(pw, listOf(flagA.name, "erase"))
|
||||
Mockito.verify(featureFlags).eraseFlag(flagA)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,14 +87,14 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testObserverClearsCache() {
|
||||
val listener = mock<FlagListenable.Listener>()
|
||||
val clearCacheAction = mock<Consumer<Int>>()
|
||||
val clearCacheAction = mock<Consumer<String>>()
|
||||
mFlagManager.clearCacheAction = clearCacheAction
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener)
|
||||
val observer = withArgCaptor<ContentObserver> {
|
||||
verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture())
|
||||
}
|
||||
observer.onChange(false, flagUri(1))
|
||||
verify(clearCacheAction).accept(eq(1))
|
||||
verify(clearCacheAction).accept(eq("1"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,14 +110,14 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
|
||||
verify(listener1).onFlagChanged(capture())
|
||||
}
|
||||
assertThat(flagEvent1.flagId).isEqualTo(1)
|
||||
assertThat(flagEvent1.flagName).isEqualTo("1")
|
||||
verifyNoMoreInteractions(listener1, listener10)
|
||||
|
||||
observer.onChange(false, flagUri(10))
|
||||
val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> {
|
||||
verify(listener10).onFlagChanged(capture())
|
||||
}
|
||||
assertThat(flagEvent10.flagId).isEqualTo(10)
|
||||
assertThat(flagEvent10.flagName).isEqualTo("10")
|
||||
verifyNoMoreInteractions(listener1, listener10)
|
||||
}
|
||||
|
||||
@@ -130,18 +130,18 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1)
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10)
|
||||
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, null)
|
||||
mFlagManager.dispatchListenersAndMaybeRestart("1", null)
|
||||
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
|
||||
verify(listener1).onFlagChanged(capture())
|
||||
}
|
||||
assertThat(flagEvent1.flagId).isEqualTo(1)
|
||||
assertThat(flagEvent1.flagName).isEqualTo("1")
|
||||
verifyNoMoreInteractions(listener1, listener10)
|
||||
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(10, null)
|
||||
mFlagManager.dispatchListenersAndMaybeRestart("10", null)
|
||||
val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> {
|
||||
verify(listener10).onFlagChanged(capture())
|
||||
}
|
||||
assertThat(flagEvent10.flagId).isEqualTo(10)
|
||||
assertThat(flagEvent10.flagName).isEqualTo("10")
|
||||
verifyNoMoreInteractions(listener1, listener10)
|
||||
}
|
||||
|
||||
@@ -151,25 +151,25 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener)
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener)
|
||||
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, null)
|
||||
mFlagManager.dispatchListenersAndMaybeRestart("1", null)
|
||||
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
|
||||
verify(listener).onFlagChanged(capture())
|
||||
}
|
||||
assertThat(flagEvent1.flagId).isEqualTo(1)
|
||||
assertThat(flagEvent1.flagName).isEqualTo("1")
|
||||
verifyNoMoreInteractions(listener)
|
||||
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(10, null)
|
||||
mFlagManager.dispatchListenersAndMaybeRestart("10", null)
|
||||
val flagEvent10 = withArgCaptor<FlagListenable.FlagEvent> {
|
||||
verify(listener, times(2)).onFlagChanged(capture())
|
||||
}
|
||||
assertThat(flagEvent10.flagId).isEqualTo(10)
|
||||
assertThat(flagEvent10.flagName).isEqualTo("10")
|
||||
verifyNoMoreInteractions(listener)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRestartWithNoListeners() {
|
||||
val restartAction = mock<Consumer<Boolean>>()
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
|
||||
mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
|
||||
verify(restartAction).accept(eq(false))
|
||||
verifyNoMoreInteractions(restartAction)
|
||||
}
|
||||
@@ -180,7 +180,7 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test")) { event ->
|
||||
event.requestNoRestart()
|
||||
}
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
|
||||
mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
|
||||
verify(restartAction).accept(eq(true))
|
||||
verifyNoMoreInteractions(restartAction)
|
||||
}
|
||||
@@ -191,7 +191,7 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event ->
|
||||
event.requestNoRestart()
|
||||
}
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
|
||||
mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
|
||||
verify(restartAction).accept(eq(false))
|
||||
verifyNoMoreInteractions(restartAction)
|
||||
}
|
||||
@@ -205,7 +205,7 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test")) {
|
||||
// do not request
|
||||
}
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
|
||||
mFlagManager.dispatchListenersAndMaybeRestart("1", restartAction)
|
||||
verify(restartAction).accept(eq(false))
|
||||
verifyNoMoreInteractions(restartAction)
|
||||
}
|
||||
@@ -214,31 +214,31 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
fun testReadBooleanFlag() {
|
||||
// test that null string returns 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
|
||||
whenever(mFlagSettingsHelper.getString(any())).thenReturn("")
|
||||
assertThat(mFlagManager.readFlagValue(1, BooleanFlagSerializer)).isNull()
|
||||
assertThat(mFlagManager.readFlagValue("1", BooleanFlagSerializer)).isNull()
|
||||
|
||||
// test false
|
||||
whenever(mFlagSettingsHelper.getString(any()))
|
||||
.thenReturn("{\"type\":\"boolean\",\"value\":false}")
|
||||
assertThat(mFlagManager.readFlagValue(1, BooleanFlagSerializer)).isFalse()
|
||||
assertThat(mFlagManager.readFlagValue("1", BooleanFlagSerializer)).isFalse()
|
||||
|
||||
// test true
|
||||
whenever(mFlagSettingsHelper.getString(any()))
|
||||
.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
|
||||
whenever(mFlagSettingsHelper.getString(any()))
|
||||
.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
|
||||
assertThrows(InvalidFlagStorageException::class.java) {
|
||||
whenever(mFlagSettingsHelper.getString(any())).thenReturn("1")
|
||||
mFlagManager.readFlagValue(1, BooleanFlagSerializer)
|
||||
mFlagManager.readFlagValue("1", BooleanFlagSerializer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,31 +257,31 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
fun testReadStringFlag() {
|
||||
// test that null string returns 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
|
||||
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
|
||||
whenever(mFlagSettingsHelper.getString(any()))
|
||||
.thenReturn("{\"type\":\"string\",\"value\":\"\"}")
|
||||
assertThat(mFlagManager.readFlagValue(1, StringFlagSerializer)).isEqualTo("")
|
||||
assertThat(mFlagManager.readFlagValue("1", StringFlagSerializer)).isEqualTo("")
|
||||
|
||||
// test string with value is returned
|
||||
whenever(mFlagSettingsHelper.getString(any()))
|
||||
.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
|
||||
whenever(mFlagSettingsHelper.getString(any()))
|
||||
.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
|
||||
assertThrows(InvalidFlagStorageException::class.java) {
|
||||
whenever(mFlagSettingsHelper.getString(any())).thenReturn("1")
|
||||
mFlagManager.readFlagValue(1, StringFlagSerializer)
|
||||
mFlagManager.readFlagValue("1", StringFlagSerializer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
|
||||
notifyFlagChanged(flag)
|
||||
@@ -73,7 +67,7 @@ class FakeFeatureFlags : FeatureFlags {
|
||||
listeners.forEach { listener ->
|
||||
listener.onFlagChanged(
|
||||
object : FlagListenable.FlagEvent {
|
||||
override val flagId = flag.id
|
||||
override val flagName = flag.name
|
||||
override fun requestNoRestart() {}
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user