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

Commit c36a556f authored by Dave Mankoff's avatar Dave Mankoff Committed by Automerger Merge Worker
Browse files

Add ability for flags to be server-overridden. am: 27195676

parents 9e20ffd4 27195676
Loading
Loading
Loading
Loading
+48 −3
Original line number Diff line number Diff line
@@ -48,9 +48,13 @@ interface SysPropFlag<T> : Flag<T> {
    val default: T
}

/**
 * Base class for most common boolean flags.
 *
 * See [UnreleasedFlag] and [ReleasedFlag] for useful implementations.
 */
// Consider using the "parcelize" kotlin library.

data class BooleanFlag @JvmOverloads constructor(
abstract class BooleanFlag constructor(
    override val id: Int,
    override val default: Boolean = false,
    override val teamfood: Boolean = false,
@@ -60,7 +64,7 @@ data class BooleanFlag @JvmOverloads constructor(
    companion object {
        @JvmField
        val CREATOR = object : Parcelable.Creator<BooleanFlag> {
            override fun createFromParcel(parcel: Parcel) = BooleanFlag(parcel)
            override fun createFromParcel(parcel: Parcel) = object : BooleanFlag(parcel) {}
            override fun newArray(size: Int) = arrayOfNulls<BooleanFlag>(size)
        }
    }
@@ -80,12 +84,46 @@ data class BooleanFlag @JvmOverloads constructor(
    }
}

/**
 * A Flag that is is false by default.
 *
 * It can be changed or overridden in debug builds but not in release builds.
 */
data class UnreleasedFlag @JvmOverloads constructor(
    override val id: Int,
    override val teamfood: Boolean = false,
    override val overridden: Boolean = false
) : BooleanFlag(id, false, teamfood, overridden)

/**
 * A Flag that is is true by default.
 *
 * It can be changed or overridden in any build, meaning it can be turned off if needed.
 */
data class ReleasedFlag @JvmOverloads constructor(
    override val id: Int,
    override val teamfood: Boolean = false,
    override val overridden: Boolean = false
) : BooleanFlag(id, true, teamfood, overridden)

/**
 * A Flag that reads its default values from a resource overlay instead of code.
 *
 * Prefer [UnreleasedFlag] and [ReleasedFlag].
 */
data class ResourceBooleanFlag @JvmOverloads constructor(
    override val id: Int,
    @BoolRes override val resourceId: Int,
    override val teamfood: Boolean = false
) : ResourceFlag<Boolean>

/**
 * A Flag that can reads its overrides from DeviceConfig.
 *
 * This is generally useful for flags that come from or are used _outside_ of SystemUI.
 *
 * Prefer [UnreleasedFlag] and [ReleasedFlag].
 */
data class DeviceConfigBooleanFlag @JvmOverloads constructor(
    override val id: Int,
    override val name: String,
@@ -94,6 +132,13 @@ data class DeviceConfigBooleanFlag @JvmOverloads constructor(
    override val teamfood: Boolean = false
) : DeviceConfigFlag<Boolean>

/**
 * A Flag that can reads its overrides from System Properties.
 *
 * This is generally useful for flags that come from or are used _outside_ of SystemUI.
 *
 * Prefer [UnreleasedFlag] and [ReleasedFlag].
 */
data class SysPropBooleanFlag @JvmOverloads constructor(
    override val id: Int,
    override val name: String,
+3 −2
Original line number Diff line number Diff line
@@ -27,7 +27,8 @@ import dagger.Provides
import javax.inject.Named

@Module(includes = [
    SettingsUtilModule::class
    ServerFlagReaderModule::class,
    SettingsUtilModule::class,
])
abstract class FlagsModule {
    @Binds
+2 −2
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ package com.android.systemui.flags
import dagger.Binds
import dagger.Module

@Module
@Module(includes = [ServerFlagReaderModule::class])
abstract class FlagsModule {
    @Binds
    abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags
+5 −2
Original line number Diff line number Diff line
@@ -23,7 +23,10 @@ package com.android.systemui.flags
 */
interface FeatureFlags : FlagListenable {
    /** Returns a boolean value for the given flag.  */
    fun isEnabled(flag: BooleanFlag): Boolean
    fun isEnabled(flag: UnreleasedFlag): Boolean

    /** Returns a boolean value for the given flag.  */
    fun isEnabled(flag: ReleasedFlag): Boolean

    /** Returns a boolean value for the given flag.  */
    fun isEnabled(flag: ResourceBooleanFlag): Boolean
+54 −33
Original line number Diff line number Diff line
@@ -47,6 +47,8 @@ import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.settings.SecureSettings;

import org.jetbrains.annotations.NotNull;

import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -83,6 +85,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
    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<>();
    private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
@@ -97,6 +100,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
            @Main Resources resources,
            DumpManager dumpManager,
            DeviceConfigProxy deviceConfigProxy,
            ServerFlagReader serverFlagReader,
            @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
            CommandRegistry commandRegistry,
            IStatusBarService barService) {
@@ -105,6 +109,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        mResources = resources;
        mSystemProperties = systemProperties;
        mDeviceConfigProxy = deviceConfigProxy;
        mServerFlagReader = serverFlagReader;
        mAllFlags = allFlags;
        mBarService = barService;

@@ -120,7 +125,16 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
    }

    @Override
    public boolean isEnabled(@NonNull BooleanFlag flag) {
    public boolean isEnabled(@NotNull UnreleasedFlag flag) {
        return isEnabledInternal(flag);
    }

    @Override
    public boolean isEnabled(@NotNull ReleasedFlag flag) {
        return isEnabledInternal(flag);
    }

    private boolean isEnabledInternal(@NotNull BooleanFlag flag) {
        int id = flag.getId();
        if (!mBooleanFlagCache.containsKey(id)) {
            mBooleanFlagCache.put(id,
@@ -197,14 +211,17 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
    /** Specific override for Boolean flags that checks against the teamfood list.*/
    private boolean readFlagValue(int id, boolean defaultValue) {
        Boolean result = readBooleanFlagOverride(id);
        // Only check for teamfood if the default is false.
        if (!defaultValue && result == null && id != Flags.TEAMFOOD.getId()) {
        boolean hasServerOverride = mServerFlagReader.hasOverride(id);

        // 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);
            }
        }

        return result == null ? defaultValue : result;
        return result == null ? mServerFlagReader.readServerOverride(id, defaultValue) : result;
    }

    private Boolean readBooleanFlagOverride(int id) {
@@ -409,37 +426,39 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
         */
        @Nullable
        private ParcelableFlag<?> toParcelableFlag(Flag<?> f) {
            if (f instanceof BooleanFlag) {
                return new BooleanFlag(
                        f.getId(),
                        isEnabled((BooleanFlag) f),
                        f.getTeamfood(),
                        readBooleanFlagOverride(f.getId()) != null);
            }
            if (f instanceof ResourceBooleanFlag) {
                return new BooleanFlag(
                        f.getId(),
                        isEnabled((ResourceBooleanFlag) f),
                        f.getTeamfood(),
                        readBooleanFlagOverride(f.getId()) != null);
            }
            if (f instanceof DeviceConfigBooleanFlag) {
                return new BooleanFlag(
                        f.getId(), isEnabled((DeviceConfigBooleanFlag) f), f.getTeamfood());
            }
            if (f instanceof SysPropBooleanFlag) {
            boolean enabled;
            boolean teamfood = f.getTeamfood();
            boolean overridden;

            if (f instanceof ReleasedFlag) {
                enabled = isEnabled((ReleasedFlag) f);
                overridden = readBooleanFlagOverride(f.getId()) != null;
            } else if (f instanceof UnreleasedFlag) {
                enabled = isEnabled((UnreleasedFlag) f);
                overridden = readBooleanFlagOverride(f.getId()) != null;
            } 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.
                return new BooleanFlag(
                        f.getId(),
                        ((SysPropBooleanFlag) f).getDefault(),
                        false,
                        !mSystemProperties.get(((SysPropBooleanFlag) f).getName()).isEmpty());
            }

                enabled = isEnabled((SysPropBooleanFlag) f);
                teamfood = false;
                overridden = !mSystemProperties.get(((SysPropBooleanFlag) f).getName()).isEmpty();
            } else {
                // TODO: add support for other flag types.
                Log.w(TAG, "Unsupported Flag Type. Please file a bug.");
                return null;
            }

            if (enabled) {
                return new ReleasedFlag(f.getId(), teamfood, overridden);
            } else {
                return new UnreleasedFlag(f.getId(), teamfood, overridden);
            }
        }
    };

    private void removeFromCache(int id) {
@@ -539,8 +558,10 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        }

        private boolean isBooleanFlagEnabled(Flag<?> flag) {
            if (flag instanceof BooleanFlag) {
                return isEnabled((BooleanFlag) flag);
            if (flag instanceof ReleasedFlag) {
                return isEnabled((ReleasedFlag) flag);
            } else if (flag instanceof UnreleasedFlag) {
                return isEnabled((UnreleasedFlag) flag);
            } else if (flag instanceof ResourceBooleanFlag) {
                return isEnabled((ResourceBooleanFlag) flag);
            } else if (flag instanceof SysPropFlag) {
Loading