Merge changes I29bf2065,Ic858826c,I7fe0bd12 into tm-qpr-dev
* changes: Define server flag names for all existing flags. RESTRICT AUTOMERGE Resynchronize QPR flags with Main Add server flag support to flags.
This commit is contained in:
@@ -116,7 +116,6 @@ android_library {
|
||||
"androidx.exifinterface_exifinterface",
|
||||
"androidx.test.ext.junit",
|
||||
"com.google.android.material_material",
|
||||
"kotlin-reflect",
|
||||
"kotlinx_coroutines_android",
|
||||
"kotlinx_coroutines",
|
||||
"iconloader_base",
|
||||
|
||||
@@ -22,9 +22,19 @@ import android.annotation.StringRes
|
||||
import android.os.Parcel
|
||||
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> {
|
||||
val id: Int
|
||||
val teamfood: Boolean
|
||||
val name: String
|
||||
val namespace: String
|
||||
}
|
||||
|
||||
interface ParcelableFlag<T> : Flag<T>, Parcelable {
|
||||
@@ -38,13 +48,10 @@ interface ResourceFlag<T> : Flag<T> {
|
||||
}
|
||||
|
||||
interface DeviceConfigFlag<T> : Flag<T> {
|
||||
val name: String
|
||||
val namespace: String
|
||||
val default: T
|
||||
}
|
||||
|
||||
interface SysPropFlag<T> : Flag<T> {
|
||||
val name: String
|
||||
val default: T
|
||||
}
|
||||
|
||||
@@ -56,6 +63,8 @@ interface SysPropFlag<T> : Flag<T> {
|
||||
// Consider using the "parcelize" kotlin library.
|
||||
abstract class BooleanFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val default: Boolean = false,
|
||||
override val teamfood: Boolean = false,
|
||||
override val overridden: Boolean = false
|
||||
@@ -71,6 +80,8 @@ abstract class BooleanFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
default = parcel.readBoolean(),
|
||||
teamfood = parcel.readBoolean(),
|
||||
overridden = parcel.readBoolean()
|
||||
@@ -78,6 +89,8 @@ abstract class BooleanFlag constructor(
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(id)
|
||||
parcel.writeString(name)
|
||||
parcel.writeString(namespace)
|
||||
parcel.writeBoolean(default)
|
||||
parcel.writeBoolean(teamfood)
|
||||
parcel.writeBoolean(overridden)
|
||||
@@ -91,20 +104,24 @@ abstract class BooleanFlag constructor(
|
||||
*/
|
||||
data class UnreleasedFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val teamfood: Boolean = false,
|
||||
override val overridden: Boolean = false
|
||||
) : BooleanFlag(id, false, teamfood, overridden)
|
||||
) : BooleanFlag(id, name, namespace, false, 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.
|
||||
*/
|
||||
data class ReleasedFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val teamfood: Boolean = false,
|
||||
override val overridden: Boolean = false
|
||||
) : BooleanFlag(id, true, teamfood, overridden)
|
||||
) : BooleanFlag(id, name, namespace, true, teamfood, overridden)
|
||||
|
||||
/**
|
||||
* A Flag that reads its default values from a resource overlay instead of code.
|
||||
@@ -113,6 +130,8 @@ data class ReleasedFlag constructor(
|
||||
*/
|
||||
data class ResourceBooleanFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
@BoolRes override val resourceId: Int,
|
||||
override val teamfood: Boolean = false
|
||||
) : ResourceFlag<Boolean>
|
||||
@@ -142,7 +161,8 @@ data class DeviceConfigBooleanFlag constructor(
|
||||
data class SysPropBooleanFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val default: Boolean = false
|
||||
override val namespace: String,
|
||||
override val default: Boolean = false,
|
||||
) : SysPropFlag<Boolean> {
|
||||
// TODO(b/223379190): Teamfood not supported for sysprop flags yet.
|
||||
override val teamfood: Boolean = false
|
||||
@@ -150,6 +170,8 @@ data class SysPropBooleanFlag constructor(
|
||||
|
||||
data class StringFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val default: String = "",
|
||||
override val teamfood: Boolean = false,
|
||||
override val overridden: Boolean = false
|
||||
@@ -164,23 +186,31 @@ data class StringFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
default = parcel.readString() ?: ""
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(id)
|
||||
parcel.writeString(name)
|
||||
parcel.writeString(namespace)
|
||||
parcel.writeString(default)
|
||||
}
|
||||
}
|
||||
|
||||
data class ResourceStringFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
@StringRes override val resourceId: Int,
|
||||
override val teamfood: Boolean = false
|
||||
) : ResourceFlag<String>
|
||||
|
||||
data class IntFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val default: Int = 0,
|
||||
override val teamfood: Boolean = false,
|
||||
override val overridden: Boolean = false
|
||||
@@ -196,17 +226,23 @@ data class IntFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
default = parcel.readInt()
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(id)
|
||||
parcel.writeString(name)
|
||||
parcel.writeString(namespace)
|
||||
parcel.writeInt(default)
|
||||
}
|
||||
}
|
||||
|
||||
data class ResourceIntFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
@IntegerRes override val resourceId: Int,
|
||||
override val teamfood: Boolean = false
|
||||
) : ResourceFlag<Int>
|
||||
@@ -215,6 +251,8 @@ data class LongFlag constructor(
|
||||
override val id: Int,
|
||||
override val default: Long = 0,
|
||||
override val teamfood: Boolean = false,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val overridden: Boolean = false
|
||||
) : ParcelableFlag<Long> {
|
||||
|
||||
@@ -228,17 +266,23 @@ data class LongFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
default = parcel.readLong()
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(id)
|
||||
parcel.writeString(name)
|
||||
parcel.writeString(namespace)
|
||||
parcel.writeLong(default)
|
||||
}
|
||||
}
|
||||
|
||||
data class FloatFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val default: Float = 0f,
|
||||
override val teamfood: Boolean = false,
|
||||
override val overridden: Boolean = false
|
||||
@@ -254,23 +298,31 @@ data class FloatFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
default = parcel.readFloat()
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(id)
|
||||
parcel.writeString(name)
|
||||
parcel.writeString(namespace)
|
||||
parcel.writeFloat(default)
|
||||
}
|
||||
}
|
||||
|
||||
data class ResourceFloatFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val resourceId: Int,
|
||||
override val teamfood: Boolean = false
|
||||
override val teamfood: Boolean = false,
|
||||
) : ResourceFlag<Int>
|
||||
|
||||
data class DoubleFlag constructor(
|
||||
override val id: Int,
|
||||
override val name: String,
|
||||
override val namespace: String,
|
||||
override val default: Double = 0.0,
|
||||
override val teamfood: Boolean = false,
|
||||
override val overridden: Boolean = false
|
||||
@@ -286,11 +338,15 @@ data class DoubleFlag constructor(
|
||||
|
||||
private constructor(parcel: Parcel) : this(
|
||||
id = parcel.readInt(),
|
||||
name = parcel.readString(),
|
||||
namespace = parcel.readString(),
|
||||
default = parcel.readDouble()
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeInt(id)
|
||||
parcel.writeString(name)
|
||||
parcel.writeString(namespace)
|
||||
parcel.writeDouble(default)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.flags
|
||||
|
||||
import android.annotation.BoolRes
|
||||
|
||||
object FlagsFactory {
|
||||
private val flagMap = mutableMapOf<String, Flag<*>>()
|
||||
|
||||
val knownFlags: Map<String, Flag<*>>
|
||||
get() = flagMap
|
||||
|
||||
fun unreleasedFlag(
|
||||
id: Int,
|
||||
name: String,
|
||||
namespace: String = "systemui",
|
||||
teamfood: Boolean = false
|
||||
): UnreleasedFlag {
|
||||
val flag = UnreleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood)
|
||||
FlagsFactory.checkForDupesAndAdd(flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
fun releasedFlag(
|
||||
id: Int,
|
||||
name: String,
|
||||
namespace: String = "systemui",
|
||||
teamfood: Boolean = false
|
||||
): ReleasedFlag {
|
||||
val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood)
|
||||
FlagsFactory.checkForDupesAndAdd(flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
fun resourceBooleanFlag(
|
||||
id: Int,
|
||||
@BoolRes resourceId: Int,
|
||||
name: String,
|
||||
namespace: String = "systemui",
|
||||
teamfood: Boolean = false
|
||||
): ResourceBooleanFlag {
|
||||
val flag =
|
||||
ResourceBooleanFlag(
|
||||
id = id,
|
||||
name = name,
|
||||
namespace = namespace,
|
||||
resourceId = resourceId,
|
||||
teamfood = teamfood
|
||||
)
|
||||
FlagsFactory.checkForDupesAndAdd(flag)
|
||||
return flag
|
||||
}
|
||||
|
||||
fun sysPropBooleanFlag(
|
||||
id: Int,
|
||||
name: String,
|
||||
namespace: String = "systemui",
|
||||
default: Boolean = false
|
||||
): SysPropBooleanFlag {
|
||||
val flag =
|
||||
SysPropBooleanFlag(id = id, name = name, namespace = "systemui", default = default)
|
||||
FlagsFactory.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")
|
||||
}
|
||||
}
|
||||
flagMap[flag.name] = flag
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.flags
|
||||
|
||||
import android.annotation.BoolRes
|
||||
|
||||
object FlagsFactory {
|
||||
private val flagMap = mutableMapOf<String, Flag<*>>()
|
||||
|
||||
val knownFlags: Map<String, Flag<*>>
|
||||
get() = flagMap
|
||||
|
||||
fun unreleasedFlag(
|
||||
id: Int,
|
||||
name: String,
|
||||
namespace: String = "systemui",
|
||||
teamfood: Boolean = false
|
||||
): UnreleasedFlag {
|
||||
// Unreleased flags are always false in this build.
|
||||
val flag = UnreleasedFlag(id = id, name = "", namespace = "", teamfood = false)
|
||||
return flag
|
||||
}
|
||||
|
||||
fun releasedFlag(
|
||||
id: Int,
|
||||
name: String,
|
||||
namespace: String = "systemui",
|
||||
teamfood: Boolean = false
|
||||
): ReleasedFlag {
|
||||
val flag = ReleasedFlag(id = id, name = name, namespace = namespace, teamfood = teamfood)
|
||||
flagMap[name] = flag
|
||||
return flag
|
||||
}
|
||||
|
||||
fun resourceBooleanFlag(
|
||||
id: Int,
|
||||
@BoolRes resourceId: Int,
|
||||
name: String,
|
||||
namespace: String = "systemui",
|
||||
teamfood: Boolean = false
|
||||
): ResourceBooleanFlag {
|
||||
val flag =
|
||||
ResourceBooleanFlag(
|
||||
id = id,
|
||||
name = name,
|
||||
namespace = namespace,
|
||||
resourceId = resourceId,
|
||||
teamfood = teamfood
|
||||
)
|
||||
flagMap[name] = flag
|
||||
return flag
|
||||
}
|
||||
|
||||
fun sysPropBooleanFlag(
|
||||
id: Int,
|
||||
name: String,
|
||||
namespace: String = "systemui",
|
||||
default: Boolean = false
|
||||
): SysPropBooleanFlag {
|
||||
val flag =
|
||||
SysPropBooleanFlag(id = id, name = name, namespace = namespace, default = default)
|
||||
flagMap[name] = flag
|
||||
return flag
|
||||
}
|
||||
}
|
||||
@@ -33,9 +33,6 @@ interface FeatureFlags : FlagListenable, Dumpable {
|
||||
/** Returns a boolean value for the given flag. */
|
||||
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. */
|
||||
fun isEnabled(flag: SysPropBooleanFlag): Boolean
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.util.DeviceConfigProxy;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -76,7 +75,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
private final SecureSettings mSecureSettings;
|
||||
private final Resources mResources;
|
||||
private final SystemPropertiesHelper mSystemProperties;
|
||||
private final DeviceConfigProxy mDeviceConfigProxy;
|
||||
private final ServerFlagReader mServerFlagReader;
|
||||
private final Map<Integer, Flag<?>> mAllFlags;
|
||||
private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
|
||||
@@ -99,7 +97,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
SecureSettings secureSettings,
|
||||
SystemPropertiesHelper systemProperties,
|
||||
@Main Resources resources,
|
||||
DeviceConfigProxy deviceConfigProxy,
|
||||
ServerFlagReader serverFlagReader,
|
||||
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
|
||||
Restarter restarter) {
|
||||
@@ -108,7 +105,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
mSecureSettings = secureSettings;
|
||||
mResources = resources;
|
||||
mSystemProperties = systemProperties;
|
||||
mDeviceConfigProxy = deviceConfigProxy;
|
||||
mServerFlagReader = serverFlagReader;
|
||||
mAllFlags = allFlags;
|
||||
mRestarter = restarter;
|
||||
@@ -140,7 +136,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
int id = flag.getId();
|
||||
if (!mBooleanFlagCache.containsKey(id)) {
|
||||
mBooleanFlagCache.put(id,
|
||||
readFlagValue(id, flag.getDefault()));
|
||||
readBooleanFlagInternal(flag, flag.getDefault()));
|
||||
}
|
||||
|
||||
return mBooleanFlagCache.get(id);
|
||||
@@ -151,19 +147,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
int id = flag.getId();
|
||||
if (!mBooleanFlagCache.containsKey(id)) {
|
||||
mBooleanFlagCache.put(id,
|
||||
readFlagValue(id, 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));
|
||||
readBooleanFlagInternal(flag, mResources.getBoolean(flag.getResourceId())));
|
||||
}
|
||||
|
||||
return mBooleanFlagCache.get(id);
|
||||
@@ -179,7 +163,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
id,
|
||||
mSystemProperties.getBoolean(
|
||||
flag.getName(),
|
||||
readFlagValue(id, flag.getDefault())));
|
||||
readBooleanFlagInternal(flag, flag.getDefault())));
|
||||
}
|
||||
|
||||
return mBooleanFlagCache.get(id);
|
||||
@@ -191,7 +175,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
int id = flag.getId();
|
||||
if (!mStringFlagCache.containsKey(id)) {
|
||||
mStringFlagCache.put(id,
|
||||
readFlagValue(id, flag.getDefault(), StringFlagSerializer.INSTANCE));
|
||||
readFlagValueInternal(id, flag.getDefault(), StringFlagSerializer.INSTANCE));
|
||||
}
|
||||
|
||||
return mStringFlagCache.get(id);
|
||||
@@ -203,20 +187,21 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
int id = flag.getId();
|
||||
if (!mStringFlagCache.containsKey(id)) {
|
||||
mStringFlagCache.put(id,
|
||||
readFlagValue(id, mResources.getString(flag.getResourceId()),
|
||||
readFlagValueInternal(id, mResources.getString(flag.getResourceId()),
|
||||
StringFlagSerializer.INSTANCE));
|
||||
}
|
||||
|
||||
return mStringFlagCache.get(id);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public int getInt(@NonNull IntFlag flag) {
|
||||
int id = flag.getId();
|
||||
if (!mIntFlagCache.containsKey(id)) {
|
||||
mIntFlagCache.put(id,
|
||||
readFlagValue(id, flag.getDefault(), IntFlagSerializer.INSTANCE));
|
||||
readFlagValueInternal(id, flag.getDefault(), IntFlagSerializer.INSTANCE));
|
||||
}
|
||||
|
||||
return mIntFlagCache.get(id);
|
||||
@@ -228,27 +213,31 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
int id = flag.getId();
|
||||
if (!mIntFlagCache.containsKey(id)) {
|
||||
mIntFlagCache.put(id,
|
||||
readFlagValue(id, mResources.getInteger(flag.getResourceId()),
|
||||
readFlagValueInternal(id, mResources.getInteger(flag.getResourceId()),
|
||||
IntFlagSerializer.INSTANCE));
|
||||
}
|
||||
|
||||
return mIntFlagCache.get(id);
|
||||
}
|
||||
|
||||
/** Specific override for Boolean flags that checks against the teamfood list. */
|
||||
private boolean readFlagValue(int id, boolean defaultValue) {
|
||||
Boolean result = readBooleanFlagOverride(id);
|
||||
boolean hasServerOverride = mServerFlagReader.hasOverride(id);
|
||||
/** 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 hasServerOverride = mServerFlagReader.hasOverride(
|
||||
flag.getNamespace(), flag.getName());
|
||||
|
||||
// Only check for teamfood if the default is false
|
||||
// and there is no server override.
|
||||
if (!hasServerOverride && !defaultValue && result == null && id != Flags.TEAMFOOD.getId()) {
|
||||
if (mAllFlags.containsKey(id) && mAllFlags.get(id).getTeamfood()) {
|
||||
return isEnabled(Flags.TEAMFOOD);
|
||||
}
|
||||
if (!hasServerOverride
|
||||
&& !defaultValue
|
||||
&& result == null
|
||||
&& flag.getId() != Flags.TEAMFOOD.getId()
|
||||
&& flag.getTeamfood()) {
|
||||
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) {
|
||||
@@ -256,7 +245,8 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
}
|
||||
|
||||
@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");
|
||||
T result = readFlagValueInternal(id, serializer);
|
||||
return result == null ? defaultValue : result;
|
||||
@@ -355,8 +345,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
|
||||
} else if (flag instanceof ResourceBooleanFlag) {
|
||||
setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
|
||||
} else if (flag instanceof DeviceConfigBooleanFlag) {
|
||||
setFlagValue(flag.getId(), 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);
|
||||
@@ -474,9 +462,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
} else if (f instanceof ResourceBooleanFlag) {
|
||||
enabled = isEnabled((ResourceBooleanFlag) f);
|
||||
overridden = readBooleanFlagOverride(f.getId()) != null;
|
||||
} else if (f instanceof DeviceConfigBooleanFlag) {
|
||||
enabled = isEnabled((DeviceConfigBooleanFlag) f);
|
||||
overridden = false;
|
||||
} else if (f instanceof SysPropBooleanFlag) {
|
||||
// TODO(b/223379190): Teamfood not supported for sysprop flags yet.
|
||||
enabled = isEnabled((SysPropBooleanFlag) f);
|
||||
@@ -489,9 +474,11 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
return new ReleasedFlag(f.getId(), teamfood, overridden);
|
||||
return new ReleasedFlag(
|
||||
f.getId(), f.getName(), f.getNamespace(), teamfood, overridden);
|
||||
} else {
|
||||
return new UnreleasedFlag(f.getId(), teamfood, overridden);
|
||||
return new UnreleasedFlag(
|
||||
f.getId(), f.getName(), f.getNamespace(), teamfood, overridden);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -101,7 +101,7 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(@NotNull ReleasedFlag flag) {
|
||||
return mServerFlagReader.readServerOverride(flag.getId(), true);
|
||||
return mServerFlagReader.readServerOverride(flag.getNamespace(), flag.getName(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,18 +114,6 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
||||
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
|
||||
public boolean isEnabled(SysPropBooleanFlag flag) {
|
||||
int cacheIndex = mBooleanCache.indexOfKey(flag.getId());
|
||||
@@ -180,10 +168,10 @@ public class FeatureFlagsRelease implements FeatureFlags {
|
||||
@Override
|
||||
public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
|
||||
pw.println("can override: false");
|
||||
Map<Integer, Flag<?>> knownFlags = Flags.collectFlags();
|
||||
for (Map.Entry<Integer, Flag<?>> idToFlag : knownFlags.entrySet()) {
|
||||
int id = idToFlag.getKey();
|
||||
Flag<?> flag = idToFlag.getValue();
|
||||
Map<String, Flag<?>> knownFlags = FlagsFactory.INSTANCE.getKnownFlags();
|
||||
for (Map.Entry<String, Flag<?>> nameToFlag : knownFlags.entrySet()) {
|
||||
Flag<?> flag = nameToFlag.getValue();
|
||||
int id = flag.getId();
|
||||
boolean def = false;
|
||||
if (mBooleanCache.indexOfKey(flag.getId()) < 0) {
|
||||
if (flag instanceof SysPropBooleanFlag) {
|
||||
|
||||
@@ -229,7 +229,7 @@ public class FlagCommand implements Command {
|
||||
}
|
||||
|
||||
private int flagNameToId(String flagName) {
|
||||
Map<String, Flag<?>> flagFields = Flags.getFlagFields();
|
||||
Map<String, Flag<?>> flagFields = FlagsFactory.INSTANCE.getKnownFlags();
|
||||
for (String fieldName : flagFields.keySet()) {
|
||||
if (flagName.equals(fieldName)) {
|
||||
return flagFields.get(fieldName).getId();
|
||||
@@ -240,7 +240,7 @@ public class FlagCommand implements Command {
|
||||
}
|
||||
|
||||
private void printKnownFlags(PrintWriter pw) {
|
||||
Map<String, Flag<?>> fields = Flags.getFlagFields();
|
||||
Map<String, Flag<?>> fields = FlagsFactory.INSTANCE.getKnownFlags();
|
||||
|
||||
int longestFieldName = 0;
|
||||
for (String fieldName : fields.keySet()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,12 +17,11 @@ package com.android.systemui.flags
|
||||
|
||||
import android.provider.DeviceConfig
|
||||
import com.android.internal.annotations.Keep
|
||||
import com.android.internal.annotations.VisibleForTesting
|
||||
import com.android.systemui.R
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.declaredMembers
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.staticProperties
|
||||
import com.android.systemui.flags.FlagsFactory.releasedFlag
|
||||
import com.android.systemui.flags.FlagsFactory.resourceBooleanFlag
|
||||
import com.android.systemui.flags.FlagsFactory.sysPropBooleanFlag
|
||||
import com.android.systemui.flags.FlagsFactory.unreleasedFlag
|
||||
|
||||
/**
|
||||
* List of [Flag] objects for use in SystemUI.
|
||||
@@ -37,41 +36,51 @@ import kotlin.reflect.full.staticProperties
|
||||
* See [FeatureFlagsDebug] for instructions on flipping the flags via adb.
|
||||
*/
|
||||
object Flags {
|
||||
@JvmField val TEAMFOOD = UnreleasedFlag(1)
|
||||
@JvmField val TEAMFOOD = unreleasedFlag(1, "teamfood")
|
||||
|
||||
// 100 - notification
|
||||
// TODO(b/254512751): Tracking Bug
|
||||
val NOTIFICATION_PIPELINE_DEVELOPER_LOGGING = UnreleasedFlag(103)
|
||||
val NOTIFICATION_PIPELINE_DEVELOPER_LOGGING =
|
||||
unreleasedFlag(103, "notification_pipeline_developer_logging")
|
||||
|
||||
// TODO(b/254512732): Tracking Bug
|
||||
@JvmField val NSSL_DEBUG_LINES = UnreleasedFlag(105)
|
||||
@JvmField val NSSL_DEBUG_LINES = unreleasedFlag(105, "nssl_debug_lines")
|
||||
|
||||
// TODO(b/254512505): Tracking Bug
|
||||
@JvmField val NSSL_DEBUG_REMOVE_ANIMATION = UnreleasedFlag(106)
|
||||
@JvmField val NSSL_DEBUG_REMOVE_ANIMATION = unreleasedFlag(106, "nssl_debug_remove_animation")
|
||||
|
||||
// TODO(b/254512624): Tracking Bug
|
||||
@JvmField
|
||||
val NOTIFICATION_DRAG_TO_CONTENTS =
|
||||
ResourceBooleanFlag(108, R.bool.config_notificationToContents)
|
||||
resourceBooleanFlag(
|
||||
108,
|
||||
R.bool.config_notificationToContents,
|
||||
"notification_drag_to_contents"
|
||||
)
|
||||
|
||||
// TODO(b/254512517): Tracking Bug
|
||||
val FSI_REQUIRES_KEYGUARD = UnreleasedFlag(110, teamfood = true)
|
||||
val FSI_REQUIRES_KEYGUARD = unreleasedFlag(110, "fsi_requires_keyguard", teamfood = true)
|
||||
|
||||
// TODO(b/254512538): Tracking Bug
|
||||
val INSTANT_VOICE_REPLY = UnreleasedFlag(111, teamfood = true)
|
||||
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply", teamfood = true)
|
||||
|
||||
// TODO(b/254512425): Tracking Bug
|
||||
val NOTIFICATION_MEMORY_MONITOR_ENABLED = ReleasedFlag(112)
|
||||
val NOTIFICATION_MEMORY_MONITOR_ENABLED =
|
||||
releasedFlag(112, "notification_memory_monitor_enabled")
|
||||
|
||||
// TODO(b/254512731): Tracking Bug
|
||||
@JvmField val NOTIFICATION_DISMISSAL_FADE = UnreleasedFlag(113, teamfood = true)
|
||||
val STABILITY_INDEX_FIX = UnreleasedFlag(114, teamfood = true)
|
||||
val SEMI_STABLE_SORT = UnreleasedFlag(115, teamfood = true)
|
||||
@JvmField
|
||||
val NOTIFICATION_DISMISSAL_FADE =
|
||||
unreleasedFlag(113, "notification_dismissal_fade", teamfood = true)
|
||||
val STABILITY_INDEX_FIX = unreleasedFlag(114, "stability_index_fix", teamfood = true)
|
||||
val SEMI_STABLE_SORT = unreleasedFlag(115, "semi_stable_sort", teamfood = true)
|
||||
|
||||
@JvmField val NOTIFICATION_GROUP_CORNER = UnreleasedFlag(116, teamfood = true)
|
||||
@JvmField
|
||||
val NOTIFICATION_GROUP_CORNER =
|
||||
unreleasedFlag(116, "notification_group_corner", teamfood = true)
|
||||
|
||||
// TODO(b/257506350): Tracking Bug
|
||||
val FSI_CHROME = UnreleasedFlag(117)
|
||||
val FSI_CHROME = unreleasedFlag(117, "fsi_chrome")
|
||||
|
||||
// next id: 118
|
||||
|
||||
@@ -80,25 +89,27 @@ object Flags {
|
||||
// public static final BooleanFlag KEYGUARD_LAYOUT =
|
||||
// new BooleanFlag(200, true);
|
||||
// TODO(b/254512713): Tracking Bug
|
||||
@JvmField val LOCKSCREEN_ANIMATIONS = ReleasedFlag(201)
|
||||
@JvmField val LOCKSCREEN_ANIMATIONS = releasedFlag(201, "lockscreen_animations")
|
||||
|
||||
// TODO(b/254512750): Tracking Bug
|
||||
val NEW_UNLOCK_SWIPE_ANIMATION = ReleasedFlag(202)
|
||||
val CHARGING_RIPPLE = ResourceBooleanFlag(203, R.bool.flag_charging_ripple)
|
||||
val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag(202, "new_unlock_swipe_animation")
|
||||
val CHARGING_RIPPLE = resourceBooleanFlag(203, R.bool.flag_charging_ripple, "charging_ripple")
|
||||
|
||||
// TODO(b/254512281): Tracking Bug
|
||||
@JvmField
|
||||
val BOUNCER_USER_SWITCHER = ResourceBooleanFlag(204, R.bool.config_enableBouncerUserSwitcher)
|
||||
val BOUNCER_USER_SWITCHER =
|
||||
resourceBooleanFlag(204, R.bool.config_enableBouncerUserSwitcher, "bouncer_user_switcher")
|
||||
|
||||
// TODO(b/254512676): Tracking Bug
|
||||
@JvmField val LOCKSCREEN_CUSTOM_CLOCKS = UnreleasedFlag(207, teamfood = true)
|
||||
@JvmField
|
||||
val LOCKSCREEN_CUSTOM_CLOCKS = unreleasedFlag(207, "lockscreen_custom_clocks", teamfood = true)
|
||||
|
||||
/**
|
||||
* Flag to enable the usage of the new bouncer data source. This is a refactor of and eventual
|
||||
* replacement of KeyguardBouncer.java.
|
||||
*/
|
||||
// TODO(b/254512385): Tracking Bug
|
||||
@JvmField val MODERN_BOUNCER = ReleasedFlag(208)
|
||||
@JvmField val MODERN_BOUNCER = releasedFlag(208, "modern_bouncer")
|
||||
|
||||
/**
|
||||
* Whether the user interactor and repository should use `UserSwitcherController`.
|
||||
@@ -107,7 +118,8 @@ object Flags {
|
||||
* framework APIs.
|
||||
*/
|
||||
// TODO(b/254513286): Tracking Bug
|
||||
val USER_INTERACTOR_AND_REPO_USE_CONTROLLER = UnreleasedFlag(210)
|
||||
val USER_INTERACTOR_AND_REPO_USE_CONTROLLER =
|
||||
unreleasedFlag(210, "user_interactor_and_repo_use_controller")
|
||||
|
||||
/**
|
||||
* Whether `UserSwitcherController` should use the user interactor.
|
||||
@@ -119,20 +131,24 @@ object Flags {
|
||||
* would created a cycle between controller -> interactor -> controller.
|
||||
*/
|
||||
// TODO(b/254513102): Tracking Bug
|
||||
val USER_CONTROLLER_USES_INTERACTOR = ReleasedFlag(211)
|
||||
val USER_CONTROLLER_USES_INTERACTOR = releasedFlag(211, "user_controller_uses_interactor")
|
||||
|
||||
/**
|
||||
* Whether the clock on a wide lock screen should use the new "stepping" animation for moving
|
||||
* the digits when the clock moves.
|
||||
*/
|
||||
@JvmField val STEP_CLOCK_ANIMATION = UnreleasedFlag(212)
|
||||
@JvmField val STEP_CLOCK_ANIMATION = unreleasedFlag(212, "step_clock_animation")
|
||||
|
||||
/**
|
||||
* Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository
|
||||
* will occur in stages. This is one stage of many to come.
|
||||
*/
|
||||
// TODO(b/255607168): Tracking Bug
|
||||
@JvmField val DOZING_MIGRATION_1 = UnreleasedFlag(213)
|
||||
@JvmField val DOZING_MIGRATION_1 = unreleasedFlag(213, "dozing_migration_1")
|
||||
|
||||
@JvmField val NEW_ELLIPSE_DETECTION = unreleasedFlag(214, "new_ellipse_detection")
|
||||
|
||||
@JvmField val NEW_UDFPS_OVERLAY = unreleasedFlag(215, "new_udfps_overlay")
|
||||
|
||||
/**
|
||||
* Whether to enable the code powering customizable lock screen quick affordances.
|
||||
@@ -140,267 +156,256 @@ object Flags {
|
||||
* Note that this flag does not enable individual implementations of quick affordances like the
|
||||
* new camera quick affordance. Look for individual flags for those.
|
||||
*/
|
||||
@JvmField val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES = UnreleasedFlag(214, teamfood = false)
|
||||
@JvmField
|
||||
val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES =
|
||||
unreleasedFlag(216, "customizable_lock_screen_quick_affordances", teamfood = false)
|
||||
|
||||
// 300 - power menu
|
||||
// TODO(b/254512600): Tracking Bug
|
||||
@JvmField val POWER_MENU_LITE = ReleasedFlag(300)
|
||||
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
|
||||
|
||||
// 400 - smartspace
|
||||
|
||||
// TODO(b/254513100): Tracking Bug
|
||||
val SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED = ReleasedFlag(401)
|
||||
val SMARTSPACE = ResourceBooleanFlag(402, R.bool.flag_smartspace)
|
||||
val SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED =
|
||||
releasedFlag(401, "smartspace_shared_element_transition_enabled")
|
||||
val SMARTSPACE = resourceBooleanFlag(402, R.bool.flag_smartspace, "smartspace")
|
||||
|
||||
// 500 - quick settings
|
||||
|
||||
// TODO(b/254512321): Tracking Bug
|
||||
@JvmField val COMBINED_QS_HEADERS = ReleasedFlag(501)
|
||||
val PEOPLE_TILE = ResourceBooleanFlag(502, R.bool.flag_conversations)
|
||||
@JvmField val COMBINED_QS_HEADERS = releasedFlag(501, "combined_qs_headers")
|
||||
val PEOPLE_TILE = resourceBooleanFlag(502, R.bool.flag_conversations, "people_tile")
|
||||
|
||||
@JvmField
|
||||
val QS_USER_DETAIL_SHORTCUT =
|
||||
ResourceBooleanFlag(503, R.bool.flag_lockscreen_qs_user_detail_shortcut)
|
||||
resourceBooleanFlag(
|
||||
503,
|
||||
R.bool.flag_lockscreen_qs_user_detail_shortcut,
|
||||
"qs_user_detail_shortcut"
|
||||
)
|
||||
|
||||
// TODO(b/254512747): Tracking Bug
|
||||
val NEW_HEADER = ReleasedFlag(505)
|
||||
val NEW_HEADER = releasedFlag(505, "new_header")
|
||||
|
||||
// TODO(b/254512383): Tracking Bug
|
||||
@JvmField
|
||||
val FULL_SCREEN_USER_SWITCHER =
|
||||
ResourceBooleanFlag(506, R.bool.config_enableFullscreenUserSwitcher)
|
||||
resourceBooleanFlag(
|
||||
506,
|
||||
R.bool.config_enableFullscreenUserSwitcher,
|
||||
"full_screen_user_switcher"
|
||||
)
|
||||
|
||||
// TODO(b/254512678): Tracking Bug
|
||||
@JvmField val NEW_FOOTER_ACTIONS = ReleasedFlag(507)
|
||||
@JvmField val NEW_FOOTER_ACTIONS = releasedFlag(507, "new_footer_actions")
|
||||
|
||||
// TODO(b/244064524): Tracking Bug
|
||||
@JvmField
|
||||
val QS_SECONDARY_DATA_SUB_INFO =
|
||||
unreleasedFlag(508, "qs_secondary_data_sub_info", teamfood = true)
|
||||
|
||||
// 600- status bar
|
||||
// TODO(b/254513246): Tracking Bug
|
||||
val STATUS_BAR_USER_SWITCHER = ResourceBooleanFlag(602, R.bool.flag_user_switcher_chip)
|
||||
val STATUS_BAR_USER_SWITCHER =
|
||||
resourceBooleanFlag(602, R.bool.flag_user_switcher_chip, "status_bar_user_switcher")
|
||||
|
||||
// TODO(b/254512623): Tracking Bug
|
||||
@Deprecated("Replaced by mobile and wifi specific flags.")
|
||||
val NEW_STATUS_BAR_PIPELINE_BACKEND = UnreleasedFlag(604, teamfood = false)
|
||||
val NEW_STATUS_BAR_PIPELINE_BACKEND =
|
||||
unreleasedFlag(604, "new_status_bar_pipeline_backend", teamfood = false)
|
||||
|
||||
// TODO(b/254512660): Tracking Bug
|
||||
@Deprecated("Replaced by mobile and wifi specific flags.")
|
||||
val NEW_STATUS_BAR_PIPELINE_FRONTEND = UnreleasedFlag(605, teamfood = false)
|
||||
val NEW_STATUS_BAR_PIPELINE_FRONTEND =
|
||||
unreleasedFlag(605, "new_status_bar_pipeline_frontend", teamfood = false)
|
||||
|
||||
// TODO(b/256614753): Tracking Bug
|
||||
val NEW_STATUS_BAR_MOBILE_ICONS = UnreleasedFlag(606)
|
||||
val NEW_STATUS_BAR_MOBILE_ICONS = unreleasedFlag(606, "new_status_bar_mobile_icons")
|
||||
|
||||
// TODO(b/256614210): Tracking Bug
|
||||
val NEW_STATUS_BAR_WIFI_ICON = UnreleasedFlag(607)
|
||||
val NEW_STATUS_BAR_WIFI_ICON = unreleasedFlag(607, "new_status_bar_wifi_icon")
|
||||
|
||||
// TODO(b/256614751): Tracking Bug
|
||||
val NEW_STATUS_BAR_MOBILE_ICONS_BACKEND = UnreleasedFlag(608)
|
||||
val NEW_STATUS_BAR_MOBILE_ICONS_BACKEND =
|
||||
unreleasedFlag(608, "new_status_bar_mobile_icons_backend")
|
||||
|
||||
// TODO(b/256613548): Tracking Bug
|
||||
val NEW_STATUS_BAR_WIFI_ICON_BACKEND = UnreleasedFlag(609)
|
||||
val NEW_STATUS_BAR_WIFI_ICON_BACKEND = unreleasedFlag(609, "new_status_bar_wifi_icon_backend")
|
||||
|
||||
// 700 - dialer/calls
|
||||
// TODO(b/254512734): Tracking Bug
|
||||
val ONGOING_CALL_STATUS_BAR_CHIP = ReleasedFlag(700)
|
||||
val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag(700, "ongoing_call_status_bar_chip")
|
||||
|
||||
// TODO(b/254512681): Tracking Bug
|
||||
val ONGOING_CALL_IN_IMMERSIVE = ReleasedFlag(701)
|
||||
val ONGOING_CALL_IN_IMMERSIVE = releasedFlag(701, "ongoing_call_in_immersive")
|
||||
|
||||
// TODO(b/254512753): Tracking Bug
|
||||
val ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP = ReleasedFlag(702)
|
||||
val ONGOING_CALL_IN_IMMERSIVE_CHIP_TAP = releasedFlag(702, "ongoing_call_in_immersive_chip_tap")
|
||||
|
||||
// 800 - general visual/theme
|
||||
@JvmField val MONET = ResourceBooleanFlag(800, R.bool.flag_monet)
|
||||
@JvmField val MONET = resourceBooleanFlag(800, R.bool.flag_monet, "monet")
|
||||
|
||||
// 801 - region sampling
|
||||
// TODO(b/254512848): Tracking Bug
|
||||
val REGION_SAMPLING = UnreleasedFlag(801)
|
||||
val REGION_SAMPLING = unreleasedFlag(801, "region_sampling")
|
||||
|
||||
// 802 - wallpaper rendering
|
||||
// TODO(b/254512923): Tracking Bug
|
||||
@JvmField val USE_CANVAS_RENDERER = ReleasedFlag(802)
|
||||
@JvmField val USE_CANVAS_RENDERER = unreleasedFlag(802, "use_canvas_renderer")
|
||||
|
||||
// 803 - screen contents translation
|
||||
// TODO(b/254513187): Tracking Bug
|
||||
val SCREEN_CONTENTS_TRANSLATION = UnreleasedFlag(803)
|
||||
val SCREEN_CONTENTS_TRANSLATION = unreleasedFlag(803, "screen_contents_translation")
|
||||
|
||||
// 804 - monochromatic themes
|
||||
@JvmField
|
||||
val MONOCHROMATIC_THEMES = SysPropBooleanFlag(804, "persist.sysui.monochromatic", false)
|
||||
val MONOCHROMATIC_THEMES =
|
||||
sysPropBooleanFlag(804, "persist.sysui.monochromatic", default = false)
|
||||
|
||||
// 900 - media
|
||||
// TODO(b/254512697): Tracking Bug
|
||||
val MEDIA_TAP_TO_TRANSFER = ReleasedFlag(900)
|
||||
val MEDIA_TAP_TO_TRANSFER = releasedFlag(900, "media_tap_to_transfer")
|
||||
|
||||
// TODO(b/254512502): Tracking Bug
|
||||
val MEDIA_SESSION_ACTIONS = UnreleasedFlag(901)
|
||||
val MEDIA_SESSION_ACTIONS = unreleasedFlag(901, "media_session_actions")
|
||||
|
||||
// TODO(b/254512726): Tracking Bug
|
||||
val MEDIA_NEARBY_DEVICES = ReleasedFlag(903)
|
||||
val MEDIA_NEARBY_DEVICES = releasedFlag(903, "media_nearby_devices")
|
||||
|
||||
// TODO(b/254512695): Tracking Bug
|
||||
val MEDIA_MUTE_AWAIT = ReleasedFlag(904)
|
||||
val MEDIA_MUTE_AWAIT = releasedFlag(904, "media_mute_await")
|
||||
|
||||
// TODO(b/254512654): Tracking Bug
|
||||
@JvmField val DREAM_MEDIA_COMPLICATION = UnreleasedFlag(905)
|
||||
@JvmField val DREAM_MEDIA_COMPLICATION = unreleasedFlag(905, "dream_media_complication")
|
||||
|
||||
// TODO(b/254512673): Tracking Bug
|
||||
@JvmField val DREAM_MEDIA_TAP_TO_OPEN = UnreleasedFlag(906)
|
||||
@JvmField val DREAM_MEDIA_TAP_TO_OPEN = unreleasedFlag(906, "dream_media_tap_to_open")
|
||||
|
||||
// TODO(b/254513168): Tracking Bug
|
||||
@JvmField val UMO_SURFACE_RIPPLE = UnreleasedFlag(907)
|
||||
@JvmField val UMO_SURFACE_RIPPLE = unreleasedFlag(907, "umo_surface_ripple")
|
||||
|
||||
// 1000 - dock
|
||||
val SIMULATE_DOCK_THROUGH_CHARGING = ReleasedFlag(1000)
|
||||
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging")
|
||||
|
||||
// TODO(b/254512758): Tracking Bug
|
||||
@JvmField val ROUNDED_BOX_RIPPLE = ReleasedFlag(1002)
|
||||
@JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple")
|
||||
|
||||
// 1100 - windowing
|
||||
@Keep
|
||||
@JvmField
|
||||
val WM_ENABLE_SHELL_TRANSITIONS =
|
||||
SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false)
|
||||
sysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", default = false)
|
||||
|
||||
// TODO(b/254513207): Tracking Bug
|
||||
@Keep
|
||||
@JvmField
|
||||
val WM_ENABLE_PARTIAL_SCREEN_SHARING =
|
||||
DeviceConfigBooleanFlag(
|
||||
unreleasedFlag(
|
||||
1102,
|
||||
"record_task_content",
|
||||
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
|
||||
false,
|
||||
name = "record_task_content",
|
||||
namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER,
|
||||
teamfood = true
|
||||
)
|
||||
|
||||
// TODO(b/254512674): Tracking Bug
|
||||
@Keep
|
||||
@JvmField
|
||||
val HIDE_NAVBAR_WINDOW = SysPropBooleanFlag(1103, "persist.wm.debug.hide_navbar_window", false)
|
||||
val HIDE_NAVBAR_WINDOW =
|
||||
sysPropBooleanFlag(1103, "persist.wm.debug.hide_navbar_window", default = false)
|
||||
|
||||
@Keep
|
||||
@JvmField
|
||||
val WM_DESKTOP_WINDOWING = SysPropBooleanFlag(1104, "persist.wm.debug.desktop_mode", false)
|
||||
val WM_DESKTOP_WINDOWING =
|
||||
sysPropBooleanFlag(1104, "persist.wm.debug.desktop_mode", default = false)
|
||||
|
||||
@Keep
|
||||
@JvmField
|
||||
val WM_CAPTION_ON_SHELL = SysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", false)
|
||||
val WM_CAPTION_ON_SHELL =
|
||||
sysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", default = false)
|
||||
|
||||
@Keep
|
||||
@JvmField
|
||||
val ENABLE_FLING_TO_DISMISS_BUBBLE =
|
||||
SysPropBooleanFlag(1108, "persist.wm.debug.fling_to_dismiss_bubble", true)
|
||||
sysPropBooleanFlag(1108, "persist.wm.debug.fling_to_dismiss_bubble", default = true)
|
||||
|
||||
@Keep
|
||||
@JvmField
|
||||
val ENABLE_FLING_TO_DISMISS_PIP =
|
||||
SysPropBooleanFlag(1109, "persist.wm.debug.fling_to_dismiss_pip", true)
|
||||
sysPropBooleanFlag(1109, "persist.wm.debug.fling_to_dismiss_pip", default = true)
|
||||
|
||||
@Keep
|
||||
@JvmField
|
||||
val ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
|
||||
SysPropBooleanFlag(1110, "persist.wm.debug.enable_pip_keep_clear_algorithm", false)
|
||||
sysPropBooleanFlag(
|
||||
1110,
|
||||
"persist.wm.debug.enable_pip_keep_clear_algorithm",
|
||||
default = false
|
||||
)
|
||||
|
||||
// TODO(b/256873975): Tracking Bug
|
||||
@JvmField @Keep val WM_BUBBLE_BAR = UnreleasedFlag(1111)
|
||||
@JvmField @Keep val WM_BUBBLE_BAR = unreleasedFlag(1111, "wm_bubble_bar")
|
||||
|
||||
// 1200 - predictive back
|
||||
@Keep
|
||||
@JvmField
|
||||
val WM_ENABLE_PREDICTIVE_BACK =
|
||||
SysPropBooleanFlag(1200, "persist.wm.debug.predictive_back", true)
|
||||
sysPropBooleanFlag(1200, "persist.wm.debug.predictive_back", default = true)
|
||||
|
||||
@Keep
|
||||
@JvmField
|
||||
val WM_ENABLE_PREDICTIVE_BACK_ANIM =
|
||||
SysPropBooleanFlag(1201, "persist.wm.debug.predictive_back_anim", false)
|
||||
sysPropBooleanFlag(1201, "persist.wm.debug.predictive_back_anim", default = false)
|
||||
|
||||
@Keep
|
||||
@JvmField
|
||||
val WM_ALWAYS_ENFORCE_PREDICTIVE_BACK =
|
||||
SysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", false)
|
||||
sysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", default = false)
|
||||
|
||||
// TODO(b/254512728): Tracking Bug
|
||||
@JvmField val NEW_BACK_AFFORDANCE = UnreleasedFlag(1203, teamfood = false)
|
||||
@JvmField
|
||||
val NEW_BACK_AFFORDANCE = unreleasedFlag(1203, "new_back_affordance", teamfood = false)
|
||||
|
||||
// 1300 - screenshots
|
||||
// TODO(b/254512719): Tracking Bug
|
||||
@JvmField val SCREENSHOT_REQUEST_PROCESSOR = UnreleasedFlag(1300, teamfood = true)
|
||||
@JvmField
|
||||
val SCREENSHOT_REQUEST_PROCESSOR =
|
||||
unreleasedFlag(1300, "screenshot_request_processor", teamfood = true)
|
||||
|
||||
// TODO(b/254513155): Tracking Bug
|
||||
@JvmField val SCREENSHOT_WORK_PROFILE_POLICY = UnreleasedFlag(1301)
|
||||
@JvmField
|
||||
val SCREENSHOT_WORK_PROFILE_POLICY = unreleasedFlag(1301, "screenshot_work_profile_policy")
|
||||
|
||||
// 1400 - columbus
|
||||
// TODO(b/254512756): Tracking Bug
|
||||
val QUICK_TAP_IN_PCC = ReleasedFlag(1400)
|
||||
val QUICK_TAP_IN_PCC = releasedFlag(1400, "quick_tap_in_pcc")
|
||||
|
||||
// 1500 - chooser
|
||||
// TODO(b/254512507): Tracking Bug
|
||||
val CHOOSER_UNBUNDLED = UnreleasedFlag(1500, teamfood = true)
|
||||
val CHOOSER_UNBUNDLED = unreleasedFlag(1500, "chooser_unbundled", teamfood = true)
|
||||
|
||||
// 1600 - accessibility
|
||||
@JvmField
|
||||
val A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS =
|
||||
unreleasedFlag(1600, "a11y_floating_menu_fling_spring_animations")
|
||||
|
||||
// 1700 - clipboard
|
||||
@JvmField val CLIPBOARD_OVERLAY_REFACTOR = UnreleasedFlag(1700, teamfood = true)
|
||||
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = UnreleasedFlag(1701)
|
||||
@JvmField
|
||||
val CLIPBOARD_OVERLAY_REFACTOR =
|
||||
unreleasedFlag(1700, "clipboard_overlay_refactor", teamfood = true)
|
||||
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = unreleasedFlag(1701, "clipboard_remote_behavior")
|
||||
|
||||
// 1800 - shade container
|
||||
@JvmField val LEAVE_SHADE_OPEN_FOR_BUGREPORT = UnreleasedFlag(1800, teamfood = true)
|
||||
@JvmField
|
||||
val LEAVE_SHADE_OPEN_FOR_BUGREPORT =
|
||||
unreleasedFlag(1800, "leave_shade_open_for_bugreport", teamfood = true)
|
||||
|
||||
// 1900 - note task
|
||||
@JvmField val NOTE_TASKS = SysPropBooleanFlag(1900, "persist.sysui.debug.note_tasks")
|
||||
@JvmField val NOTE_TASKS = sysPropBooleanFlag(1900, "persist.sysui.debug.note_tasks")
|
||||
|
||||
// 2000 - device controls
|
||||
@Keep @JvmField val USE_APP_PANELS = UnreleasedFlag(2000, teamfood = true)
|
||||
@Keep @JvmField val USE_APP_PANELS = unreleasedFlag(2000, "use_app_panels", teamfood = true)
|
||||
|
||||
// 2100 - Falsing Manager
|
||||
@JvmField val FALSING_FOR_LONG_TAPS = ReleasedFlag(2100)
|
||||
|
||||
// Pay no attention to the reflection behind the curtain.
|
||||
// ========================== Curtain ==========================
|
||||
// | |
|
||||
// | . . . . . . . . . . . . . . . . . . . |
|
||||
@JvmStatic
|
||||
fun collectFlags(): Map<Int, Flag<*>> {
|
||||
return flagFields.mapKeys { field -> field.value.id }
|
||||
}
|
||||
|
||||
// | . . . . . . . . . . . . . . . . . . . |
|
||||
@JvmStatic
|
||||
val flagFields: Map<String, Flag<*>>
|
||||
get() = collectFlagsInClass(Flags)
|
||||
|
||||
@VisibleForTesting
|
||||
fun collectFlagsInClass(instance: Any): Map<String, Flag<*>> {
|
||||
val cls = instance::class
|
||||
val javaPropNames = cls.java.fields.map { it.name }
|
||||
val props = cls.declaredMembers
|
||||
val staticProps = cls.staticProperties
|
||||
val staticPropNames = staticProps.map { it.name }
|
||||
return props
|
||||
.mapNotNull { property ->
|
||||
if ((property.returnType.classifier as KClass<*>).isSubclassOf(Flag::class)) {
|
||||
// Fields with @JvmStatic should be accessed via java mechanisms
|
||||
if (javaPropNames.contains(property.name)) {
|
||||
property.name to cls.java.getField(property.name)[null] as Flag<*>
|
||||
// Fields with @Keep but not @JvmField. Don't do this.
|
||||
} else if (staticPropNames.contains(property.name)) {
|
||||
// The below code causes access violation exceptions. I don't know why.
|
||||
// property.name to (property.call() as Flag<*>)
|
||||
// property.name to (staticProps.find { it.name == property.name }!!
|
||||
// .getter.call() as Flag<*>)
|
||||
throw java.lang.RuntimeException(
|
||||
"The {$property.name} flag needs @JvmField"
|
||||
)
|
||||
// Everything else. Skip the `get` prefixed fields that kotlin adds.
|
||||
} else if (property.name.subSequence(0, 3) != "get") {
|
||||
property.name to (property.call(instance) as Flag<*>)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.toMap()
|
||||
}
|
||||
// | |
|
||||
// \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|
||||
@JvmField val FALSING_FOR_LONG_TAPS = releasedFlag(2100, "falsing_for_long_taps")
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ interface FlagsCommonModule {
|
||||
@Provides
|
||||
@Named(ALL_FLAGS)
|
||||
fun providesAllFlags(): Map<Int, Flag<*>> {
|
||||
return Flags.collectFlags()
|
||||
return FlagsFactory.knownFlags.map { it.value.id to it.value }.toMap()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -27,11 +27,10 @@ import javax.inject.Inject
|
||||
|
||||
interface ServerFlagReader {
|
||||
/** 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. */
|
||||
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. */
|
||||
fun listenForChanges(values: Collection<Flag<*>>, listener: ChangeListener)
|
||||
|
||||
@@ -68,19 +67,19 @@ class ServerFlagReaderImpl @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasOverride(flagId: Int): Boolean =
|
||||
deviceConfig.getProperty(
|
||||
override fun hasOverride(namespace: String, name: String): Boolean =
|
||||
!namespace.isBlank() && !name.isBlank() && deviceConfig.getProperty(
|
||||
namespace,
|
||||
getServerOverrideName(flagId)
|
||||
name
|
||||
) != 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,
|
||||
getServerOverrideName(flagId),
|
||||
name,
|
||||
default
|
||||
)
|
||||
}
|
||||
|
||||
override fun listenForChanges(
|
||||
flags: Collection<Flag<*>>,
|
||||
@@ -121,24 +120,24 @@ interface ServerFlagReaderModule {
|
||||
}
|
||||
|
||||
class ServerFlagReaderFake : ServerFlagReader {
|
||||
private val flagMap: MutableMap<Int, Boolean> = mutableMapOf()
|
||||
private val flagMap: MutableMap<String, Boolean> = mutableMapOf()
|
||||
private val listeners =
|
||||
mutableListOf<Pair<ServerFlagReader.ChangeListener, Collection<Flag<*>>>>()
|
||||
|
||||
override fun hasOverride(flagId: Int): Boolean {
|
||||
return flagMap.containsKey(flagId)
|
||||
override fun hasOverride(namespace: String, name: String): Boolean {
|
||||
return flagMap.containsKey(name)
|
||||
}
|
||||
|
||||
override fun readServerOverride(flagId: Int, default: Boolean): Boolean {
|
||||
return flagMap.getOrDefault(flagId, default)
|
||||
override fun readServerOverride(namespace: String, name: String, default: Boolean): Boolean {
|
||||
return flagMap.getOrDefault(name, default)
|
||||
}
|
||||
|
||||
fun setFlagValue(flagId: Int, value: Boolean) {
|
||||
flagMap.put(flagId, value)
|
||||
fun setFlagValue(namespace: String, name: String, value: Boolean) {
|
||||
flagMap.put(name, value)
|
||||
|
||||
for ((listener, flags) in listeners) {
|
||||
flagLoop@ for (flag in flags) {
|
||||
if (flagId == flag.id) {
|
||||
if (name == flag.name) {
|
||||
listener.onChange()
|
||||
break@flagLoop
|
||||
}
|
||||
@@ -146,8 +145,8 @@ class ServerFlagReaderFake : ServerFlagReader {
|
||||
}
|
||||
}
|
||||
|
||||
fun eraseFlag(flagId: Int) {
|
||||
flagMap.remove(flagId)
|
||||
fun eraseFlag(namespace: String, name: String) {
|
||||
flagMap.remove(name)
|
||||
}
|
||||
|
||||
override fun listenForChanges(
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.lang.IllegalStateException
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -29,12 +28,12 @@ import org.junit.runner.RunWith
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
|
||||
private val unreleasedFlag = UnreleasedFlag(-1000)
|
||||
private val releasedFlag = ReleasedFlag(-1001)
|
||||
private val stringFlag = StringFlag(-1002)
|
||||
private val resourceBooleanFlag = ResourceBooleanFlag(-1003, resourceId = -1)
|
||||
private val resourceStringFlag = ResourceStringFlag(-1004, resourceId = -1)
|
||||
private val sysPropBooleanFlag = SysPropBooleanFlag(-1005, name = "test")
|
||||
private val unreleasedFlag = UnreleasedFlag(-1000, "-1000", "test")
|
||||
private val releasedFlag = ReleasedFlag(-1001, "-1001", "test")
|
||||
private val stringFlag = StringFlag(-1002, "-1002", "test")
|
||||
private val resourceBooleanFlag = ResourceBooleanFlag(-1003, "-1003", "test", resourceId = -1)
|
||||
private val resourceStringFlag = ResourceStringFlag(-1004, "-1004", "test", resourceId = -1)
|
||||
private val sysPropBooleanFlag = SysPropBooleanFlag(-1005, "test", "test")
|
||||
|
||||
/**
|
||||
* FakeFeatureFlags does not honor any default values. All flags which are accessed must be
|
||||
@@ -47,7 +46,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() {
|
||||
assertThat(flags.isEnabled(Flags.TEAMFOOD)).isFalse()
|
||||
fail("Expected an exception when accessing an unspecified flag.")
|
||||
} catch (ex: IllegalStateException) {
|
||||
assertThat(ex.message).contains("TEAMFOOD")
|
||||
assertThat(ex.message).contains("id=1")
|
||||
}
|
||||
try {
|
||||
assertThat(flags.isEnabled(unreleasedFlag)).isFalse()
|
||||
|
||||
@@ -31,10 +31,6 @@ import com.android.systemui.util.mockito.nullable
|
||||
import com.android.systemui.util.mockito.withArgCaptor
|
||||
import com.android.systemui.util.settings.SecureSettings
|
||||
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.Before
|
||||
import org.junit.Test
|
||||
@@ -46,8 +42,12 @@ import org.mockito.Mockito.inOrder
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.verifyNoMoreInteractions
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
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
|
||||
@@ -57,21 +57,32 @@ import org.mockito.MockitoAnnotations
|
||||
class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
private lateinit var mFeatureFlagsDebug: FeatureFlagsDebug
|
||||
|
||||
@Mock private lateinit var flagManager: FlagManager
|
||||
@Mock private lateinit var mockContext: Context
|
||||
@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
|
||||
@Mock
|
||||
private lateinit var flagManager: FlagManager
|
||||
@Mock
|
||||
private lateinit var mockContext: Context
|
||||
@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 lateinit var broadcastReceiver: BroadcastReceiver
|
||||
private lateinit var clearCacheAction: Consumer<Int>
|
||||
private val serverFlagReader = ServerFlagReaderFake()
|
||||
|
||||
private val deviceConfig = DeviceConfigProxyFake()
|
||||
private val teamfoodableFlagA = UnreleasedFlag(500, true)
|
||||
private val teamfoodableFlagB = ReleasedFlag(501, true)
|
||||
private val teamfoodableFlagA = UnreleasedFlag(
|
||||
500, name = "a", namespace = "test", teamfood = true
|
||||
)
|
||||
private val teamfoodableFlagB = ReleasedFlag(
|
||||
501, name = "b", namespace = "test", teamfood = true
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
@@ -84,7 +95,6 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
secureSettings,
|
||||
systemProperties,
|
||||
resources,
|
||||
deviceConfig,
|
||||
serverFlagReader,
|
||||
flagMap,
|
||||
restarter
|
||||
@@ -92,8 +102,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
mFeatureFlagsDebug.init()
|
||||
verify(flagManager).onSettingsChangedAction = any()
|
||||
broadcastReceiver = withArgCaptor {
|
||||
verify(mockContext).registerReceiver(capture(), any(), nullable(), nullable(),
|
||||
any())
|
||||
verify(mockContext).registerReceiver(
|
||||
capture(), any(), nullable(), nullable(),
|
||||
any()
|
||||
)
|
||||
}
|
||||
clearCacheAction = withArgCaptor {
|
||||
verify(flagManager).clearCacheAction = capture()
|
||||
@@ -107,10 +119,42 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false)
|
||||
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(ReleasedFlag(2))).isTrue()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(UnreleasedFlag(3))).isTrue()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(ReleasedFlag(4))).isFalse()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(UnreleasedFlag(5))).isFalse()
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
ReleasedFlag(
|
||||
2,
|
||||
name = "2",
|
||||
namespace = "test"
|
||||
)
|
||||
)
|
||||
).isTrue()
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
UnreleasedFlag(
|
||||
3,
|
||||
name = "3",
|
||||
namespace = "test"
|
||||
)
|
||||
)
|
||||
).isTrue()
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
ReleasedFlag(
|
||||
4,
|
||||
name = "3",
|
||||
namespace = "test"
|
||||
)
|
||||
)
|
||||
).isFalse()
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
UnreleasedFlag(
|
||||
5,
|
||||
name = "4",
|
||||
namespace = "test"
|
||||
)
|
||||
)
|
||||
).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -138,9 +182,9 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun teamFoodFlag_Overridden() {
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any()))
|
||||
.thenReturn(true)
|
||||
.thenReturn(true)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any()))
|
||||
.thenReturn(false)
|
||||
.thenReturn(false)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()
|
||||
@@ -161,17 +205,26 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
|
||||
whenever(flagManager.readFlagValue<Boolean>(eq(5), any())).thenReturn(false)
|
||||
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(1, 1001))).isFalse()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(2, 1002))).isTrue()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(3, 1003))).isTrue()
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
ResourceBooleanFlag(
|
||||
1,
|
||||
"1",
|
||||
"test",
|
||||
1001
|
||||
)
|
||||
)
|
||||
).isFalse()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(2, "2", "test", 1002))).isTrue()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(3, "3", "test", 1003))).isTrue()
|
||||
|
||||
Assert.assertThrows(NameNotFoundException::class.java) {
|
||||
mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(4, 1004))
|
||||
mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(4, "4", "test", 1004))
|
||||
}
|
||||
// Test that resource is loaded (and validated) even when the setting is set.
|
||||
// This prevents developers from not noticing when they reference an invalid resource.
|
||||
Assert.assertThrows(NameNotFoundException::class.java) {
|
||||
mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(5, 1005))
|
||||
mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(5, "5", "test", 1005))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,36 +237,30 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
return@thenAnswer it.getArgument(1)
|
||||
}
|
||||
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(1, "a"))).isFalse()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(2, "b"))).isTrue()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(3, "c", true))).isTrue()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(4, "d", false))).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()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(1, "a", "test"))).isFalse()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(2, "b", "test"))).isTrue()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(3, "c", "test", true))).isTrue()
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.isEnabled(
|
||||
SysPropBooleanFlag(
|
||||
4,
|
||||
"d",
|
||||
"test",
|
||||
false
|
||||
)
|
||||
)
|
||||
).isFalse()
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(SysPropBooleanFlag(5, "e", "test"))).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun readStringFlag() {
|
||||
whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo")
|
||||
whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar")
|
||||
assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "biz"))).isEqualTo("biz")
|
||||
assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "baz"))).isEqualTo("baz")
|
||||
assertThat(mFeatureFlagsDebug.getString(StringFlag(3, "buz"))).isEqualTo("foo")
|
||||
assertThat(mFeatureFlagsDebug.getString(StringFlag(4, "buz"))).isEqualTo("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")
|
||||
assertThat(mFeatureFlagsDebug.getString(StringFlag(4, "4", "test", "buz"))).isEqualTo("bar")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -229,20 +276,47 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("override4")
|
||||
whenever(flagManager.readFlagValue<String>(eq(6), any())).thenReturn("override6")
|
||||
|
||||
assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(1, 1001))).isEqualTo("")
|
||||
assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(2, 1002))).isEqualTo("resource2")
|
||||
assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(3, 1003))).isEqualTo("override3")
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.getString(
|
||||
ResourceStringFlag(
|
||||
1,
|
||||
"1",
|
||||
"test",
|
||||
1001
|
||||
)
|
||||
)
|
||||
).isEqualTo("")
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.getString(
|
||||
ResourceStringFlag(
|
||||
2,
|
||||
"2",
|
||||
"test",
|
||||
1002
|
||||
)
|
||||
)
|
||||
).isEqualTo("resource2")
|
||||
assertThat(
|
||||
mFeatureFlagsDebug.getString(
|
||||
ResourceStringFlag(
|
||||
3,
|
||||
"3",
|
||||
"test",
|
||||
1003
|
||||
)
|
||||
)
|
||||
).isEqualTo("override3")
|
||||
|
||||
Assert.assertThrows(NullPointerException::class.java) {
|
||||
mFeatureFlagsDebug.getString(ResourceStringFlag(4, 1004))
|
||||
mFeatureFlagsDebug.getString(ResourceStringFlag(4, "4", "test", 1004))
|
||||
}
|
||||
Assert.assertThrows(NameNotFoundException::class.java) {
|
||||
mFeatureFlagsDebug.getString(ResourceStringFlag(5, 1005))
|
||||
mFeatureFlagsDebug.getString(ResourceStringFlag(5, "5", "test", 1005))
|
||||
}
|
||||
// Test that resource is loaded (and validated) even when the setting is set.
|
||||
// This prevents developers from not noticing when they reference an invalid resource.
|
||||
Assert.assertThrows(NameNotFoundException::class.java) {
|
||||
mFeatureFlagsDebug.getString(ResourceStringFlag(6, 1005))
|
||||
mFeatureFlagsDebug.getString(ResourceStringFlag(6, "6", "test", 1005))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,10 +324,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
fun readIntFlag() {
|
||||
whenever(flagManager.readFlagValue<Int>(eq(3), any())).thenReturn(22)
|
||||
whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(48)
|
||||
assertThat(mFeatureFlagsDebug.getInt(IntFlag(1, 12))).isEqualTo(12)
|
||||
assertThat(mFeatureFlagsDebug.getInt(IntFlag(2, 93))).isEqualTo(93)
|
||||
assertThat(mFeatureFlagsDebug.getInt(IntFlag(3, 8))).isEqualTo(22)
|
||||
assertThat(mFeatureFlagsDebug.getInt(IntFlag(4, 234))).isEqualTo(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)
|
||||
assertThat(mFeatureFlagsDebug.getInt(IntFlag(4, "4", "test", 234))).isEqualTo(48)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -269,26 +343,26 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
whenever(flagManager.readFlagValue<Int>(eq(4), any())).thenReturn(500)
|
||||
whenever(flagManager.readFlagValue<Int>(eq(5), any())).thenReturn(9519)
|
||||
|
||||
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(1, 1001))).isEqualTo(88)
|
||||
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(2, 1002))).isEqualTo(61)
|
||||
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(3, 1003))).isEqualTo(20)
|
||||
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(1, "1", "test", 1001))).isEqualTo(88)
|
||||
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(2, "2", "test", 1002))).isEqualTo(61)
|
||||
assertThat(mFeatureFlagsDebug.getInt(ResourceIntFlag(3, "3", "test", 1003))).isEqualTo(20)
|
||||
|
||||
Assert.assertThrows(NotFoundException::class.java) {
|
||||
mFeatureFlagsDebug.getInt(ResourceIntFlag(4, 1004))
|
||||
mFeatureFlagsDebug.getInt(ResourceIntFlag(4, "4", "test", 1004))
|
||||
}
|
||||
// Test that resource is loaded (and validated) even when the setting is set.
|
||||
// This prevents developers from not noticing when they reference an invalid resource.
|
||||
Assert.assertThrows(NotFoundException::class.java) {
|
||||
mFeatureFlagsDebug.getInt(ResourceIntFlag(5, 1005))
|
||||
mFeatureFlagsDebug.getInt(ResourceIntFlag(5, "5", "test", 1005))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun broadcastReceiver_IgnoresInvalidData() {
|
||||
addFlag(UnreleasedFlag(1))
|
||||
addFlag(ResourceBooleanFlag(2, 1002))
|
||||
addFlag(StringFlag(3, "flag3"))
|
||||
addFlag(ResourceStringFlag(4, 1004))
|
||||
addFlag(UnreleasedFlag(1, "1", "test"))
|
||||
addFlag(ResourceBooleanFlag(2, "2", "test", 1002))
|
||||
addFlag(StringFlag(3, "3", "test", "flag3"))
|
||||
addFlag(ResourceStringFlag(4, "4", "test", 1004))
|
||||
|
||||
broadcastReceiver.onReceive(mockContext, null)
|
||||
broadcastReceiver.onReceive(mockContext, Intent())
|
||||
@@ -304,7 +378,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun intentWithId_NoValueKeyClears() {
|
||||
addFlag(UnreleasedFlag(1))
|
||||
addFlag(UnreleasedFlag(1, name = "1", namespace = "test"))
|
||||
|
||||
// trying to erase an id not in the map does nothing
|
||||
broadcastReceiver.onReceive(
|
||||
@@ -323,10 +397,10 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun setBooleanFlag() {
|
||||
addFlag(UnreleasedFlag(1))
|
||||
addFlag(UnreleasedFlag(2))
|
||||
addFlag(ResourceBooleanFlag(3, 1003))
|
||||
addFlag(ResourceBooleanFlag(4, 1004))
|
||||
addFlag(UnreleasedFlag(1, "1", "test"))
|
||||
addFlag(UnreleasedFlag(2, "2", "test"))
|
||||
addFlag(ResourceBooleanFlag(3, "3", "test", 1003))
|
||||
addFlag(ResourceBooleanFlag(4, "4", "test", 1004))
|
||||
|
||||
setByBroadcast(1, false)
|
||||
verifyPutData(1, "{\"type\":\"boolean\",\"value\":false}")
|
||||
@@ -343,8 +417,8 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun setStringFlag() {
|
||||
addFlag(StringFlag(1, "flag1"))
|
||||
addFlag(ResourceStringFlag(2, 1002))
|
||||
addFlag(StringFlag(1, "flag1", "1", "test"))
|
||||
addFlag(ResourceStringFlag(2, "2", "test", 1002))
|
||||
|
||||
setByBroadcast(1, "override1")
|
||||
verifyPutData(1, "{\"type\":\"string\",\"value\":\"override1\"}")
|
||||
@@ -355,7 +429,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun setFlag_ClearsCache() {
|
||||
val flag1 = addFlag(StringFlag(1, "flag1"))
|
||||
val flag1 = addFlag(StringFlag(1, "1", "test", "flag1"))
|
||||
whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("original")
|
||||
|
||||
// gets the flag & cache it
|
||||
@@ -377,31 +451,31 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun serverSide_Overrides_MakesFalse() {
|
||||
val flag = ReleasedFlag(100)
|
||||
val flag = ReleasedFlag(100, "100", "test")
|
||||
|
||||
serverFlagReader.setFlagValue(flag.id, false)
|
||||
serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
|
||||
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(flag)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun serverSide_Overrides_MakesTrue() {
|
||||
val flag = UnreleasedFlag(100)
|
||||
val flag = UnreleasedFlag(100, name = "100", namespace = "test")
|
||||
|
||||
serverFlagReader.setFlagValue(flag.id, true)
|
||||
serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
|
||||
|
||||
assertThat(mFeatureFlagsDebug.isEnabled(flag)).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dumpFormat() {
|
||||
val flag1 = ReleasedFlag(1)
|
||||
val flag2 = ResourceBooleanFlag(2, 1002)
|
||||
val flag3 = UnreleasedFlag(3)
|
||||
val flag4 = StringFlag(4, "")
|
||||
val flag5 = StringFlag(5, "flag5default")
|
||||
val flag6 = ResourceStringFlag(6, 1006)
|
||||
val flag7 = ResourceStringFlag(7, 1007)
|
||||
val flag1 = ReleasedFlag(1, "1", "test")
|
||||
val flag2 = ResourceBooleanFlag(2, "2", "test", 1002)
|
||||
val flag3 = UnreleasedFlag(3, "3", "test")
|
||||
val flag4 = StringFlag(4, "4", "test", "")
|
||||
val flag5 = StringFlag(5, "5", "test", "flag5default")
|
||||
val flag6 = ResourceStringFlag(6, "6", "test", 1006)
|
||||
val flag7 = ResourceStringFlag(7, "7", "test", 1007)
|
||||
|
||||
whenever(resources.getBoolean(1002)).thenReturn(true)
|
||||
whenever(resources.getString(1006)).thenReturn("resource1006")
|
||||
|
||||
@@ -25,8 +25,8 @@ import org.junit.Assert.assertThrows
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
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
|
||||
@@ -59,7 +59,9 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
|
||||
fun testBooleanResourceFlag() {
|
||||
val flagId = 213
|
||||
val flagResourceId = 3
|
||||
val flag = ResourceBooleanFlag(flagId, flagResourceId)
|
||||
val flagName = "213"
|
||||
val flagNamespace = "test"
|
||||
val flag = ResourceBooleanFlag(flagId, flagName, flagNamespace, flagResourceId)
|
||||
whenever(mResources.getBoolean(flagResourceId)).thenReturn(true)
|
||||
assertThat(mFeatureFlagsRelease.isEnabled(flag)).isTrue()
|
||||
}
|
||||
@@ -71,57 +73,45 @@ class FeatureFlagsReleaseTest : SysuiTestCase() {
|
||||
whenever(mResources.getString(1003)).thenReturn(null)
|
||||
whenever(mResources.getString(1004)).thenAnswer { throw NameNotFoundException() }
|
||||
|
||||
assertThat(mFeatureFlagsRelease.getString(ResourceStringFlag(1, 1001))).isEqualTo("")
|
||||
assertThat(mFeatureFlagsRelease.getString(ResourceStringFlag(2, 1002))).isEqualTo("res2")
|
||||
assertThat(mFeatureFlagsRelease.getString(
|
||||
ResourceStringFlag(1, "1", "test", 1001))).isEqualTo("")
|
||||
assertThat(mFeatureFlagsRelease.getString(
|
||||
ResourceStringFlag(2, "2", "test", 1002))).isEqualTo("res2")
|
||||
|
||||
assertThrows(NullPointerException::class.java) {
|
||||
mFeatureFlagsRelease.getString(ResourceStringFlag(3, 1003))
|
||||
mFeatureFlagsRelease.getString(ResourceStringFlag(3, "3", "test", 1003))
|
||||
}
|
||||
assertThrows(NameNotFoundException::class.java) {
|
||||
mFeatureFlagsRelease.getString(ResourceStringFlag(4, 1004))
|
||||
mFeatureFlagsRelease.getString(ResourceStringFlag(4, "4", "test", 1004))
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
fun testSysPropBooleanFlag() {
|
||||
val flagId = 213
|
||||
val flagName = "sys_prop_flag"
|
||||
val flagNamespace = "test"
|
||||
val flagDefault = true
|
||||
|
||||
val flag = SysPropBooleanFlag(flagId, flagName, flagDefault)
|
||||
val flag = SysPropBooleanFlag(flagId, flagName, flagNamespace, flagDefault)
|
||||
whenever(mSystemProperties.getBoolean(flagName, flagDefault)).thenReturn(flagDefault)
|
||||
assertThat(mFeatureFlagsRelease.isEnabled(flag)).isEqualTo(flagDefault)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun serverSide_OverridesReleased_MakesFalse() {
|
||||
val flag = ReleasedFlag(100)
|
||||
val flag = ReleasedFlag(100, "100", "test")
|
||||
|
||||
serverFlagReader.setFlagValue(flag.id, false)
|
||||
serverFlagReader.setFlagValue(flag.namespace, flag.name, false)
|
||||
|
||||
assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun serverSide_OverridesUnreleased_Ignored() {
|
||||
val flag = UnreleasedFlag(100)
|
||||
val flag = UnreleasedFlag(100, "100", "test")
|
||||
|
||||
serverFlagReader.setFlagValue(flag.id, true)
|
||||
serverFlagReader.setFlagValue(flag.namespace, flag.name, true)
|
||||
|
||||
assertThat(mFeatureFlagsRelease.isEnabled(flag)).isFalse()
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ class FlagCommandTest : SysuiTestCase() {
|
||||
@Mock private lateinit var featureFlags: FeatureFlagsDebug
|
||||
@Mock private lateinit var pw: PrintWriter
|
||||
private val flagMap = mutableMapOf<Int, Flag<*>>()
|
||||
private val flagA = UnreleasedFlag(500)
|
||||
private val flagB = ReleasedFlag(501)
|
||||
private val stringFlag = StringFlag(502, "abracadabra")
|
||||
private val intFlag = IntFlag(503, 12)
|
||||
private val flagA = UnreleasedFlag(500, "500", "test")
|
||||
private val flagB = ReleasedFlag(501, "501", "test")
|
||||
private val stringFlag = StringFlag(502, "502", "test", "abracadabra")
|
||||
private val intFlag = IntFlag(503, "503", "test", 12)
|
||||
|
||||
private lateinit var cmd: FlagCommand
|
||||
|
||||
|
||||
@@ -64,14 +64,14 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
verifyNoMoreInteractions(mFlagSettingsHelper)
|
||||
|
||||
// adding the first listener registers the observer
|
||||
mFlagManager.addListener(ReleasedFlag(1), listener1)
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1)
|
||||
val observer = withArgCaptor<ContentObserver> {
|
||||
verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture())
|
||||
}
|
||||
verifyNoMoreInteractions(mFlagSettingsHelper)
|
||||
|
||||
// adding another listener does nothing
|
||||
mFlagManager.addListener(ReleasedFlag(2), listener2)
|
||||
mFlagManager.addListener(ReleasedFlag(2, "2", "test"), listener2)
|
||||
verifyNoMoreInteractions(mFlagSettingsHelper)
|
||||
|
||||
// removing the original listener does nothing with second one still present
|
||||
@@ -89,7 +89,7 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
val listener = mock<FlagListenable.Listener>()
|
||||
val clearCacheAction = mock<Consumer<Int>>()
|
||||
mFlagManager.clearCacheAction = clearCacheAction
|
||||
mFlagManager.addListener(ReleasedFlag(1), listener)
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener)
|
||||
val observer = withArgCaptor<ContentObserver> {
|
||||
verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture())
|
||||
}
|
||||
@@ -101,8 +101,8 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
fun testObserverInvokesListeners() {
|
||||
val listener1 = mock<FlagListenable.Listener>()
|
||||
val listener10 = mock<FlagListenable.Listener>()
|
||||
mFlagManager.addListener(ReleasedFlag(1), listener1)
|
||||
mFlagManager.addListener(ReleasedFlag(10), listener10)
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1)
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10)
|
||||
val observer = withArgCaptor<ContentObserver> {
|
||||
verify(mFlagSettingsHelper).registerContentObserver(any(), any(), capture())
|
||||
}
|
||||
@@ -127,8 +127,8 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
fun testOnlySpecificFlagListenerIsInvoked() {
|
||||
val listener1 = mock<FlagListenable.Listener>()
|
||||
val listener10 = mock<FlagListenable.Listener>()
|
||||
mFlagManager.addListener(ReleasedFlag(1), listener1)
|
||||
mFlagManager.addListener(ReleasedFlag(10), listener10)
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener1)
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener10)
|
||||
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, null)
|
||||
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
|
||||
@@ -148,8 +148,8 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testSameListenerCanBeUsedForMultipleFlags() {
|
||||
val listener = mock<FlagListenable.Listener>()
|
||||
mFlagManager.addListener(ReleasedFlag(1), listener)
|
||||
mFlagManager.addListener(ReleasedFlag(10), listener)
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test"), listener)
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test"), listener)
|
||||
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, null)
|
||||
val flagEvent1 = withArgCaptor<FlagListenable.FlagEvent> {
|
||||
@@ -177,7 +177,7 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testListenerCanSuppressRestart() {
|
||||
val restartAction = mock<Consumer<Boolean>>()
|
||||
mFlagManager.addListener(ReleasedFlag(1)) { event ->
|
||||
mFlagManager.addListener(ReleasedFlag(1, "1", "test")) { event ->
|
||||
event.requestNoRestart()
|
||||
}
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
|
||||
@@ -188,7 +188,7 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testListenerOnlySuppressesRestartForOwnFlag() {
|
||||
val restartAction = mock<Consumer<Boolean>>()
|
||||
mFlagManager.addListener(ReleasedFlag(10)) { event ->
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event ->
|
||||
event.requestNoRestart()
|
||||
}
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
|
||||
@@ -199,10 +199,10 @@ class FlagManagerTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testRestartWhenNotAllListenersRequestSuppress() {
|
||||
val restartAction = mock<Consumer<Boolean>>()
|
||||
mFlagManager.addListener(ReleasedFlag(10)) { event ->
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test")) { event ->
|
||||
event.requestNoRestart()
|
||||
}
|
||||
mFlagManager.addListener(ReleasedFlag(10)) {
|
||||
mFlagManager.addListener(ReleasedFlag(10, "10", "test")) {
|
||||
// do not request
|
||||
}
|
||||
mFlagManager.dispatchListenersAndMaybeRestart(1, restartAction)
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.systemui.flags
|
||||
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.google.common.truth.Truth
|
||||
import java.lang.StringBuilder
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
import org.junit.Test
|
||||
|
||||
@SmallTest
|
||||
class FlagsTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testDuplicateFlagIdCheckWorks() {
|
||||
val flags = Flags.collectFlagsInClass(DuplicateFlagContainer)
|
||||
val duplicates = groupDuplicateFlags(flags)
|
||||
Truth.assertWithMessage(generateAssertionMessage(duplicates))
|
||||
.that(duplicates.size)
|
||||
.isEqualTo(2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNoDuplicateFlagIds() {
|
||||
val flags = Flags.collectFlagsInClass(Flags)
|
||||
val duplicates = groupDuplicateFlags(flags)
|
||||
Truth.assertWithMessage(generateAssertionMessage(duplicates))
|
||||
.that(duplicates.size)
|
||||
.isEqualTo(0)
|
||||
}
|
||||
|
||||
private fun generateAssertionMessage(duplicates: Map<Int, List<String>>): String {
|
||||
val stringBuilder = StringBuilder()
|
||||
stringBuilder.append("Duplicate flag keys found: {")
|
||||
for (id in duplicates.keys) {
|
||||
stringBuilder
|
||||
.append(" ")
|
||||
.append(id)
|
||||
.append(": [")
|
||||
.append(java.lang.String.join(", ", duplicates[id]))
|
||||
.append("]")
|
||||
}
|
||||
stringBuilder.append(" }")
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
|
||||
private fun groupDuplicateFlags(flags: Map<String, Flag<*>>): Map<Int, List<String>> {
|
||||
val grouping: MutableMap<Int, MutableList<String>> = HashMap()
|
||||
for (flag in flags) {
|
||||
grouping.putIfAbsent(flag.value.id, ArrayList())
|
||||
grouping[flag.value.id]!!.add(flag.key)
|
||||
}
|
||||
val result: MutableMap<Int, List<String>> = HashMap()
|
||||
for (id in grouping.keys) {
|
||||
if (grouping[id]!!.size > 1) {
|
||||
result[id] = grouping[id]!!
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private object DuplicateFlagContainer {
|
||||
val A_FLAG: BooleanFlag = UnreleasedFlag(0)
|
||||
val B_FLAG: BooleanFlag = UnreleasedFlag(0)
|
||||
val C_FLAG = StringFlag(0)
|
||||
val D_FLAG: BooleanFlag = UnreleasedFlag(1)
|
||||
val E_FLAG = DoubleFlag(3)
|
||||
val F_FLAG = DoubleFlag(3)
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class ServerFlagReaderImplTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testChange_alertsListener() {
|
||||
val flag = ReleasedFlag(1)
|
||||
val flag = ReleasedFlag(1, "1", "test")
|
||||
serverFlagReader.listenForChanges(listOf(flag), changeListener)
|
||||
|
||||
deviceConfig.setProperty(NAMESPACE, "flag_override_1", "1", false)
|
||||
|
||||
@@ -27,7 +27,7 @@ class FakeFeatureFlags : FeatureFlags {
|
||||
private val listenerFlagIds = mutableMapOf<FlagListenable.Listener, MutableSet<Int>>()
|
||||
|
||||
init {
|
||||
Flags.flagFields.forEach { entry: Map.Entry<String, Flag<*>> ->
|
||||
FlagsFactory.knownFlags.forEach { entry: Map.Entry<String, Flag<*>> ->
|
||||
knownFlagNames[entry.value.id] = entry.key
|
||||
}
|
||||
}
|
||||
@@ -87,8 +87,6 @@ class FakeFeatureFlags : FeatureFlags {
|
||||
|
||||
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 getString(flag: StringFlag): String = requireStringValue(flag.id)
|
||||
|
||||
Reference in New Issue
Block a user