/* * 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 static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS; import androidx.annotation.NonNull; import com.android.systemui.statusbar.commandline.Command; import java.io.PrintWriter; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; /** * A {@link Command} used to flip flags in SystemUI. */ public class FlagCommand implements Command { public static final String FLAG_COMMAND = "flag"; private final List mOnCommands = List.of("true", "on", "1", "enabled"); private final List mOffCommands = List.of("false", "off", "0", "disable"); private final List mSetCommands = List.of("set", "put"); private final FeatureFlagsDebug mFeatureFlags; private final Map> mAllFlags; @Inject FlagCommand( FeatureFlagsDebug featureFlags, @Named(ALL_FLAGS) Map> allFlags ) { mFeatureFlags = featureFlags; mAllFlags = allFlags; } @Override public void execute(@NonNull PrintWriter pw, @NonNull List args) { if (args.size() == 0) { pw.println("Error: no flag name supplied"); help(pw); pw.println(); printKnownFlags(pw); return; } String name = args.get(0); if (!mAllFlags.containsKey(name)) { pw.println("Unknown flag name: " + name); pw.println(); printKnownFlags(pw); return; } Flag flag = mAllFlags.get(name); String cmd = ""; if (args.size() > 1) { cmd = args.get(1).toLowerCase(); } if ("erase".equals(cmd) || "reset".equals(cmd)) { if (args.size() > 2) { pw.println("Invalid number of arguments to reset a flag."); help(pw); return; } mFeatureFlags.eraseFlag(flag); return; } boolean shouldSet = true; if (args.size() == 1) { shouldSet = false; } if (isBooleanFlag(flag)) { if (args.size() > 2) { pw.println("Invalid number of arguments for a boolean flag."); help(pw); return; } 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 " + name + " 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 " + name + " 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 " + name + " 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 " + name + " to " + value); pw.flush(); // Next command will restart sysui, so flush before we do so. mFeatureFlags.setIntFlagInternal(flag, value); } else { pw.println("Flag " + name + " is " + getIntFlag(flag)); } return; } } @Override public void help(PrintWriter pw) { pw.println("Usage: adb shell cmd statusbar flag [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 \"\"]"); pw.println(" Int Flag Options: [set|put ]"); 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); } private boolean isBooleanFlagEnabled(Flag flag) { if (flag instanceof ReleasedFlag) { return mFeatureFlags.isEnabled((ReleasedFlag) flag); } else if (flag instanceof UnreleasedFlag) { return mFeatureFlags.isEnabled((UnreleasedFlag) flag); } else if (flag instanceof ResourceBooleanFlag) { return mFeatureFlags.isEnabled((ResourceBooleanFlag) flag); } else if (flag instanceof SysPropFlag) { return mFeatureFlags.isEnabled((SysPropBooleanFlag) flag); } 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 void printKnownFlags(PrintWriter pw) { Map> fields = FlagsFactory.INSTANCE.getKnownFlags(); int longestFieldName = 0; for (String fieldName : fields.keySet()) { longestFieldName = Math.max(longestFieldName, fieldName.length()); } pw.println("Known Flags:"); pw.print("Flag Name"); for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) { pw.print(" "); } pw.println(" Value"); for (int i = 0; i < longestFieldName; i++) { pw.print("="); } pw.println(" ========"); for (String fieldName : fields.keySet()) { Flag flag = fields.get(fieldName); if (!mAllFlags.containsKey(flag.getName())) { continue; } pw.print(fieldName); int fieldWidth = fieldName.length(); for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) { pw.print(" "); } pw.print(" "); if (isBooleanFlag(flag)) { pw.println(isBooleanFlagEnabled(flag)); } else if (isStringFlag(flag)) { pw.println(getStringFlag(flag)); } else if (isIntFlag(flag)) { pw.println(getIntFlag(flag)); } else { pw.println(""); } } } }