Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5a0cfad authored by Dave Mankoff's avatar Dave Mankoff Committed by Android (Google) Code Review
Browse files

Merge "Add support for TEAMFOOD flag." into tm-dev

parents b2f938bf 214c0014
Loading
Loading
Loading
Loading
+30 −16
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.os.Parcelable

interface Flag<T> {
    val id: Int
    val teamfood: Boolean
}

interface ParcelableFlag<T> : Flag<T>, Parcelable {
@@ -44,7 +45,8 @@ interface SysPropFlag<T> : Flag<T> {

data class BooleanFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Boolean = false
    override val default: Boolean = false,
    override val teamfood: Boolean = false
) : ParcelableFlag<Boolean> {

    companion object {
@@ -66,20 +68,25 @@ data class BooleanFlag @JvmOverloads constructor(
    }
}

data class ResourceBooleanFlag constructor(
data class ResourceBooleanFlag @JvmOverloads constructor(
    override val id: Int,
    @BoolRes override val resourceId: Int
    @BoolRes override val resourceId: Int,
    override val teamfood: Boolean = false
) : ResourceFlag<Boolean>

data class SysPropBooleanFlag constructor(
data class SysPropBooleanFlag @JvmOverloads constructor(
    override val id: Int,
    override val name: String,
    override val default: Boolean = false
) : SysPropFlag<Boolean>
) : SysPropFlag<Boolean> {
    // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
    override val teamfood: Boolean = false
}

data class StringFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: String = ""
    override val default: String = "",
    override val teamfood: Boolean = false
) : ParcelableFlag<String> {
    companion object {
        @JvmField
@@ -100,14 +107,16 @@ data class StringFlag @JvmOverloads constructor(
    }
}

data class ResourceStringFlag constructor(
data class ResourceStringFlag @JvmOverloads constructor(
    override val id: Int,
    @StringRes override val resourceId: Int
    @StringRes override val resourceId: Int,
    override val teamfood: Boolean = false
) : ResourceFlag<String>

data class IntFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Int = 0
    override val default: Int = 0,
    override val teamfood: Boolean = false
) : ParcelableFlag<Int> {

    companion object {
@@ -129,14 +138,16 @@ data class IntFlag @JvmOverloads constructor(
    }
}

data class ResourceIntFlag constructor(
data class ResourceIntFlag @JvmOverloads constructor(
    override val id: Int,
    @IntegerRes override val resourceId: Int
    @IntegerRes override val resourceId: Int,
    override val teamfood: Boolean = false
) : ResourceFlag<Int>

data class LongFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Long = 0
    override val default: Long = 0,
    override val teamfood: Boolean = false
) : ParcelableFlag<Long> {

    companion object {
@@ -160,7 +171,8 @@ data class LongFlag @JvmOverloads constructor(

data class FloatFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Float = 0f
    override val default: Float = 0f,
    override val teamfood: Boolean = false
) : ParcelableFlag<Float> {

    companion object {
@@ -182,14 +194,16 @@ data class FloatFlag @JvmOverloads constructor(
    }
}

data class ResourceFloatFlag constructor(
data class ResourceFloatFlag @JvmOverloads constructor(
    override val id: Int,
    override val resourceId: Int
    override val resourceId: Int,
    override val teamfood: Boolean = false
) : ResourceFlag<Int>

data class DoubleFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: Double = 0.0
    override val default: Double = 0.0,
    override val teamfood: Boolean = false
) : ParcelableFlag<Double> {

    companion object {
+2 −2
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ class FlagManager constructor(
        intent.setPackage(RECEIVING_PACKAGE)

        return CallbackToFutureAdapter.getFuture {
            completer: CallbackToFutureAdapter.Completer<Any?> ->
            completer: CallbackToFutureAdapter.Completer<Collection<Flag<*>>> ->
                context.sendOrderedBroadcast(intent, null,
                    object : BroadcastReceiver() {
                        override fun onReceive(context: Context, intent: Intent) {
@@ -79,7 +79,7 @@ class FlagManager constructor(
                        }
                    }, null, Activity.RESULT_OK, "extra data", null)
            "QueryingFlags"
        } as ListenableFuture<Collection<Flag<*>>>
        }
    }

    /**
+4 −2
Original line number Diff line number Diff line
@@ -19,11 +19,12 @@ package com.android.systemui.flags
import android.content.Context
import android.os.Handler
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlagsDebug.ALL_FLAGS
import com.android.systemui.util.settings.SettingsUtilModule
import dagger.Binds
import dagger.Module
import dagger.Provides
import java.util.function.Supplier
import javax.inject.Named

@Module(includes = [
    SettingsUtilModule::class
@@ -42,6 +43,7 @@ abstract class FlagsModule {

        @JvmStatic
        @Provides
        fun providesFlagCollector(): Supplier<Map<Int, Flag<*>>>? = null
        @Named(ALL_FLAGS)
        fun providesAllFlags(): Map<Int, Flag<*>> = Flags.collectFlags()
    }
}
 No newline at end of file
+35 −16
Original line number Diff line number Diff line
@@ -50,9 +50,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Consumer;
import java.util.function.Supplier;

import javax.inject.Inject;
import javax.inject.Named;

/**
 * Concrete implementation of the a Flag manager that returns default values for debug builds
@@ -66,12 +66,13 @@ import javax.inject.Inject;
@SysUISingleton
public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
    private static final String TAG = "SysUIFlags";
    static final String ALL_FLAGS = "all_flags";

    private final FlagManager mFlagManager;
    private final SecureSettings mSecureSettings;
    private final Resources mResources;
    private final SystemPropertiesHelper mSystemProperties;
    private final Supplier<Map<Integer, Flag<?>>> mFlagsCollector;
    private final Map<Integer, Flag<?>> mAllFlags;
    private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
    private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
    private final IStatusBarService mBarService;
@@ -84,13 +85,13 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
            SystemPropertiesHelper systemProperties,
            @Main Resources resources,
            DumpManager dumpManager,
            @Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector,
            @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
            IStatusBarService barService) {
        mFlagManager = flagManager;
        mSecureSettings = secureSettings;
        mResources = resources;
        mSystemProperties = systemProperties;
        mFlagsCollector = flagsCollector != null ? flagsCollector : Flags::collectFlags;
        mAllFlags = allFlags;
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_SET_FLAG);
        filter.addAction(ACTION_GET_FLAGS);
@@ -107,7 +108,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        int id = flag.getId();
        if (!mBooleanFlagCache.containsKey(id)) {
            mBooleanFlagCache.put(id,
                    readFlagValue(id, flag.getDefault(), BooleanFlagSerializer.INSTANCE));
                    readFlagValue(id, flag.getDefault()));
        }

        return mBooleanFlagCache.get(id);
@@ -118,8 +119,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        int id = flag.getId();
        if (!mBooleanFlagCache.containsKey(id)) {
            mBooleanFlagCache.put(id,
                    readFlagValue(id, mResources.getBoolean(flag.getResourceId()),
                            BooleanFlagSerializer.INSTANCE));
                    readFlagValue(id, mResources.getBoolean(flag.getResourceId())));
        }

        return mBooleanFlagCache.get(id);
@@ -129,8 +129,13 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
    public boolean isEnabled(@NonNull SysPropBooleanFlag flag) {
        int id = flag.getId();
        if (!mBooleanFlagCache.containsKey(id)) {
            // Use #readFlagValue to get the default. That will allow it to fall through to
            // teamfood if need be.
            mBooleanFlagCache.put(
                    id, mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
                    id,
                    mSystemProperties.getBoolean(
                            flag.getName(),
                            readFlagValue(id, flag.getDefault())));
        }

        return mBooleanFlagCache.get(id);
@@ -161,6 +166,19 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        return mStringFlagCache.get(id);
    }

    /** Specific override for Boolean flags that checks against the teamfood list.*/
    private boolean readFlagValue(int id, boolean defaultValue) {
        Boolean result = readFlagValueInternal(id, BooleanFlagSerializer.INSTANCE);
        // Only check for teamfood if the default is false.
        if (!defaultValue && result == null && id != Flags.TEAMFOOD.getId()) {
            if (mAllFlags.containsKey(id) && mAllFlags.get(id).getTeamfood()) {
                return isEnabled(Flags.TEAMFOOD);
            }
        }

        return result == null ? defaultValue : result;
    }

    @NonNull
    private <T> T readFlagValue(int id, @NonNull T defaultValue, FlagSerializer<T> serializer) {
        requireNonNull(defaultValue, "defaultValue");
@@ -266,8 +284,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
            if (ACTION_SET_FLAG.equals(action)) {
                handleSetFlag(intent.getExtras());
            } else if (ACTION_GET_FLAGS.equals(action)) {
                Map<Integer, Flag<?>> knownFlagMap = mFlagsCollector.get();
                ArrayList<Flag<?>> flags = new ArrayList<>(knownFlagMap.values());
                ArrayList<Flag<?>> flags = new ArrayList<>(mAllFlags.values());

                // Convert all flags to parcelable flags.
                ArrayList<ParcelableFlag<?>> pFlags = new ArrayList<>();
@@ -296,12 +313,11 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
                return;
            }

            Map<Integer, Flag<?>> flagMap = mFlagsCollector.get();
            if (!flagMap.containsKey(id)) {
            if (!mAllFlags.containsKey(id)) {
                Log.w(TAG, "Tried to set unknown id: " + id);
                return;
            }
            Flag<?> flag = flagMap.get(id);
            Flag<?> flag = mAllFlags.get(id);

            if (!extras.containsKey(EXTRA_VALUE)) {
                eraseFlag(flag);
@@ -338,13 +354,16 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        @Nullable
        private ParcelableFlag<?> toParcelableFlag(Flag<?> f) {
            if (f instanceof BooleanFlag) {
                return new BooleanFlag(f.getId(), isEnabled((BooleanFlag) f));
                return new BooleanFlag(f.getId(), isEnabled((BooleanFlag) f), f.getTeamfood());
            }
            if (f instanceof ResourceBooleanFlag) {
                return new BooleanFlag(f.getId(), isEnabled((ResourceBooleanFlag) f));
                return new BooleanFlag(
                        f.getId(), isEnabled((ResourceBooleanFlag) f), f.getTeamfood());
            }
            if (f instanceof SysPropBooleanFlag) {
                return new BooleanFlag(f.getId(), isEnabled((SysPropBooleanFlag) f));
                // TODO(b/223379190): Teamfood not supported for sysprop flags yet.
                return new BooleanFlag(
                        f.getId(), isEnabled((SysPropBooleanFlag) f), false);
            }

            // TODO: add support for other flag types.
+45 −2
Original line number Diff line number Diff line
@@ -67,9 +67,14 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
    private lateinit var mBroadcastReceiver: BroadcastReceiver
    private lateinit var mClearCacheAction: Consumer<Int>

    private val teamfoodableFlagA = BooleanFlag(500, false, true)
    private val teamfoodableFlagB = BooleanFlag(501, true, true)

    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)
        mFlagMap.put(teamfoodableFlagA.id, teamfoodableFlagA)
        mFlagMap.put(teamfoodableFlagB.id, teamfoodableFlagB)
        mFeatureFlagsDebug = FeatureFlagsDebug(
            mFlagManager,
            mMockContext,
@@ -77,7 +82,7 @@ class FeatureFlagsDebugTest : SysuiTestCase() {
            mSystemProperties,
            mResources,
            mDumpManager,
            { mFlagMap },
            mFlagMap,
            mBarService
        )
        verify(mFlagManager).onSettingsChangedAction = any()
@@ -93,12 +98,50 @@ class FeatureFlagsDebugTest : SysuiTestCase() {

    @Test
    fun testReadBooleanFlag() {
        // Remember that the TEAMFOOD flag is id#1 and has special behavior.
        whenever(mFlagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
        whenever(mFlagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false)
        assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(1, false))).isFalse()
        assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(2, true))).isTrue()
        assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(3, false))).isTrue()
        assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(4, true))).isFalse()
        assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(5, false))).isFalse()
    }

    @Test
    fun testTeamFoodFlag_False() {
        whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(false)
        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse()
        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()

        // Regular boolean flags should still test the same.
        // Only our teamfoodableFlag should change.
        testReadBooleanFlag()
    }

    @Test
    fun testTeamFoodFlag_True() {
        whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()

        // Regular boolean flags should still test the same.
        // Only our teamfoodableFlag should change.
        testReadBooleanFlag()
    }

    @Test
    fun testTeamFoodFlag_Overridden() {
        whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any()))
                .thenReturn(true)
        whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any()))
                .thenReturn(false)
        whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
        assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()

        // Regular boolean flags should still test the same.
        // Only our teamfoodableFlag should change.
        testReadBooleanFlag()
    }

    @Test