blob: 03483893161da0fff7f6f0e5687908465f05868a [file] [log] [blame]
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001/*
2 * Copyright (C) 2018 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
17package com.android.phone;
18
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010019import android.content.Context;
Hall Liua1548bd2019-12-24 14:14:12 -080020import android.os.BasicShellCommandHandler;
Hall Liud892bec2018-11-30 14:51:45 -080021import android.os.Binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010022import android.os.PersistableBundle;
Hall Liud892bec2018-11-30 14:51:45 -080023import android.os.Process;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070024import android.os.RemoteException;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010025import android.telephony.CarrierConfigManager;
26import android.telephony.SubscriptionInfo;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070027import android.telephony.SubscriptionManager;
sqian9d4df8b2019-01-15 18:32:07 -080028import android.telephony.emergency.EmergencyNumber;
Brad Ebinger24c29992019-12-05 13:03:21 -080029import android.telephony.ims.feature.ImsFeature;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070030import android.util.Log;
31
32import com.android.internal.telephony.ITelephony;
sqian9d4df8b2019-01-15 18:32:07 -080033import com.android.internal.telephony.emergency.EmergencyNumberTracker;
Meng Wangc4f61042019-11-21 10:51:05 -080034import com.android.internal.telephony.util.TelephonyUtils;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070035
36import java.io.PrintWriter;
sqian9d4df8b2019-01-15 18:32:07 -080037import java.util.ArrayList;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010038import java.util.HashMap;
Brad Ebinger24c29992019-12-05 13:03:21 -080039import java.util.List;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010040import java.util.Map;
41import java.util.TreeSet;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070042
43/**
44 * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
45 * permission checks have been done before onCommand was called. Make sure any commands processed
46 * here also contain the appropriate permissions checks.
47 */
48
Hall Liua1548bd2019-12-24 14:14:12 -080049public class TelephonyShellCommand extends BasicShellCommandHandler {
Brad Ebinger4dc095a2018-04-03 15:17:52 -070050
51 private static final String LOG_TAG = "TelephonyShellCommand";
52 // Don't commit with this true.
53 private static final boolean VDBG = true;
Brad Ebinger0aa2f242018-04-12 09:49:23 -070054 private static final int DEFAULT_PHONE_ID = 0;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070055
56 private static final String IMS_SUBCOMMAND = "ims";
Hall Liud892bec2018-11-30 14:51:45 -080057 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
sqian9d4df8b2019-01-15 18:32:07 -080058 private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010059 private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
Shuo Qianf5125122019-12-16 17:03:07 -080060 private static final String DATA_TEST_MODE = "data";
61 private static final String DATA_ENABLE = "enable";
62 private static final String DATA_DISABLE = "disable";
Hall Liud892bec2018-11-30 14:51:45 -080063
Brad Ebinger4dc095a2018-04-03 15:17:52 -070064 private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
65 private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
66 private static final String IMS_ENABLE = "enable";
67 private static final String IMS_DISABLE = "disable";
Tyler Gunn7bcdc742019-10-04 15:56:59 -070068 // Used to disable or enable processing of conference event package data from the network.
69 // This is handy for testing scenarios where CEP data does not exist on a network which does
70 // support CEP data.
71 private static final String IMS_CEP = "conference-event-package";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070072
Hall Liud892bec2018-11-30 14:51:45 -080073 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080074 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080075
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010076 private static final String CC_GET_VALUE = "get-value";
77 private static final String CC_SET_VALUE = "set-value";
78 private static final String CC_CLEAR_VALUES = "clear-values";
79
Brad Ebinger4dc095a2018-04-03 15:17:52 -070080 // Take advantage of existing methods that already contain permissions checks when possible.
81 private final ITelephony mInterface;
82
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010083 private SubscriptionManager mSubscriptionManager;
84 private CarrierConfigManager mCarrierConfigManager;
85
86 private enum CcType {
87 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
88 STRING_ARRAY, UNKNOWN
89 }
90
Torbjorn Eklund723527a2019-02-13 11:16:25 +010091 private class CcOptionParseResult {
92 public int mSubId;
93 public boolean mPersistent;
94 }
95
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010096 // Maps carrier config keys to type. It is possible to infer the type for most carrier config
97 // keys by looking at the end of the string which usually tells the type.
98 // For instance: "xxxx_string", "xxxx_string_array", etc.
99 // The carrier config keys in this map does not follow this convention. It is therefore not
100 // possible to infer the type for these keys by looking at the string.
101 private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
102 put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
103 put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
104 put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
105 put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
106 put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
107 put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
108 put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
109 put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
110 put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
111 put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
112 put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
113 CcType.STRING);
114 put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
115 CcType.STRING_ARRAY);
116 put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
117 CcType.STRING_ARRAY);
118 put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
119 put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
120 put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
121 put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
122 put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
123 put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
124 put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
125 put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
126 }
127 };
128
129 public TelephonyShellCommand(ITelephony binder, Context context) {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700130 mInterface = binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100131 mCarrierConfigManager =
132 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
133 mSubscriptionManager = (SubscriptionManager)
134 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700135 }
136
137 @Override
138 public int onCommand(String cmd) {
139 if (cmd == null) {
140 return handleDefaultCommands(null);
141 }
142
143 switch (cmd) {
144 case IMS_SUBCOMMAND: {
145 return handleImsCommand();
146 }
Hall Liud892bec2018-11-30 14:51:45 -0800147 case NUMBER_VERIFICATION_SUBCOMMAND:
148 return handleNumberVerificationCommand();
sqian9d4df8b2019-01-15 18:32:07 -0800149 case EMERGENCY_NUMBER_TEST_MODE:
150 return handleEmergencyNumberTestModeCommand();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100151 case CARRIER_CONFIG_SUBCOMMAND: {
152 return handleCcCommand();
153 }
Shuo Qianf5125122019-12-16 17:03:07 -0800154 case DATA_TEST_MODE:
155 return handleDataTestModeCommand();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700156 default: {
157 return handleDefaultCommands(cmd);
158 }
159 }
160 }
161
162 @Override
163 public void onHelp() {
164 PrintWriter pw = getOutPrintWriter();
165 pw.println("Telephony Commands:");
166 pw.println(" help");
167 pw.println(" Print this help text.");
168 pw.println(" ims");
169 pw.println(" IMS Commands.");
sqian9d4df8b2019-01-15 18:32:07 -0800170 pw.println(" emergency-number-test-mode");
171 pw.println(" Emergency Number Test Mode Commands.");
Shuo Qianf5125122019-12-16 17:03:07 -0800172 pw.println(" data");
173 pw.println(" Data Test Mode Commands.");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100174 pw.println(" cc");
175 pw.println(" Carrier Config Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700176 onHelpIms();
sqian9d4df8b2019-01-15 18:32:07 -0800177 onHelpEmergencyNumber();
Shuo Qianf5125122019-12-16 17:03:07 -0800178 onHelpDataTestMode();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100179 onHelpCc();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700180 }
181
182 private void onHelpIms() {
183 PrintWriter pw = getOutPrintWriter();
184 pw.println("IMS Commands:");
Brad Ebinger24c29992019-12-05 13:03:21 -0800185 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700186 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
187 pw.println(" ImsService. Options are:");
188 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
189 pw.println(" is specified, it will choose the default voice SIM slot.");
190 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
191 pw.println(" -d: Override the ImsService defined in the device overlay.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800192 pw.println(" -f: Set the feature that this override if for, if no option is");
193 pw.println(" specified, the new package name will be used for all features.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700194 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
195 pw.println(" Gets the package name of the currently defined ImsService.");
196 pw.println(" Options are:");
197 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
198 pw.println(" is specified, it will choose the default voice SIM slot.");
199 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
200 pw.println(" -c: The ImsService defined as the device default ImsService.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800201 pw.println(" -f: The feature type that the query will be requested for. If none is");
202 pw.println(" specified, the returned package name will correspond to MMTEL.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700203 pw.println(" ims enable [-s SLOT_ID]");
204 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
205 pw.println(" if none is specified.");
206 pw.println(" ims disable [-s SLOT_ID]");
207 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
208 pw.println(" slot if none is specified.");
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700209 pw.println(" ims conference-event-package [enable/disable]");
210 pw.println(" enables or disables handling or network conference event package data.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700211 }
212
Hall Liud892bec2018-11-30 14:51:45 -0800213 private void onHelpNumberVerification() {
214 PrintWriter pw = getOutPrintWriter();
215 pw.println("Number verification commands");
216 pw.println(" numverify override-package PACKAGE_NAME;");
217 pw.println(" Set the authorized package for number verification.");
218 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800219 pw.println(" numverify fake-call NUMBER;");
220 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
221 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800222 }
223
Shuo Qianf5125122019-12-16 17:03:07 -0800224 private void onHelpDataTestMode() {
225 PrintWriter pw = getOutPrintWriter();
226 pw.println("Mobile Data Test Mode Commands:");
227 pw.println(" data enable: enable mobile data connectivity");
228 pw.println(" data disable: disable mobile data connectivity");
229 }
230
sqian9d4df8b2019-01-15 18:32:07 -0800231 private void onHelpEmergencyNumber() {
232 PrintWriter pw = getOutPrintWriter();
233 pw.println("Emergency Number Test Mode Commands:");
234 pw.println(" emergency-number-test-mode ");
235 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
236 + " the test mode");
237 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian9121f982019-03-14 19:45:39 -0700238 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800239 pw.println(" -c: clear the emergency number list in the test mode.");
240 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian9121f982019-03-14 19:45:39 -0700241 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800242 pw.println(" -p: get the full emergency number list in the test mode.");
243 }
244
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100245 private void onHelpCc() {
246 PrintWriter pw = getOutPrintWriter();
247 pw.println("Carrier Config Commands:");
248 pw.println(" cc get-value [-s SLOT_ID] [KEY]");
249 pw.println(" Print carrier config values.");
250 pw.println(" Options are:");
251 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
252 pw.println(" is specified, it will choose the default voice SIM slot.");
253 pw.println(" KEY: The key to the carrier config value to print. All values are printed");
254 pw.println(" if KEY is not specified.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100255 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100256 pw.println(" Set carrier config KEY to NEW_VALUE.");
257 pw.println(" Options are:");
258 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
259 pw.println(" is specified, it will choose the default voice SIM slot.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100260 pw.println(" -p: Value will be stored persistent");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100261 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be");
262 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
263 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
264 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
265 pw.println(" cc clear-values [-s SLOT_ID]");
266 pw.println(" Clear all carrier override values that has previously been set");
267 pw.println(" with set-value");
268 pw.println(" Options are:");
269 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
270 pw.println(" is specified, it will choose the default voice SIM slot.");
271 }
272
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700273 private int handleImsCommand() {
274 String arg = getNextArg();
275 if (arg == null) {
276 onHelpIms();
277 return 0;
278 }
279
280 switch (arg) {
281 case IMS_SET_CARRIER_SERVICE: {
282 return handleImsSetServiceCommand();
283 }
284 case IMS_GET_CARRIER_SERVICE: {
285 return handleImsGetServiceCommand();
286 }
287 case IMS_ENABLE: {
288 return handleEnableIms();
289 }
290 case IMS_DISABLE: {
291 return handleDisableIms();
292 }
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700293 case IMS_CEP: {
294 return handleCepChange();
295 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700296 }
297
298 return -1;
299 }
300
Shuo Qianf5125122019-12-16 17:03:07 -0800301 private int handleDataTestModeCommand() {
302 PrintWriter errPw = getErrPrintWriter();
303 String arg = getNextArgRequired();
304 if (arg == null) {
305 onHelpDataTestMode();
306 return 0;
307 }
308 switch (arg) {
309 case DATA_ENABLE: {
310 try {
311 mInterface.enableDataConnectivity();
312 } catch (RemoteException ex) {
313 Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
314 errPw.println("Exception: " + ex.getMessage());
315 return -1;
316 }
317 break;
318 }
319 case DATA_DISABLE: {
320 try {
321 mInterface.disableDataConnectivity();
322 } catch (RemoteException ex) {
323 Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
324 errPw.println("Exception: " + ex.getMessage());
325 return -1;
326 }
327 break;
328 }
329 default:
330 onHelpDataTestMode();
331 break;
332 }
333 return 0;
334 }
335
sqian9d4df8b2019-01-15 18:32:07 -0800336 private int handleEmergencyNumberTestModeCommand() {
337 PrintWriter errPw = getErrPrintWriter();
338 String opt = getNextOption();
339 if (opt == null) {
340 onHelpEmergencyNumber();
341 return 0;
342 }
343
344 switch (opt) {
345 case "-a": {
346 String emergencyNumberCmd = getNextArgRequired();
347 if (emergencyNumberCmd == null
348 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700349 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800350 + " to be specified after -a in the command ");
351 return -1;
352 }
353 try {
354 mInterface.updateEmergencyNumberListTestMode(
355 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
356 new EmergencyNumber(emergencyNumberCmd, "", "",
357 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
358 new ArrayList<String>(),
359 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
360 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
361 } catch (RemoteException ex) {
362 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
363 + ", error " + ex.getMessage());
364 errPw.println("Exception: " + ex.getMessage());
365 return -1;
366 }
367 break;
368 }
369 case "-c": {
370 try {
371 mInterface.updateEmergencyNumberListTestMode(
372 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
373 } catch (RemoteException ex) {
374 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
375 errPw.println("Exception: " + ex.getMessage());
376 return -1;
377 }
378 break;
379 }
380 case "-r": {
381 String emergencyNumberCmd = getNextArgRequired();
382 if (emergencyNumberCmd == null
383 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700384 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800385 + " to be specified after -r in the command ");
386 return -1;
387 }
388 try {
389 mInterface.updateEmergencyNumberListTestMode(
390 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
391 new EmergencyNumber(emergencyNumberCmd, "", "",
392 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
393 new ArrayList<String>(),
394 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
395 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
396 } catch (RemoteException ex) {
397 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
398 + ", error " + ex.getMessage());
399 errPw.println("Exception: " + ex.getMessage());
400 return -1;
401 }
402 break;
403 }
404 case "-p": {
405 try {
406 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
407 } catch (RemoteException ex) {
408 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
409 errPw.println("Exception: " + ex.getMessage());
410 return -1;
411 }
412 break;
413 }
414 default:
415 onHelpEmergencyNumber();
416 break;
417 }
418 return 0;
419 }
420
Hall Liud892bec2018-11-30 14:51:45 -0800421 private int handleNumberVerificationCommand() {
422 String arg = getNextArg();
423 if (arg == null) {
424 onHelpNumberVerification();
425 return 0;
426 }
427
Hall Liuca5af3a2018-12-04 16:58:23 -0800428 if (!checkShellUid()) {
429 return -1;
430 }
431
Hall Liud892bec2018-11-30 14:51:45 -0800432 switch (arg) {
433 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800434 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
435 return 0;
436 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800437 case NUMBER_VERIFICATION_FAKE_CALL: {
438 boolean val = NumberVerificationManager.getInstance()
439 .checkIncomingCall(getNextArg());
440 getOutPrintWriter().println(val ? "1" : "0");
441 return 0;
442 }
Hall Liud892bec2018-11-30 14:51:45 -0800443 }
444
445 return -1;
446 }
447
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700448 // ims set-ims-service
449 private int handleImsSetServiceCommand() {
450 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700451 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700452 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800453 List<Integer> featuresList = new ArrayList<>();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700454
455 String opt;
456 while ((opt = getNextOption()) != null) {
457 switch (opt) {
458 case "-s": {
459 try {
460 slotId = Integer.parseInt(getNextArgRequired());
461 } catch (NumberFormatException e) {
462 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
463 return -1;
464 }
465 break;
466 }
467 case "-c": {
468 isCarrierService = true;
469 break;
470 }
471 case "-d": {
472 isCarrierService = false;
473 break;
474 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800475 case "-f": {
476 String featureString = getNextArgRequired();
477 String[] features = featureString.split(",");
478 for (int i = 0; i < features.length; i++) {
479 try {
480 Integer result = Integer.parseInt(features[i]);
481 if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
482 || result >= ImsFeature.FEATURE_MAX) {
483 errPw.println("ims set-ims-service -f " + result
484 + " is an invalid feature.");
485 return -1;
486 }
487 featuresList.add(result);
488 } catch (NumberFormatException e) {
489 errPw.println("ims set-ims-service -f tried to parse " + features[i]
490 + " as an integer.");
491 return -1;
492 }
493 }
494 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700495 }
496 }
497 // Mandatory param, either -c or -d
498 if (isCarrierService == null) {
499 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
500 return -1;
501 }
502
503 String packageName = getNextArg();
504
505 try {
506 if (packageName == null) {
507 packageName = "";
508 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800509 int[] featureArray = new int[featuresList.size()];
510 for (int i = 0; i < featuresList.size(); i++) {
511 featureArray[i] = featuresList.get(i);
512 }
513 boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
514 featureArray, packageName);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700515 if (VDBG) {
516 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800517 + (isCarrierService ? "-c " : "-d ")
518 + "-f " + featuresList + " "
519 + packageName + ", result=" + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700520 }
521 getOutPrintWriter().println(result);
522 } catch (RemoteException e) {
523 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800524 + (isCarrierService ? "-c " : "-d ")
525 + "-f " + featuresList + " "
526 + packageName + ", error" + e.getMessage());
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700527 errPw.println("Exception: " + e.getMessage());
528 return -1;
529 }
530 return 0;
531 }
532
533 // ims get-ims-service
534 private int handleImsGetServiceCommand() {
535 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700536 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700537 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800538 Integer featureType = ImsFeature.FEATURE_MMTEL;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700539
540 String opt;
541 while ((opt = getNextOption()) != null) {
542 switch (opt) {
543 case "-s": {
544 try {
545 slotId = Integer.parseInt(getNextArgRequired());
546 } catch (NumberFormatException e) {
547 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
548 return -1;
549 }
550 break;
551 }
552 case "-c": {
553 isCarrierService = true;
554 break;
555 }
556 case "-d": {
557 isCarrierService = false;
558 break;
559 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800560 case "-f": {
561 try {
562 featureType = Integer.parseInt(getNextArg());
563 } catch (NumberFormatException e) {
564 errPw.println("ims get-ims-service -f requires valid integer as feature.");
565 return -1;
566 }
567 if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
568 || featureType >= ImsFeature.FEATURE_MAX) {
569 errPw.println("ims get-ims-service -f invalid feature.");
570 return -1;
571 }
572 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700573 }
574 }
575 // Mandatory param, either -c or -d
576 if (isCarrierService == null) {
Brad Ebinger24c29992019-12-05 13:03:21 -0800577 errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700578 return -1;
579 }
580
581 String result;
582 try {
Brad Ebinger24c29992019-12-05 13:03:21 -0800583 result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700584 } catch (RemoteException e) {
585 return -1;
586 }
587 if (VDBG) {
588 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800589 + (isCarrierService ? "-c " : "-d ")
590 + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
591 + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700592 }
593 getOutPrintWriter().println(result);
594 return 0;
595 }
596
597 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700598 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700599 String opt;
600 while ((opt = getNextOption()) != null) {
601 switch (opt) {
602 case "-s": {
603 try {
604 slotId = Integer.parseInt(getNextArgRequired());
605 } catch (NumberFormatException e) {
606 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
607 return -1;
608 }
609 break;
610 }
611 }
612 }
613 try {
614 mInterface.enableIms(slotId);
615 } catch (RemoteException e) {
616 return -1;
617 }
618 if (VDBG) {
619 Log.v(LOG_TAG, "ims enable -s " + slotId);
620 }
621 return 0;
622 }
623
624 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700625 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700626 String opt;
627 while ((opt = getNextOption()) != null) {
628 switch (opt) {
629 case "-s": {
630 try {
631 slotId = Integer.parseInt(getNextArgRequired());
632 } catch (NumberFormatException e) {
633 getErrPrintWriter().println(
634 "ims disable requires an integer as a SLOT_ID.");
635 return -1;
636 }
637 break;
638 }
639 }
640 }
641 try {
642 mInterface.disableIms(slotId);
643 } catch (RemoteException e) {
644 return -1;
645 }
646 if (VDBG) {
647 Log.v(LOG_TAG, "ims disable -s " + slotId);
648 }
649 return 0;
650 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700651
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700652 private int handleCepChange() {
653 Log.i(LOG_TAG, "handleCepChange");
654 String opt = getNextArg();
655 if (opt == null) {
656 return -1;
657 }
658 boolean isCepEnabled = opt.equals("enable");
659
660 try {
661 mInterface.setCepEnabled(isCepEnabled);
662 } catch (RemoteException e) {
663 return -1;
664 }
665 return 0;
666 }
667
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700668 private int getDefaultSlot() {
669 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
670 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
671 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
672 // If there is no default, default to slot 0.
673 slotId = DEFAULT_PHONE_ID;
674 }
675 return slotId;
676 }
sqian2fff4a32018-11-05 14:18:37 -0800677
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100678 // Parse options related to Carrier Config Commands.
679 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100680 PrintWriter errPw = getErrPrintWriter();
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100681 CcOptionParseResult result = new CcOptionParseResult();
682 result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
683 result.mPersistent = false;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100684
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100685 String opt;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100686 while ((opt = getNextOption()) != null) {
687 switch (opt) {
688 case "-s": {
689 try {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100690 result.mSubId = slotStringToSubId(tag, getNextArgRequired());
691 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
692 errPw.println(tag + "No valid subscription found.");
693 return null;
694 }
695
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100696 } catch (IllegalArgumentException e) {
697 // Missing slot id
698 errPw.println(tag + "SLOT_ID expected after -s.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100699 return null;
700 }
701 break;
702 }
703 case "-p": {
704 if (allowOptionPersistent) {
705 result.mPersistent = true;
706 } else {
707 errPw.println(tag + "Unexpected option " + opt);
708 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100709 }
710 break;
711 }
712 default: {
713 errPw.println(tag + "Unknown option " + opt);
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100714 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100715 }
716 }
717 }
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100718 return result;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100719 }
720
721 private int slotStringToSubId(String tag, String slotString) {
722 int slotId = -1;
723 try {
724 slotId = Integer.parseInt(slotString);
725 } catch (NumberFormatException e) {
726 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
727 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
728 }
729
730 SubscriptionInfo subInfo =
731 mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(slotId);
732 if (subInfo == null) {
733 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
734 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
735 }
736 return subInfo.getSubscriptionId();
737 }
738
Hall Liud892bec2018-11-30 14:51:45 -0800739 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -0800740 // adb can run as root or as shell, depending on whether the device is rooted.
741 return Binder.getCallingUid() == Process.SHELL_UID
742 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -0800743 }
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100744
745 private int handleCcCommand() {
746 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
747 // non user build.
Meng Wangc4f61042019-11-21 10:51:05 -0800748 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100749 getErrPrintWriter().println("cc: Permission denied.");
750 return -1;
751 }
752
753 String arg = getNextArg();
754 if (arg == null) {
755 onHelpCc();
756 return 0;
757 }
758
759 switch (arg) {
760 case CC_GET_VALUE: {
761 return handleCcGetValue();
762 }
763 case CC_SET_VALUE: {
764 return handleCcSetValue();
765 }
766 case CC_CLEAR_VALUES: {
767 return handleCcClearValues();
768 }
769 default: {
770 getErrPrintWriter().println("cc: Unknown argument: " + arg);
771 }
772 }
773 return -1;
774 }
775
776 // cc get-value
777 private int handleCcGetValue() {
778 PrintWriter errPw = getErrPrintWriter();
779 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
780 String key = null;
781
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100782 // Parse all options
783 CcOptionParseResult options = parseCcOptions(tag, false);
784 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100785 return -1;
786 }
787
788 // Get bundle containing all carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100789 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100790 if (bundle == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100791 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100792 return -1;
793 }
794
795 // Get the key.
796 key = getNextArg();
797 if (key != null) {
798 // A key was provided. Verify if it is a valid key
799 if (!bundle.containsKey(key)) {
800 errPw.println(tag + key + " is not a valid key.");
801 return -1;
802 }
803
804 // Print the carrier config value for key.
805 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
806 } else {
807 // No key provided. Show all values.
808 // Iterate over a sorted list of all carrier config keys and print them.
809 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
810 for (String k : sortedSet) {
811 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
812 }
813 }
814 return 0;
815 }
816
817 // cc set-value
818 private int handleCcSetValue() {
819 PrintWriter errPw = getErrPrintWriter();
820 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
821
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100822 // Parse all options
823 CcOptionParseResult options = parseCcOptions(tag, true);
824 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100825 return -1;
826 }
827
828 // Get bundle containing all current carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100829 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100830 if (originalValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100831 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100832 return -1;
833 }
834
835 // Get the key.
836 String key = getNextArg();
837 if (key == null || key.equals("")) {
838 errPw.println(tag + "KEY is missing");
839 return -1;
840 }
841
842 // Verify if the key is valid
843 if (!originalValues.containsKey(key)) {
844 errPw.println(tag + key + " is not a valid key.");
845 return -1;
846 }
847
848 // Remaining arguments is a list of new values. Add them all into an ArrayList.
849 ArrayList<String> valueList = new ArrayList<String>();
850 while (peekNextArg() != null) {
851 valueList.add(getNextArg());
852 }
853
854 // Find the type of the carrier config value
855 CcType type = getType(tag, key, originalValues);
856 if (type == CcType.UNKNOWN) {
857 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
858 return -1;
859 }
860
861 // Create an override bundle containing the key and value that should be overriden.
862 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
863 if (overrideBundle == null) {
864 return -1;
865 }
866
867 // Override the value
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100868 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100869
870 // Find bundle containing all new carrier configuration values after the override.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100871 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100872 if (newValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100873 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100874 return -1;
875 }
876
877 // Print the original and new value.
878 String originalValueString = ccValueToString(key, type, originalValues);
879 String newValueString = ccValueToString(key, type, newValues);
880 getOutPrintWriter().println("Previous value: \n" + originalValueString);
881 getOutPrintWriter().println("New value: \n" + newValueString);
882
883 return 0;
884 }
885
886 // cc clear-values
887 private int handleCcClearValues() {
888 PrintWriter errPw = getErrPrintWriter();
889 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
890
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100891 // Parse all options
892 CcOptionParseResult options = parseCcOptions(tag, false);
893 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100894 return -1;
895 }
896
897 // Clear all values that has previously been set.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100898 mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100899 getOutPrintWriter()
900 .println("All previously set carrier config override values has been cleared");
901 return 0;
902 }
903
904 private CcType getType(String tag, String key, PersistableBundle bundle) {
905 // Find the type by checking the type of the current value stored in the bundle.
906 Object value = bundle.get(key);
907
908 if (CC_TYPE_MAP.containsKey(key)) {
909 return CC_TYPE_MAP.get(key);
910 } else if (value != null) {
911 if (value instanceof Boolean) {
912 return CcType.BOOLEAN;
913 } else if (value instanceof Double) {
914 return CcType.DOUBLE;
915 } else if (value instanceof double[]) {
916 return CcType.DOUBLE_ARRAY;
917 } else if (value instanceof Integer) {
918 return CcType.INT;
919 } else if (value instanceof int[]) {
920 return CcType.INT_ARRAY;
921 } else if (value instanceof Long) {
922 return CcType.LONG;
923 } else if (value instanceof long[]) {
924 return CcType.LONG_ARRAY;
925 } else if (value instanceof String) {
926 return CcType.STRING;
927 } else if (value instanceof String[]) {
928 return CcType.STRING_ARRAY;
929 }
930 } else {
931 // Current value was null and can therefore not be used in order to find the type.
932 // Check the name of the key to infer the type. This check is not needed for primitive
933 // data types (boolean, double, int and long), since they can not be null.
934 if (key.endsWith("double_array")) {
935 return CcType.DOUBLE_ARRAY;
936 }
937 if (key.endsWith("int_array")) {
938 return CcType.INT_ARRAY;
939 }
940 if (key.endsWith("long_array")) {
941 return CcType.LONG_ARRAY;
942 }
943 if (key.endsWith("string")) {
944 return CcType.STRING;
945 }
946 if (key.endsWith("string_array") || key.endsWith("strings")) {
947 return CcType.STRING_ARRAY;
948 }
949 }
950
951 // Not possible to infer the type by looking at the current value or the key.
952 PrintWriter errPw = getErrPrintWriter();
953 errPw.println(tag + "ERROR: " + key + " has unknown type.");
954 return CcType.UNKNOWN;
955 }
956
957 private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
958 String result;
959 StringBuilder valueString = new StringBuilder();
960 String typeString = type.toString();
961 Object value = bundle.get(key);
962
963 if (value == null) {
964 valueString.append("null");
965 } else {
966 switch (type) {
967 case DOUBLE_ARRAY: {
968 // Format the string representation of the int array as value1 value2......
969 double[] valueArray = (double[]) value;
970 for (int i = 0; i < valueArray.length; i++) {
971 if (i != 0) {
972 valueString.append(" ");
973 }
974 valueString.append(valueArray[i]);
975 }
976 break;
977 }
978 case INT_ARRAY: {
979 // Format the string representation of the int array as value1 value2......
980 int[] valueArray = (int[]) value;
981 for (int i = 0; i < valueArray.length; i++) {
982 if (i != 0) {
983 valueString.append(" ");
984 }
985 valueString.append(valueArray[i]);
986 }
987 break;
988 }
989 case LONG_ARRAY: {
990 // Format the string representation of the int array as value1 value2......
991 long[] valueArray = (long[]) value;
992 for (int i = 0; i < valueArray.length; i++) {
993 if (i != 0) {
994 valueString.append(" ");
995 }
996 valueString.append(valueArray[i]);
997 }
998 break;
999 }
1000 case STRING: {
1001 valueString.append("\"" + value.toString() + "\"");
1002 break;
1003 }
1004 case STRING_ARRAY: {
1005 // Format the string representation of the string array as "value1" "value2"....
1006 String[] valueArray = (String[]) value;
1007 for (int i = 0; i < valueArray.length; i++) {
1008 if (i != 0) {
1009 valueString.append(" ");
1010 }
1011 if (valueArray[i] != null) {
1012 valueString.append("\"" + valueArray[i] + "\"");
1013 } else {
1014 valueString.append("null");
1015 }
1016 }
1017 break;
1018 }
1019 default: {
1020 valueString.append(value.toString());
1021 }
1022 }
1023 }
1024 return String.format("%-70s %-15s %s", key, typeString, valueString);
1025 }
1026
1027 private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
1028 ArrayList<String> valueList) {
1029 PrintWriter errPw = getErrPrintWriter();
1030 PersistableBundle bundle = new PersistableBundle();
1031
1032 // First verify that a valid number of values has been provided for the type.
1033 switch (type) {
1034 case BOOLEAN:
1035 case DOUBLE:
1036 case INT:
1037 case LONG: {
1038 if (valueList.size() != 1) {
1039 errPw.println(tag + "Expected 1 value for type " + type
1040 + ". Found: " + valueList.size());
1041 return null;
1042 }
1043 break;
1044 }
1045 case STRING: {
1046 if (valueList.size() > 1) {
1047 errPw.println(tag + "Expected 0 or 1 values for type " + type
1048 + ". Found: " + valueList.size());
1049 return null;
1050 }
1051 break;
1052 }
1053 }
1054
1055 // Parse the value according to type and add it to the Bundle.
1056 switch (type) {
1057 case BOOLEAN: {
1058 if ("true".equalsIgnoreCase(valueList.get(0))) {
1059 bundle.putBoolean(key, true);
1060 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1061 bundle.putBoolean(key, false);
1062 } else {
1063 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1064 return null;
1065 }
1066 break;
1067 }
1068 case DOUBLE: {
1069 try {
1070 bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1071 } catch (NumberFormatException nfe) {
1072 // Not a valid double
1073 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1074 return null;
1075 }
1076 break;
1077 }
1078 case DOUBLE_ARRAY: {
1079 double[] valueDoubleArray = null;
1080 if (valueList.size() > 0) {
1081 valueDoubleArray = new double[valueList.size()];
1082 for (int i = 0; i < valueList.size(); i++) {
1083 try {
1084 valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1085 } catch (NumberFormatException nfe) {
1086 // Not a valid double
1087 errPw.println(
1088 tag + "Unable to parse " + valueList.get(i) + " as a double.");
1089 return null;
1090 }
1091 }
1092 }
1093 bundle.putDoubleArray(key, valueDoubleArray);
1094 break;
1095 }
1096 case INT: {
1097 try {
1098 bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1099 } catch (NumberFormatException nfe) {
1100 // Not a valid integer
1101 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1102 return null;
1103 }
1104 break;
1105 }
1106 case INT_ARRAY: {
1107 int[] valueIntArray = null;
1108 if (valueList.size() > 0) {
1109 valueIntArray = new int[valueList.size()];
1110 for (int i = 0; i < valueList.size(); i++) {
1111 try {
1112 valueIntArray[i] = Integer.parseInt(valueList.get(i));
1113 } catch (NumberFormatException nfe) {
1114 // Not a valid integer
1115 errPw.println(tag
1116 + "Unable to parse " + valueList.get(i) + " as an integer.");
1117 return null;
1118 }
1119 }
1120 }
1121 bundle.putIntArray(key, valueIntArray);
1122 break;
1123 }
1124 case LONG: {
1125 try {
1126 bundle.putLong(key, Long.parseLong(valueList.get(0)));
1127 } catch (NumberFormatException nfe) {
1128 // Not a valid long
1129 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1130 return null;
1131 }
1132 break;
1133 }
1134 case LONG_ARRAY: {
1135 long[] valueLongArray = null;
1136 if (valueList.size() > 0) {
1137 valueLongArray = new long[valueList.size()];
1138 for (int i = 0; i < valueList.size(); i++) {
1139 try {
1140 valueLongArray[i] = Long.parseLong(valueList.get(i));
1141 } catch (NumberFormatException nfe) {
1142 // Not a valid long
1143 errPw.println(
1144 tag + "Unable to parse " + valueList.get(i) + " as a long");
1145 return null;
1146 }
1147 }
1148 }
1149 bundle.putLongArray(key, valueLongArray);
1150 break;
1151 }
1152 case STRING: {
1153 String value = null;
1154 if (valueList.size() > 0) {
1155 value = valueList.get(0);
1156 }
1157 bundle.putString(key, value);
1158 break;
1159 }
1160 case STRING_ARRAY: {
1161 String[] valueStringArray = null;
1162 if (valueList.size() > 0) {
1163 valueStringArray = new String[valueList.size()];
1164 valueList.toArray(valueStringArray);
1165 }
1166 bundle.putStringArray(key, valueStringArray);
1167 break;
1168 }
1169 }
1170 return bundle;
1171 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001172}