Add server flag support to flags.

Bug: 249121873
Test: atest SystemUITests
Change-Id: I7fe0bd122cbcc3365abe7f4071a76a04783ff3d0
This commit is contained in:
Dave Mankoff
2022-10-27 20:47:12 +00:00
parent d825147525
commit 96c315ea7b
9 changed files with 102 additions and 133 deletions

View File

@@ -22,9 +22,19 @@ import android.annotation.StringRes
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
/**
* Base interface for flags that can change value on a running device.
* @property id unique id to help identify this flag. Must be unique. This will be removed soon.
* @property teamfood Set to true to include this flag as part of the teamfood flag. This will
* be removed soon.
* @property name Used for server-side flagging where appropriate. Also used for display. No spaces.
* @property namespace The server-side namespace that this flag lives under.
*/
interface Flag<T> { interface Flag<T> {
val id: Int val id: Int
val teamfood: Boolean val teamfood: Boolean
val name: String
val namespace: String
} }
interface ParcelableFlag<T> : Flag<T>, Parcelable { interface ParcelableFlag<T> : Flag<T>, Parcelable {
@@ -38,13 +48,10 @@ interface ResourceFlag<T> : Flag<T> {
} }
interface DeviceConfigFlag<T> : Flag<T> { interface DeviceConfigFlag<T> : Flag<T> {
val name: String
val namespace: String
val default: T val default: T
} }
interface SysPropFlag<T> : Flag<T> { interface SysPropFlag<T> : Flag<T> {
val name: String
val default: T val default: T
} }
@@ -57,6 +64,8 @@ interface SysPropFlag<T> : Flag<T> {
abstract class BooleanFlag constructor( abstract class BooleanFlag constructor(
override val id: Int, override val id: Int,
override val default: Boolean = false, override val default: Boolean = false,
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false, override val teamfood: Boolean = false,
override val overridden: Boolean = false override val overridden: Boolean = false
) : ParcelableFlag<Boolean> { ) : ParcelableFlag<Boolean> {
@@ -91,20 +100,24 @@ abstract class BooleanFlag constructor(
*/ */
data class UnreleasedFlag constructor( data class UnreleasedFlag constructor(
override val id: Int, override val id: Int,
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false, override val teamfood: Boolean = false,
override val overridden: Boolean = false override val overridden: Boolean = false
) : BooleanFlag(id, false, teamfood, overridden) ) : BooleanFlag(id, false, name, namespace, teamfood, overridden)
/** /**
* A Flag that is is true by default. * A Flag that is true by default.
* *
* It can be changed or overridden in any build, meaning it can be turned off if needed. * It can be changed or overridden in any build, meaning it can be turned off if needed.
*/ */
data class ReleasedFlag constructor( data class ReleasedFlag constructor(
override val id: Int, override val id: Int,
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false, override val teamfood: Boolean = false,
override val overridden: Boolean = false override val overridden: Boolean = false
) : BooleanFlag(id, true, teamfood, overridden) ) : BooleanFlag(id, true, name, namespace, teamfood, overridden)
/** /**
* A Flag that reads its default values from a resource overlay instead of code. * A Flag that reads its default values from a resource overlay instead of code.
@@ -114,6 +127,8 @@ data class ReleasedFlag constructor(
data class ResourceBooleanFlag constructor( data class ResourceBooleanFlag constructor(
override val id: Int, override val id: Int,
@BoolRes override val resourceId: Int, @BoolRes override val resourceId: Int,
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false override val teamfood: Boolean = false
) : ResourceFlag<Boolean> ) : ResourceFlag<Boolean>
@@ -142,7 +157,8 @@ data class DeviceConfigBooleanFlag constructor(
data class SysPropBooleanFlag constructor( data class SysPropBooleanFlag constructor(
override val id: Int, override val id: Int,
override val name: String, override val name: String,
override val default: Boolean = false override val default: Boolean = false,
override val namespace: String = ""
) : SysPropFlag<Boolean> { ) : SysPropFlag<Boolean> {
// TODO(b/223379190): Teamfood not supported for sysprop flags yet. // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
override val teamfood: Boolean = false override val teamfood: Boolean = false
@@ -151,6 +167,8 @@ data class SysPropBooleanFlag constructor(
data class StringFlag constructor( data class StringFlag constructor(
override val id: Int, override val id: Int,
override val default: String = "", override val default: String = "",
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false, override val teamfood: Boolean = false,
override val overridden: Boolean = false override val overridden: Boolean = false
) : ParcelableFlag<String> { ) : ParcelableFlag<String> {
@@ -176,12 +194,16 @@ data class StringFlag constructor(
data class ResourceStringFlag constructor( data class ResourceStringFlag constructor(
override val id: Int, override val id: Int,
@StringRes override val resourceId: Int, @StringRes override val resourceId: Int,
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false override val teamfood: Boolean = false
) : ResourceFlag<String> ) : ResourceFlag<String>
data class IntFlag constructor( data class IntFlag constructor(
override val id: Int, override val id: Int,
override val default: Int = 0, override val default: Int = 0,
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false, override val teamfood: Boolean = false,
override val overridden: Boolean = false override val overridden: Boolean = false
) : ParcelableFlag<Int> { ) : ParcelableFlag<Int> {
@@ -208,6 +230,8 @@ data class IntFlag constructor(
data class ResourceIntFlag constructor( data class ResourceIntFlag constructor(
override val id: Int, override val id: Int,
@IntegerRes override val resourceId: Int, @IntegerRes override val resourceId: Int,
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false override val teamfood: Boolean = false
) : ResourceFlag<Int> ) : ResourceFlag<Int>
@@ -215,6 +239,8 @@ data class LongFlag constructor(
override val id: Int, override val id: Int,
override val default: Long = 0, override val default: Long = 0,
override val teamfood: Boolean = false, override val teamfood: Boolean = false,
override val name: String = "",
override val namespace: String = "",
override val overridden: Boolean = false override val overridden: Boolean = false
) : ParcelableFlag<Long> { ) : ParcelableFlag<Long> {
@@ -240,6 +266,8 @@ data class LongFlag constructor(
data class FloatFlag constructor( data class FloatFlag constructor(
override val id: Int, override val id: Int,
override val default: Float = 0f, override val default: Float = 0f,
override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false, override val teamfood: Boolean = false,
override val overridden: Boolean = false override val overridden: Boolean = false
) : ParcelableFlag<Float> { ) : ParcelableFlag<Float> {
@@ -266,13 +294,17 @@ data class FloatFlag constructor(
data class ResourceFloatFlag constructor( data class ResourceFloatFlag constructor(
override val id: Int, override val id: Int,
override val resourceId: Int, override val resourceId: Int,
override val teamfood: Boolean = false override val name: String = "",
override val namespace: String = "",
override val teamfood: Boolean = false,
) : ResourceFlag<Int> ) : ResourceFlag<Int>
data class DoubleFlag constructor( data class DoubleFlag constructor(
override val id: Int, override val id: Int,
override val default: Double = 0.0, override val default: Double = 0.0,
override val teamfood: Boolean = false, override val teamfood: Boolean = false,
override val name: String = "",
override val namespace: String = "",
override val overridden: Boolean = false override val overridden: Boolean = false
) : ParcelableFlag<Double> { ) : ParcelableFlag<Double> {

View File

@@ -33,9 +33,6 @@ interface FeatureFlags : FlagListenable, Dumpable {
/** Returns a boolean value for the given flag. */ /** Returns a boolean value for the given flag. */
fun isEnabled(flag: ResourceBooleanFlag): Boolean fun isEnabled(flag: ResourceBooleanFlag): Boolean
/** Returns a boolean value for the given flag. */
fun isEnabled(flag: DeviceConfigBooleanFlag): Boolean
/** Returns a boolean value for the given flag. */ /** Returns a boolean value for the given flag. */
fun isEnabled(flag: SysPropBooleanFlag): Boolean fun isEnabled(flag: SysPropBooleanFlag): Boolean

View File

@@ -39,7 +39,6 @@ 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.DeviceConfigProxy;
import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.settings.SecureSettings;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -76,7 +75,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
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 DeviceConfigProxy mDeviceConfigProxy;
private final ServerFlagReader mServerFlagReader; private final ServerFlagReader mServerFlagReader;
private final Map<Integer, Flag<?>> mAllFlags; private final Map<Integer, Flag<?>> mAllFlags;
private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>(); private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
@@ -99,7 +97,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
SecureSettings secureSettings, SecureSettings secureSettings,
SystemPropertiesHelper systemProperties, SystemPropertiesHelper systemProperties,
@Main Resources resources, @Main Resources resources,
DeviceConfigProxy deviceConfigProxy,
ServerFlagReader serverFlagReader, ServerFlagReader serverFlagReader,
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags, @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
Restarter restarter) { Restarter restarter) {
@@ -108,7 +105,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
mSecureSettings = secureSettings; mSecureSettings = secureSettings;
mResources = resources; mResources = resources;
mSystemProperties = systemProperties; mSystemProperties = systemProperties;
mDeviceConfigProxy = deviceConfigProxy;
mServerFlagReader = serverFlagReader; mServerFlagReader = serverFlagReader;
mAllFlags = allFlags; mAllFlags = allFlags;
mRestarter = restarter; mRestarter = restarter;
@@ -140,7 +136,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
int id = flag.getId(); int id = flag.getId();
if (!mBooleanFlagCache.containsKey(id)) { if (!mBooleanFlagCache.containsKey(id)) {
mBooleanFlagCache.put(id, mBooleanFlagCache.put(id,
readFlagValue(id, flag.getDefault())); readBooleanFlagInternal(flag, flag.getDefault()));
} }
return mBooleanFlagCache.get(id); return mBooleanFlagCache.get(id);
@@ -151,19 +147,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
int id = flag.getId(); int id = flag.getId();
if (!mBooleanFlagCache.containsKey(id)) { if (!mBooleanFlagCache.containsKey(id)) {
mBooleanFlagCache.put(id, mBooleanFlagCache.put(id,
readFlagValue(id, mResources.getBoolean(flag.getResourceId()))); readBooleanFlagInternal(flag, mResources.getBoolean(flag.getResourceId())));
}
return mBooleanFlagCache.get(id);
}
@Override
public boolean isEnabled(@NonNull DeviceConfigBooleanFlag flag) {
int id = flag.getId();
if (!mBooleanFlagCache.containsKey(id)) {
boolean deviceConfigValue = mDeviceConfigProxy.getBoolean(flag.getNamespace(),
flag.getName(), flag.getDefault());
mBooleanFlagCache.put(id, readFlagValue(id, deviceConfigValue));
} }
return mBooleanFlagCache.get(id); return mBooleanFlagCache.get(id);
@@ -179,7 +163,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
id, id,
mSystemProperties.getBoolean( mSystemProperties.getBoolean(
flag.getName(), flag.getName(),
readFlagValue(id, flag.getDefault()))); readBooleanFlagInternal(flag, flag.getDefault())));
} }
return mBooleanFlagCache.get(id); return mBooleanFlagCache.get(id);
@@ -191,7 +175,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
int id = flag.getId(); int id = flag.getId();
if (!mStringFlagCache.containsKey(id)) { if (!mStringFlagCache.containsKey(id)) {
mStringFlagCache.put(id, mStringFlagCache.put(id,
readFlagValue(id, flag.getDefault(), StringFlagSerializer.INSTANCE)); readFlagValueInternal(id, flag.getDefault(), StringFlagSerializer.INSTANCE));
} }
return mStringFlagCache.get(id); return mStringFlagCache.get(id);
@@ -203,20 +187,21 @@ public class FeatureFlagsDebug implements FeatureFlags {
int id = flag.getId(); int id = flag.getId();
if (!mStringFlagCache.containsKey(id)) { if (!mStringFlagCache.containsKey(id)) {
mStringFlagCache.put(id, mStringFlagCache.put(id,
readFlagValue(id, mResources.getString(flag.getResourceId()), readFlagValueInternal(id, mResources.getString(flag.getResourceId()),
StringFlagSerializer.INSTANCE)); StringFlagSerializer.INSTANCE));
} }
return mStringFlagCache.get(id); return mStringFlagCache.get(id);
} }
@NonNull @NonNull
@Override @Override
public int getInt(@NonNull IntFlag flag) { public int getInt(@NonNull IntFlag flag) {
int id = flag.getId(); int id = flag.getId();
if (!mIntFlagCache.containsKey(id)) { if (!mIntFlagCache.containsKey(id)) {
mIntFlagCache.put(id, mIntFlagCache.put(id,
readFlagValue(id, flag.getDefault(), IntFlagSerializer.INSTANCE)); readFlagValueInternal(id, flag.getDefault(), IntFlagSerializer.INSTANCE));
} }
return mIntFlagCache.get(id); return mIntFlagCache.get(id);
@@ -228,27 +213,31 @@ public class FeatureFlagsDebug implements FeatureFlags {
int id = flag.getId(); int id = flag.getId();
if (!mIntFlagCache.containsKey(id)) { if (!mIntFlagCache.containsKey(id)) {
mIntFlagCache.put(id, mIntFlagCache.put(id,
readFlagValue(id, mResources.getInteger(flag.getResourceId()), readFlagValueInternal(id, mResources.getInteger(flag.getResourceId()),
IntFlagSerializer.INSTANCE)); IntFlagSerializer.INSTANCE));
} }
return mIntFlagCache.get(id); return mIntFlagCache.get(id);
} }
/** Specific override for Boolean flags that checks against the teamfood list. */ /** Specific override for Boolean flags that checks against the teamfood list.*/
private boolean readFlagValue(int id, boolean defaultValue) { private boolean readBooleanFlagInternal(Flag<Boolean> flag, boolean defaultValue) {
Boolean result = readBooleanFlagOverride(id); Boolean result = readBooleanFlagOverride(flag.getId());
boolean hasServerOverride = mServerFlagReader.hasOverride(id); boolean hasServerOverride = mServerFlagReader.hasOverride(
flag.getNamespace(), flag.getName());
// Only check for teamfood if the default is false // Only check for teamfood if the default is false
// and there is no server override. // and there is no server override.
if (!hasServerOverride && !defaultValue && result == null && id != Flags.TEAMFOOD.getId()) { if (!hasServerOverride
if (mAllFlags.containsKey(id) && mAllFlags.get(id).getTeamfood()) { && !defaultValue
&& result == null
&& flag.getId() != Flags.TEAMFOOD.getId()
&& flag.getTeamfood()) {
return isEnabled(Flags.TEAMFOOD); return isEnabled(Flags.TEAMFOOD);
} }
}
return result == null ? mServerFlagReader.readServerOverride(id, defaultValue) : result; return result == null ? mServerFlagReader.readServerOverride(
flag.getNamespace(), flag.getName(), defaultValue) : result;
} }
private Boolean readBooleanFlagOverride(int id) { private Boolean readBooleanFlagOverride(int id) {
@@ -256,7 +245,8 @@ public class FeatureFlagsDebug implements FeatureFlags {
} }
@NonNull @NonNull
private <T> T readFlagValue(int id, @NonNull T defaultValue, FlagSerializer<T> serializer) { private <T> T readFlagValueInternal(
int id, @NonNull T defaultValue, FlagSerializer<T> serializer) {
requireNonNull(defaultValue, "defaultValue"); requireNonNull(defaultValue, "defaultValue");
T result = readFlagValueInternal(id, serializer); T result = readFlagValueInternal(id, serializer);
return result == null ? defaultValue : result; return result == null ? defaultValue : result;
@@ -355,8 +345,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
} else if (flag instanceof ResourceBooleanFlag) { } else if (flag instanceof ResourceBooleanFlag) {
setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE); setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
} else if (flag instanceof DeviceConfigBooleanFlag) {
setFlagValue(flag.getId(), 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);
@@ -474,9 +462,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
} 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.getId()) != null;
} else if (f instanceof DeviceConfigBooleanFlag) {
enabled = isEnabled((DeviceConfigBooleanFlag) f);
overridden = false;
} 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);
@@ -489,9 +474,11 @@ public class FeatureFlagsDebug implements FeatureFlags {
} }
if (enabled) { if (enabled) {
return new ReleasedFlag(f.getId(), teamfood, overridden); return new ReleasedFlag(
f.getId(), f.getName(), f.getNamespace(), teamfood, overridden);
} else { } else {
return new UnreleasedFlag(f.getId(), teamfood, overridden); return new UnreleasedFlag(
f.getId(), f.getName(), f.getNamespace(), teamfood, overridden);
} }
} }
}; };

View File

@@ -101,7 +101,7 @@ public class FeatureFlagsRelease implements FeatureFlags {
@Override @Override
public boolean isEnabled(@NotNull ReleasedFlag flag) { public boolean isEnabled(@NotNull ReleasedFlag flag) {
return mServerFlagReader.readServerOverride(flag.getId(), true); return mServerFlagReader.readServerOverride(flag.getNamespace(), flag.getName(), true);
} }
@Override @Override
@@ -114,18 +114,6 @@ public class FeatureFlagsRelease implements FeatureFlags {
return mBooleanCache.valueAt(cacheIndex); return mBooleanCache.valueAt(cacheIndex);
} }
@Override
public boolean isEnabled(@NonNull DeviceConfigBooleanFlag flag) {
int cacheIndex = mBooleanCache.indexOfKey(flag.getId());
if (cacheIndex < 0) {
boolean deviceConfigValue = mDeviceConfigProxy.getBoolean(flag.getNamespace(),
flag.getName(), flag.getDefault());
return isEnabled(flag.getId(), deviceConfigValue);
}
return mBooleanCache.valueAt(cacheIndex);
}
@Override @Override
public boolean isEnabled(SysPropBooleanFlag flag) { public boolean isEnabled(SysPropBooleanFlag flag) {
int cacheIndex = mBooleanCache.indexOfKey(flag.getId()); int cacheIndex = mBooleanCache.indexOfKey(flag.getId());

View File

@@ -264,11 +264,10 @@ object Flags {
@Keep @Keep
@JvmField @JvmField
val WM_ENABLE_PARTIAL_SCREEN_SHARING = val WM_ENABLE_PARTIAL_SCREEN_SHARING =
DeviceConfigBooleanFlag( UnreleasedFlag(
1102, 1102,
"record_task_content", name = "record_task_content",
DeviceConfig.NAMESPACE_WINDOW_MANAGER, namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER,
false,
teamfood = true teamfood = true
) )

View File

@@ -27,11 +27,10 @@ import javax.inject.Inject
interface ServerFlagReader { interface ServerFlagReader {
/** Returns true if there is a server-side setting stored. */ /** Returns true if there is a server-side setting stored. */
fun hasOverride(flagId: Int): Boolean fun hasOverride(namespace: String, name: String): Boolean
/** Returns any stored server-side setting or the default if not set. */ /** Returns any stored server-side setting or the default if not set. */
fun readServerOverride(flagId: Int, default: Boolean): Boolean fun readServerOverride(namespace: String, name: String, default: Boolean): Boolean
/** Register a listener for changes to any of the passed in flags. */ /** Register a listener for changes to any of the passed in flags. */
fun listenForChanges(values: Collection<Flag<*>>, listener: ChangeListener) fun listenForChanges(values: Collection<Flag<*>>, listener: ChangeListener)
@@ -68,19 +67,19 @@ class ServerFlagReaderImpl @Inject constructor(
} }
} }
override fun hasOverride(flagId: Int): Boolean = override fun hasOverride(namespace: String, name: String): Boolean =
deviceConfig.getProperty( !namespace.isBlank() && !name.isBlank() && deviceConfig.getProperty(
namespace, namespace,
getServerOverrideName(flagId) name
) != null ) != null
override fun readServerOverride(flagId: Int, default: Boolean): Boolean {
return deviceConfig.getBoolean( override fun readServerOverride(namespace: String, name: String, default: Boolean): Boolean =
!namespace.isBlank() && !name.isBlank() && deviceConfig.getBoolean(
namespace, namespace,
getServerOverrideName(flagId), name,
default default
) )
}
override fun listenForChanges( override fun listenForChanges(
flags: Collection<Flag<*>>, flags: Collection<Flag<*>>,
@@ -121,24 +120,24 @@ interface ServerFlagReaderModule {
} }
class ServerFlagReaderFake : ServerFlagReader { class ServerFlagReaderFake : ServerFlagReader {
private val flagMap: MutableMap<Int, Boolean> = mutableMapOf() private val flagMap: MutableMap<String, Boolean> = mutableMapOf()
private val listeners = private val listeners =
mutableListOf<Pair<ServerFlagReader.ChangeListener, Collection<Flag<*>>>>() mutableListOf<Pair<ServerFlagReader.ChangeListener, Collection<Flag<*>>>>()
override fun hasOverride(flagId: Int): Boolean { override fun hasOverride(namespace: String, name: String): Boolean {
return flagMap.containsKey(flagId) return flagMap.containsKey(name)
} }
override fun readServerOverride(flagId: Int, default: Boolean): Boolean { override fun readServerOverride(namespace: String, name: String, default: Boolean): Boolean {
return flagMap.getOrDefault(flagId, default) return flagMap.getOrDefault(name, default)
} }
fun setFlagValue(flagId: Int, value: Boolean) { fun setFlagValue(namespace: String, name: String, value: Boolean) {
flagMap.put(flagId, value) flagMap.put(name, value)
for ((listener, flags) in listeners) { for ((listener, flags) in listeners) {
flagLoop@ for (flag in flags) { flagLoop@ for (flag in flags) {
if (flagId == flag.id) { if (name == flag.name) {
listener.onChange() listener.onChange()
break@flagLoop break@flagLoop
} }
@@ -146,8 +145,8 @@ class ServerFlagReaderFake : ServerFlagReader {
} }
} }
fun eraseFlag(flagId: Int) { fun eraseFlag(namespace: String, name: String) {
flagMap.remove(flagId) flagMap.remove(name)
} }
override fun listenForChanges( override fun listenForChanges(

View File

@@ -31,10 +31,6 @@ 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.SecureSettings import com.android.systemui.util.settings.SecureSettings
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import java.io.PrintWriter
import java.io.Serializable
import java.io.StringWriter
import java.util.function.Consumer
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@@ -46,8 +42,12 @@ import org.mockito.Mockito.inOrder
import org.mockito.Mockito.times import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
import java.io.PrintWriter
import java.io.Serializable
import java.io.StringWriter
import java.util.function.Consumer
import org.mockito.Mockito.`when` as whenever
/** /**
* NOTE: This test is for the version of FeatureFlagManager in src-debug, which allows overriding * NOTE: This test is for the version of FeatureFlagManager in src-debug, which allows overriding
@@ -70,8 +70,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
private val serverFlagReader = ServerFlagReaderFake() private val serverFlagReader = ServerFlagReaderFake()
private val deviceConfig = DeviceConfigProxyFake() private val deviceConfig = DeviceConfigProxyFake()
private val teamfoodableFlagA = UnreleasedFlag(500, true) private val teamfoodableFlagA = UnreleasedFlag(500, teamfood = true)
private val teamfoodableFlagB = ReleasedFlag(501, true) private val teamfoodableFlagB = ReleasedFlag(501, teamfood = true)
@Before @Before
fun setup() { fun setup() {
@@ -84,7 +84,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
secureSettings, secureSettings,
systemProperties, systemProperties,
resources, resources,
deviceConfig,
serverFlagReader, serverFlagReader,
flagMap, flagMap,
restarter restarter
@@ -191,21 +190,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e"))).isFalse() assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e"))).isFalse()
} }
@Test
fun readDeviceConfigBooleanFlag() {
val namespace = "test_namespace"
deviceConfig.setProperty(namespace, "a", "true", false)
deviceConfig.setProperty(namespace, "b", "false", false)
deviceConfig.setProperty(namespace, "c", null, false)
assertThat(mFeatureFlagsDebug.isEnabled(DeviceConfigBooleanFlag(1, "a", namespace)))
.isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(DeviceConfigBooleanFlag(2, "b", namespace)))
.isFalse()
assertThat(mFeatureFlagsDebug.isEnabled(DeviceConfigBooleanFlag(3, "c", namespace)))
.isFalse()
}
@Test @Test
fun readStringFlag() { fun readStringFlag() {
whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo") whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo")
@@ -379,7 +363,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
fun serverSide_Overrides_MakesFalse() { fun serverSide_Overrides_MakesFalse() {
val flag = ReleasedFlag(100) val flag = ReleasedFlag(100)
serverFlagReader.setFlagValue(flag.id, false) serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
assertThat(mFeatureFlagsDebug.isEnabled(flag)).isFalse() assertThat(mFeatureFlagsDebug.isEnabled(flag)).isFalse()
} }
@@ -388,7 +372,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
fun serverSide_Overrides_MakesTrue() { fun serverSide_Overrides_MakesTrue() {
val flag = UnreleasedFlag(100) val flag = UnreleasedFlag(100)
serverFlagReader.setFlagValue(flag.id, true) serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
assertThat(mFeatureFlagsDebug.isEnabled(flag)).isTrue() assertThat(mFeatureFlagsDebug.isEnabled(flag)).isTrue()
} }

View File

@@ -25,8 +25,8 @@ import org.junit.Assert.assertThrows
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
/** /**
* NOTE: This test is for the version of FeatureFlagManager in src-release, which should not allow * NOTE: This test is for the version of FeatureFlagManager in src-release, which should not allow
@@ -82,21 +82,6 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
} }
} }
@Test
fun testReadDeviceConfigBooleanFlag() {
val namespace = "test_namespace"
deviceConfig.setProperty(namespace, "a", "true", false)
deviceConfig.setProperty(namespace, "b", "false", false)
deviceConfig.setProperty(namespace, "c", null, false)
assertThat(mFeatureFlagsRelease.isEnabled(DeviceConfigBooleanFlag(1, "a", namespace)))
.isTrue()
assertThat(mFeatureFlagsRelease.isEnabled(DeviceConfigBooleanFlag(2, "b", namespace)))
.isFalse()
assertThat(mFeatureFlagsRelease.isEnabled(DeviceConfigBooleanFlag(3, "c", namespace)))
.isFalse()
}
@Test @Test
fun testSysPropBooleanFlag() { fun testSysPropBooleanFlag() {
val flagId = 213 val flagId = 213
@@ -112,7 +97,7 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
fun serverSide_OverridesReleased_MakesFalse() { fun serverSide_OverridesReleased_MakesFalse() {
val flag = ReleasedFlag(100) val flag = ReleasedFlag(100)
serverFlagReader.setFlagValue(flag.id, false) serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse() assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse()
} }
@@ -121,7 +106,7 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
fun serverSide_OverridesUnreleased_Ignored() { fun serverSide_OverridesUnreleased_Ignored() {
val flag = UnreleasedFlag(100) val flag = UnreleasedFlag(100)
serverFlagReader.setFlagValue(flag.id, true) serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse() assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse()
} }

View File

@@ -87,8 +87,6 @@ class FakeFeatureFlags : FeatureFlags {
override fun isEnabled(flag: ResourceBooleanFlag): Boolean = requireBooleanValue(flag.id) override fun isEnabled(flag: ResourceBooleanFlag): Boolean = requireBooleanValue(flag.id)
override fun isEnabled(flag: DeviceConfigBooleanFlag): Boolean = requireBooleanValue(flag.id)
override fun isEnabled(flag: SysPropBooleanFlag): Boolean = requireBooleanValue(flag.id) override fun isEnabled(flag: SysPropBooleanFlag): Boolean = requireBooleanValue(flag.id)
override fun getString(flag: StringFlag): String = requireStringValue(flag.id) override fun getString(flag: StringFlag): String = requireStringValue(flag.id)