• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.flags;
18 
19 import static com.android.systemui.flags.FlagsCommonModule.ALL_FLAGS;
20 
21 import androidx.annotation.NonNull;
22 
23 import com.android.systemui.statusbar.commandline.Command;
24 
25 import java.io.PrintWriter;
26 import java.util.List;
27 import java.util.Map;
28 
29 import javax.inject.Inject;
30 import javax.inject.Named;
31 
32 /**
33  * A {@link Command} used to flip flags in SystemUI.
34  */
35 public class FlagCommand implements Command {
36     public static final String FLAG_COMMAND = "flag";
37 
38     private final List<String> mOnCommands = List.of("true", "on", "1", "enabled");
39     private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
40     private final List<String> mSetCommands = List.of("set", "put");
41     private final FeatureFlagsDebug mFeatureFlags;
42     private final Map<String, Flag<?>> mAllFlags;
43 
44     @Inject
FlagCommand( FeatureFlagsDebug featureFlags, @Named(ALL_FLAGS) Map<String, Flag<?>> allFlags )45     FlagCommand(
46             FeatureFlagsDebug featureFlags,
47             @Named(ALL_FLAGS) Map<String, Flag<?>> allFlags
48     ) {
49         mFeatureFlags = featureFlags;
50         mAllFlags = allFlags;
51     }
52 
53     @Override
execute(@onNull PrintWriter pw, @NonNull List<String> args)54     public void execute(@NonNull PrintWriter pw, @NonNull List<String> args) {
55         if (args.size() == 0) {
56             pw.println("Error: no flag name supplied");
57             help(pw);
58             pw.println();
59             printKnownFlags(pw);
60             return;
61         }
62 
63         String name = args.get(0);
64         if (!mAllFlags.containsKey(name)) {
65             pw.println("Unknown flag name: " + name);
66             pw.println();
67             printKnownFlags(pw);
68             return;
69         }
70 
71         Flag<?> flag = mAllFlags.get(name);
72 
73         String cmd = "";
74         if (args.size() > 1) {
75             cmd = args.get(1).toLowerCase();
76         }
77 
78         if ("erase".equals(cmd) || "reset".equals(cmd)) {
79             if (args.size() > 2) {
80                 pw.println("Invalid number of arguments to reset a flag.");
81                 help(pw);
82                 return;
83             }
84 
85             mFeatureFlags.eraseFlag(flag);
86             return;
87         }
88 
89         boolean shouldSet = true;
90         if (args.size() == 1) {
91             shouldSet = false;
92         }
93         if (isBooleanFlag(flag)) {
94             if (args.size() > 2) {
95                 pw.println("Invalid number of arguments for a boolean flag.");
96                 help(pw);
97                 return;
98             }
99             boolean newValue = isBooleanFlagEnabled(flag);
100             if ("toggle".equals(cmd)) {
101                 newValue = !newValue;
102             } else if (mOnCommands.contains(cmd)) {
103                 newValue = true;
104             } else if (mOffCommands.contains(cmd)) {
105                 newValue = false;
106             } else if (shouldSet) {
107                 pw.println("Invalid on/off argument supplied");
108                 help(pw);
109                 return;
110             }
111 
112             pw.println("Flag " + name + " is " + newValue);
113             pw.flush();  // Next command will restart sysui, so flush before we do so.
114             if (shouldSet) {
115                 mFeatureFlags.setBooleanFlagInternal(flag, newValue);
116             }
117             return;
118 
119         } else if (isStringFlag(flag)) {
120             if (shouldSet) {
121                 if (args.size() != 3) {
122                     pw.println("Invalid number of arguments a StringFlag.");
123                     help(pw);
124                     return;
125                 } else if (!mSetCommands.contains(cmd)) {
126                     pw.println("Unknown command: " + cmd);
127                     help(pw);
128                     return;
129                 }
130                 String value = args.get(2);
131                 pw.println("Setting Flag " + name + " to " + value);
132                 pw.flush();  // Next command will restart sysui, so flush before we do so.
133                 mFeatureFlags.setStringFlagInternal(flag, args.get(2));
134             } else {
135                 pw.println("Flag " + name + " is " + getStringFlag(flag));
136             }
137             return;
138         } else if (isIntFlag(flag)) {
139             if (shouldSet) {
140                 if (args.size() != 3) {
141                     pw.println("Invalid number of arguments for an IntFlag.");
142                     help(pw);
143                     return;
144                 } else if (!mSetCommands.contains(cmd)) {
145                     pw.println("Unknown command: " + cmd);
146                     help(pw);
147                     return;
148                 }
149                 int value = Integer.parseInt(args.get(2));
150                 pw.println("Setting Flag " + name + " to " + value);
151                 pw.flush();  // Next command will restart sysui, so flush before we do so.
152                 mFeatureFlags.setIntFlagInternal(flag, value);
153             } else {
154                 pw.println("Flag " + name + " is " + getIntFlag(flag));
155             }
156             return;
157         }
158     }
159 
160     @Override
help(PrintWriter pw)161     public void help(PrintWriter pw) {
162         pw.println("Usage: adb shell cmd statusbar flag <id> [options]");
163         pw.println();
164         pw.println("  Boolean Flag Options: "
165                         + "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]");
166         pw.println("  String Flag Options: [set|put \"<value>\"]");
167         pw.println("  Int Flag Options: [set|put <value>]");
168         pw.println();
169         pw.println("The id can either be a numeric integer or the corresponding field name");
170         pw.println(
171                 "If no argument is supplied after the id, the flags runtime value is output");
172     }
173 
isBooleanFlag(Flag<?> flag)174     private boolean isBooleanFlag(Flag<?> flag) {
175         return (flag instanceof BooleanFlag)
176                 || (flag instanceof ResourceBooleanFlag)
177                 || (flag instanceof SysPropFlag);
178     }
179 
isBooleanFlagEnabled(Flag<?> flag)180     private boolean isBooleanFlagEnabled(Flag<?> flag) {
181         if (flag instanceof ReleasedFlag) {
182             return mFeatureFlags.isEnabled((ReleasedFlag) flag);
183         } else if (flag instanceof UnreleasedFlag) {
184             return mFeatureFlags.isEnabled((UnreleasedFlag) flag);
185         } else if (flag instanceof ResourceBooleanFlag) {
186             return mFeatureFlags.isEnabled((ResourceBooleanFlag) flag);
187         } else if (flag instanceof SysPropFlag) {
188             return mFeatureFlags.isEnabled((SysPropBooleanFlag) flag);
189         }
190 
191         return false;
192     }
193 
isStringFlag(Flag<?> flag)194     private boolean isStringFlag(Flag<?> flag) {
195         return (flag instanceof StringFlag) || (flag instanceof ResourceStringFlag);
196     }
197 
getStringFlag(Flag<?> flag)198     private String getStringFlag(Flag<?> flag) {
199         if (flag instanceof StringFlag) {
200             return mFeatureFlags.getString((StringFlag) flag);
201         } else if (flag instanceof ResourceStringFlag) {
202             return mFeatureFlags.getString((ResourceStringFlag) flag);
203         }
204 
205         return "";
206     }
207 
isIntFlag(Flag<?> flag)208     private boolean isIntFlag(Flag<?> flag) {
209         return (flag instanceof IntFlag) || (flag instanceof ResourceIntFlag);
210     }
211 
getIntFlag(Flag<?> flag)212     private int getIntFlag(Flag<?> flag) {
213         if (flag instanceof IntFlag) {
214             return mFeatureFlags.getInt((IntFlag) flag);
215         } else if (flag instanceof ResourceIntFlag) {
216             return mFeatureFlags.getInt((ResourceIntFlag) flag);
217         }
218 
219         return 0;
220     }
221 
flagNameToId(String flagName)222     private int flagNameToId(String flagName) {
223         Map<String, Flag<?>> flagFields = FlagsFactory.INSTANCE.getKnownFlags();
224         for (String fieldName : flagFields.keySet()) {
225             if (flagName.equals(fieldName)) {
226                 return flagFields.get(fieldName).getId();
227             }
228         }
229 
230         return 0;
231     }
232 
printKnownFlags(PrintWriter pw)233     private void printKnownFlags(PrintWriter pw) {
234         Map<String, Flag<?>> fields = FlagsFactory.INSTANCE.getKnownFlags();
235 
236         int longestFieldName = 0;
237         for (String fieldName : fields.keySet()) {
238             longestFieldName = Math.max(longestFieldName, fieldName.length());
239         }
240 
241         pw.println("Known Flags:");
242         pw.print("Flag Name");
243         for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
244             pw.print(" ");
245         }
246         pw.println(" Value");
247         for (int i = 0; i < longestFieldName; i++) {
248             pw.print("=");
249         }
250         pw.println(" ========");
251         for (String fieldName : fields.keySet()) {
252             Flag<?> flag = fields.get(fieldName);
253             if (!mAllFlags.containsKey(flag.getName())) {
254                 continue;
255             }
256             pw.print(fieldName);
257             int fieldWidth = fieldName.length();
258             for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) {
259                 pw.print(" ");
260             }
261             pw.print(" ");
262             if (isBooleanFlag(flag)) {
263                 pw.println(isBooleanFlagEnabled(flag));
264             } else if (isStringFlag(flag)) {
265                 pw.println(getStringFlag(flag));
266             } else if (isIntFlag(flag)) {
267                 pw.println(getIntFlag(flag));
268             } else {
269                 pw.println("<unknown flag type>");
270             }
271         }
272     }
273 }
274