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

Commit f3df059e authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Enable Int and String flags.

Puts mechanics in to support IntFlag and ResourceIntFlag.

Also adds support for both IntFlag and StringFlag via the
command line.

Support in the app will come later.

Bug: 257066497
Test: manual via the command line.
Change-Id: I378f0f1e0db028cee33f729c47a63262124389d7
parent 847d0f53
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ private const val FIELD_VALUE = "value"
private const val FIELD_TYPE = "type"
private const val TYPE_BOOLEAN = "boolean"
private const val TYPE_STRING = "string"
private const val TYPE_INT = "int"

private const val TAG = "FlagSerializer"

@@ -77,4 +78,10 @@ object StringFlagSerializer : FlagSerializer<String>(
    JSONObject::getString
)

object IntFlagSerializer : FlagSerializer<Int>(
    TYPE_INT,
    JSONObject::put,
    JSONObject::getInt
)

class InvalidFlagStorageException : Exception("Data found but is invalid")
+6 −0
Original line number Diff line number Diff line
@@ -44,4 +44,10 @@ interface FeatureFlags : FlagListenable, Dumpable {

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

    /** Returns an int value for a given flag/ */
    fun getInt(flag: IntFlag): Int

    /** Returns an int value for a given flag/ */
    fun getInt(flag: ResourceIntFlag): Int
}
+36 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ public class FeatureFlagsDebug implements FeatureFlags {
    private final Map<Integer, Flag<?>> mAllFlags;
    private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
    private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
    private final Map<Integer, Integer> mIntFlagCache = new TreeMap<>();
    private final Restarter mRestarter;

    private final ServerFlagReader.ChangeListener mOnPropertiesChanged =
@@ -209,6 +210,31 @@ public class FeatureFlagsDebug implements FeatureFlags {
        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));
        }

        return mIntFlagCache.get(id);
    }

    @NonNull
    @Override
    public int getInt(@NonNull ResourceIntFlag flag) {
        int id = flag.getId();
        if (!mIntFlagCache.containsKey(id)) {
            mIntFlagCache.put(id,
                    readFlagValue(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);
@@ -351,6 +377,16 @@ public class FeatureFlagsDebug implements FeatureFlags {
        }
    }

    void setIntFlagInternal(Flag<?> flag, int value) {
        if (flag instanceof IntFlag) {
            setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE);
        } else if (flag instanceof ResourceIntFlag) {
            setFlagValue(flag.getId(), value, IntFlagSerializer.INSTANCE);
        } else {
            throw new IllegalArgumentException("Unknown flag type");
        }
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
+12 −0
Original line number Diff line number Diff line
@@ -165,6 +165,18 @@ public class FeatureFlagsRelease implements FeatureFlags {
        return defaultValue;
    }

    @NonNull
    @Override
    public int getInt(@NonNull IntFlag flag) {
        return flag.getDefault();
    }

    @NonNull
    @Override
    public int getInt(@NonNull ResourceIntFlag flag) {
        return mResources.getInteger(flag.getResourceId());
    }

    @Override
    public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
        pw.println("can override: false");
+124 −26
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ public class FlagCommand implements Command {

    private final List<String> mOnCommands = List.of("true", "on", "1", "enabled");
    private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
    private final List<String> mSetCommands = List.of("set", "put");
    private final FeatureFlagsDebug mFeatureFlags;
    private final Map<Integer, Flag<?>> mAllFlags;

@@ -60,12 +61,6 @@ public class FlagCommand implements Command {
            return;
        }

        if (args.size() > 2) {
            pw.println("Invalid number of arguments.");
            help(pw);
            return;
        }

        int id = 0;
        try {
            id = Integer.parseInt(args.get(0));
@@ -85,48 +80,113 @@ public class FlagCommand implements Command {
        Flag<?> flag = mAllFlags.get(id);

        String cmd = "";
        if (args.size() == 2) {
        if (args.size() > 1) {
            cmd = args.get(1).toLowerCase();
        }

        if ("erase".equals(cmd) || "reset".equals(cmd)) {
            mFeatureFlags.eraseFlag(flag);
            if (args.size() > 2) {
                pw.println("Invalid number of arguments to reset a flag.");
                help(pw);
                return;
            }

        boolean newValue = true;
        if (args.size() == 1 || "toggle".equals(cmd)) {
            boolean enabled = isBooleanFlagEnabled(flag);
            mFeatureFlags.eraseFlag(flag);
            return;
        }

        boolean shouldSet = true;
        if (args.size() == 1) {
                pw.println("Flag " + id + " is " + enabled);
            shouldSet = false;
        }
        if (isBooleanFlag(flag)) {
            if (args.size() > 2) {
                pw.println("Invalid number of arguments for a boolean flag.");
                help(pw);
                return;
            }

            newValue = !enabled;
        } else {
            newValue = mOnCommands.contains(cmd);
            if (!newValue && !mOffCommands.contains(cmd)) {
            boolean newValue = isBooleanFlagEnabled(flag);
            if ("toggle".equals(cmd)) {
                newValue = !newValue;
            } else if (mOnCommands.contains(cmd)) {
                newValue = true;
            } else if (mOffCommands.contains(cmd)) {
                newValue = false;
            } else if (shouldSet) {
                pw.println("Invalid on/off argument supplied");
                help(pw);
                return;
            }
        }

            pw.println("Flag " + id + " is " + newValue);
            pw.flush();  // Next command will restart sysui, so flush before we do so.
            if (shouldSet) {
                mFeatureFlags.setBooleanFlagInternal(flag, newValue);
            }
            return;

        } else if (isStringFlag(flag)) {
            if (shouldSet) {
                if (args.size() != 3) {
                    pw.println("Invalid number of arguments a StringFlag.");
                    help(pw);
                    return;
                } else if (!mSetCommands.contains(cmd)) {
                    pw.println("Unknown command: " + cmd);
                    help(pw);
                    return;
                }
                String value = args.get(2);
                pw.println("Setting Flag " + id + " to " + value);
                pw.flush();  // Next command will restart sysui, so flush before we do so.
                mFeatureFlags.setStringFlagInternal(flag, args.get(2));
            } else {
                pw.println("Flag " + id + " is " + getStringFlag(flag));
            }
            return;
        } else if (isIntFlag(flag)) {
            if (shouldSet) {
                if (args.size() != 3) {
                    pw.println("Invalid number of arguments for an IntFlag.");
                    help(pw);
                    return;
                } else if (!mSetCommands.contains(cmd)) {
                    pw.println("Unknown command: " + cmd);
                    help(pw);
                    return;
                }
                int value = Integer.parseInt(args.get(2));
                pw.println("Setting Flag " + id + " to " + value);
                pw.flush();  // Next command will restart sysui, so flush before we do so.
                mFeatureFlags.setIntFlagInternal(flag, value);
            } else {
                pw.println("Flag " + id + " is " + getIntFlag(flag));
            }
            return;
        }
    }

    @Override
    public void help(PrintWriter pw) {
        pw.println(
                "Usage: adb shell cmd statusbar flag <id> "
        pw.println("Usage: adb shell cmd statusbar flag <id> [options]");
        pw.println();
        pw.println("  Boolean Flag Options: "
                        + "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]");
        pw.println("  String Flag Options: [set|put \"<value>\"]");
        pw.println("  Int Flag Options: [set|put <value>]");
        pw.println();
        pw.println("The id can either be a numeric integer or the corresponding field name");
        pw.println(
                "If no argument is supplied after the id, the flags runtime value is output");
    }

    private boolean isBooleanFlag(Flag<?> flag) {
        return (flag instanceof BooleanFlag)
                || (flag instanceof ResourceBooleanFlag)
                || (flag instanceof SysPropFlag)
                || (flag instanceof DeviceConfigBooleanFlag);
    }

    private boolean isBooleanFlagEnabled(Flag<?> flag) {
        if (flag instanceof ReleasedFlag) {
            return mFeatureFlags.isEnabled((ReleasedFlag) flag);
@@ -141,6 +201,34 @@ public class FlagCommand implements Command {
        return false;
    }

    private boolean isStringFlag(Flag<?> flag) {
        return (flag instanceof StringFlag) || (flag instanceof ResourceStringFlag);
    }

    private String getStringFlag(Flag<?> flag) {
        if (flag instanceof StringFlag) {
            return mFeatureFlags.getString((StringFlag) flag);
        } else if (flag instanceof ResourceStringFlag) {
            return mFeatureFlags.getString((ResourceStringFlag) flag);
        }

        return "";
    }

    private boolean isIntFlag(Flag<?> flag) {
        return (flag instanceof IntFlag) || (flag instanceof ResourceIntFlag);
    }

    private int getIntFlag(Flag<?> flag) {
        if (flag instanceof IntFlag) {
            return mFeatureFlags.getInt((IntFlag) flag);
        } else if (flag instanceof ResourceIntFlag) {
            return mFeatureFlags.getInt((ResourceIntFlag) flag);
        }

        return 0;
    }

    private int flagNameToId(String flagName) {
        List<Field> fields = Flags.getFlagFields();
        for (Field field : fields) {
@@ -176,13 +264,15 @@ public class FlagCommand implements Command {
        for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
            pw.print(" ");
        }
        pw.println("ID   Enabled?");
        pw.println("ID   Value");
        for (int i = 0; i < longestFieldName; i++) {
            pw.print("=");
        }
        pw.println(" ==== ========");
        pw.println(" ==== =====");
        for (Field field : fields) {
            int id = fieldToId(field);
            Flag<?> flag = mAllFlags.get(id);

            if (id == 0 || !mAllFlags.containsKey(id)) {
                continue;
            }
@@ -192,7 +282,15 @@ public class FlagCommand implements Command {
                pw.print(" ");
            }
            pw.printf("%-4d ", id);
            if (isBooleanFlag(flag)) {
                pw.println(isBooleanFlagEnabled(mAllFlags.get(id)));
            } else if (isStringFlag(flag)) {
                pw.println(getStringFlag(flag));
            } else if (isIntFlag(flag)) {
                pw.println(getIntFlag(flag));
            } else {
                pw.println("<unknown flag type>");
            }
        }
    }
}
Loading