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

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

Merge "Add support for SystemProperty flags to SysUI." into tm-dev

parents 7f9d05c6 7277cee4
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -35,6 +35,11 @@ interface ResourceFlag<T> : Flag<T> {
    val resourceId: Int
}

interface SysPropFlag<T> : Flag<T> {
    val name: String
    val default: T
}

// Consider using the "parcelize" kotlin library.

data class BooleanFlag @JvmOverloads constructor(
@@ -66,6 +71,12 @@ data class ResourceBooleanFlag constructor(
    @BoolRes override val resourceId: Int
) : ResourceFlag<Boolean>

data class SysPropBooleanFlag constructor(
    override val id: Int,
    override val name: String,
    override val default: Boolean = false
) : SysPropFlag<Boolean>

data class StringFlag @JvmOverloads constructor(
    override val id: Int,
    override val default: String = ""
+3 −3
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ class FlagManager constructor(
     * An action called on restart which takes as an argument whether the listeners requested
     * that the restart be suppressed
     */
    var restartAction: Consumer<Boolean>? = null
    var onSettingsChangedAction: Consumer<Boolean>? = null
    var clearCacheAction: Consumer<Int>? = null
    private val listeners: MutableSet<PerFlagListener> = mutableSetOf()
    private val settingsObserver: ContentObserver = SettingsObserver()
@@ -154,11 +154,11 @@ class FlagManager constructor(
            val idStr = parts[parts.size - 1]
            val id = try { idStr.toInt() } catch (e: NumberFormatException) { return }
            clearCacheAction?.accept(id)
            dispatchListenersAndMaybeRestart(id)
            dispatchListenersAndMaybeRestart(id, onSettingsChangedAction)
        }
    }

    fun dispatchListenersAndMaybeRestart(id: Int) {
    fun dispatchListenersAndMaybeRestart(id: Int, restartAction: Consumer<Boolean>?) {
        val filteredListeners: List<FlagListenable.Listener> = synchronized(listeners) {
            listeners.mapNotNull { if (it.id == id) it.listener else null }
        }
+3 −0
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@ interface FeatureFlags : FlagListenable {
    /** Returns a boolean value for the given flag.  */
    fun isEnabled(flag: ResourceBooleanFlag): Boolean

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

    /** Returns a string value for the given flag.  */
    fun getString(flag: StringFlag): String

+44 −6
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import java.util.ArrayList;
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;
@@ -69,6 +70,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
    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, Boolean> mBooleanFlagCache = new TreeMap<>();
    private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
@@ -79,6 +81,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
            FlagManager flagManager,
            Context context,
            SecureSettings secureSettings,
            SystemPropertiesHelper systemProperties,
            @Main Resources resources,
            DumpManager dumpManager,
            @Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector,
@@ -86,11 +89,12 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        mFlagManager = flagManager;
        mSecureSettings = secureSettings;
        mResources = resources;
        mSystemProperties = systemProperties;
        mFlagsCollector = flagsCollector != null ? flagsCollector : Flags::collectFlags;
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_SET_FLAG);
        filter.addAction(ACTION_GET_FLAGS);
        flagManager.setRestartAction(this::restartSystemUI);
        flagManager.setOnSettingsChangedAction(this::restartSystemUI);
        flagManager.setClearCacheAction(this::removeFromCache);
        context.registerReceiver(mReceiver, filter, null, null,
                Context.RECEIVER_EXPORTED_UNAUDITED);
@@ -121,6 +125,17 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        return mBooleanFlagCache.get(id);
    }

    @Override
    public boolean isEnabled(@NonNull SysPropBooleanFlag flag) {
        int id = flag.getId();
        if (!mBooleanFlagCache.containsKey(id)) {
            mBooleanFlagCache.put(
                    id, mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
        }

        return mBooleanFlagCache.get(id);
    }

    @NonNull
    @Override
    public String getString(@NonNull StringFlag flag) {
@@ -180,16 +195,28 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        mSecureSettings.putString(mFlagManager.idToSettingsKey(id), data);
        Log.i(TAG, "Set id " + id + " to " + value);
        removeFromCache(id);
        mFlagManager.dispatchListenersAndMaybeRestart(id);
        mFlagManager.dispatchListenersAndMaybeRestart(id, this::restartSystemUI);
    }

    private <T> void eraseFlag(Flag<T> flag) {
        if (flag instanceof SysPropFlag) {
            mSystemProperties.erase(((SysPropFlag<T>) flag).getName());
            dispatchListenersAndMaybeRestart(flag.getId(), this::restartAndroid);
        } else {
            eraseFlag(flag.getId());
        }
    }

    /** Erase a flag's overridden value if there is one. */
    public void eraseFlag(int id) {
    private void eraseFlag(int id) {
        eraseInternal(id);
        removeFromCache(id);
        mFlagManager.dispatchListenersAndMaybeRestart(id);
        dispatchListenersAndMaybeRestart(id, this::restartSystemUI);
    }

    private void dispatchListenersAndMaybeRestart(int id, Consumer<Boolean> restartAction) {
        mFlagManager.dispatchListenersAndMaybeRestart(id, restartAction);
    }
    /** Works just like {@link #eraseFlag(int)} except that it doesn't restart SystemUI. */
    private void eraseInternal(int id) {
        // We can't actually "erase" things from sysprops, but we can set them to empty!
@@ -217,7 +244,11 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
        System.exit(0);
    }

    private void restartAndroid() {
    private void restartAndroid(boolean requestSuppress) {
        if (requestSuppress) {
            Log.i(TAG, "Android Restart Suppressed");
            return;
        }
        Log.i(TAG, "Restarting Android");
        try {
            mBarService.restart();
@@ -273,7 +304,7 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
            Flag<?> flag = flagMap.get(id);

            if (!extras.containsKey(EXTRA_VALUE)) {
                eraseFlag(id);
                eraseFlag(flag);
                return;
            }

@@ -282,6 +313,10 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
                setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE);
            } else  if (flag instanceof ResourceBooleanFlag && value instanceof Boolean) {
                setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE);
            } else  if (flag instanceof SysPropBooleanFlag && value instanceof Boolean) {
                // Store SysProp flags in SystemProperties where they can read by outside parties.
                mSystemProperties.setBoolean(
                        ((SysPropBooleanFlag) flag).getName(), (Boolean) value);
            } else if (flag instanceof StringFlag && value instanceof String) {
                setFlagValue(id, (String) value, StringFlagSerializer.INSTANCE);
            } else if (flag instanceof ResourceStringFlag && value instanceof String) {
@@ -306,6 +341,9 @@ public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
            if (f instanceof ResourceBooleanFlag) {
                return new BooleanFlag(f.getId(), isEnabled((ResourceBooleanFlag) f));
            }
            if (f instanceof SysPropBooleanFlag) {
                return new BooleanFlag(f.getId(), isEnabled((SysPropBooleanFlag) f));
            }

            // TODO: add support for other flag types.
            Log.w(TAG, "Unsupported Flag Type. Please file a bug.");
+18 −1
Original line number Diff line number Diff line
@@ -43,11 +43,17 @@ import javax.inject.Inject;
@SysUISingleton
public class FeatureFlagsRelease implements FeatureFlags, Dumpable {
    private final Resources mResources;
    private final SystemPropertiesHelper mSystemProperties;
    SparseBooleanArray mBooleanCache = new SparseBooleanArray();
    SparseArray<String> mStringCache = new SparseArray<>();

    @Inject
    public FeatureFlagsRelease(@Main Resources resources, DumpManager dumpManager) {
    public FeatureFlagsRelease(
            @Main Resources resources,
            SystemPropertiesHelper systemProperties,
            DumpManager dumpManager) {
        mResources = resources;
        mSystemProperties = systemProperties;
        dumpManager.registerDumpable("SysUIFlags", this);
    }

@@ -72,6 +78,17 @@ public class FeatureFlagsRelease implements FeatureFlags, Dumpable {
        return mBooleanCache.valueAt(cacheIndex);
    }

    @Override
    public boolean isEnabled(SysPropBooleanFlag flag) {
        int cacheIndex = mBooleanCache.indexOfKey(flag.getId());
        if (cacheIndex < 0) {
            return isEnabled(
                    flag.getId(), mSystemProperties.getBoolean(flag.getName(), flag.getDefault()));
        }

        return mBooleanCache.valueAt(cacheIndex);
    }

    private boolean isEnabled(int key, boolean defaultValue) {
        mBooleanCache.append(key, defaultValue);
        return defaultValue;
Loading