blob: db2f4293d26ba75417fddbbfd27b743b02e62ad6 [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 Liud892bec2018-11-30 14:51:45 -080020import android.os.Binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010021import android.os.PersistableBundle;
Hall Liud892bec2018-11-30 14:51:45 -080022import android.os.Process;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070023import android.os.RemoteException;
24import android.os.ShellCommand;
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
49public class TelephonyShellCommand extends ShellCommand {
50
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";
Hall Liud892bec2018-11-30 14:51:45 -080060
Brad Ebinger4dc095a2018-04-03 15:17:52 -070061 private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
62 private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
63 private static final String IMS_ENABLE = "enable";
64 private static final String IMS_DISABLE = "disable";
Tyler Gunn7bcdc742019-10-04 15:56:59 -070065 // Used to disable or enable processing of conference event package data from the network.
66 // This is handy for testing scenarios where CEP data does not exist on a network which does
67 // support CEP data.
68 private static final String IMS_CEP = "conference-event-package";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070069
Hall Liud892bec2018-11-30 14:51:45 -080070 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080071 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080072
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010073 private static final String CC_GET_VALUE = "get-value";
74 private static final String CC_SET_VALUE = "set-value";
75 private static final String CC_CLEAR_VALUES = "clear-values";
76
Brad Ebinger4dc095a2018-04-03 15:17:52 -070077 // Take advantage of existing methods that already contain permissions checks when possible.
78 private final ITelephony mInterface;
79
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010080 private SubscriptionManager mSubscriptionManager;
81 private CarrierConfigManager mCarrierConfigManager;
82
83 private enum CcType {
84 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
85 STRING_ARRAY, UNKNOWN
86 }
87
Torbjorn Eklundcbd73752019-02-13 11:16:25 +010088 private class CcOptionParseResult {
89 public int mSubId;
90 public boolean mPersistent;
91 }
92
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010093 // Maps carrier config keys to type. It is possible to infer the type for most carrier config
94 // keys by looking at the end of the string which usually tells the type.
95 // For instance: "xxxx_string", "xxxx_string_array", etc.
96 // The carrier config keys in this map does not follow this convention. It is therefore not
97 // possible to infer the type for these keys by looking at the string.
98 private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
99 put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
100 put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
101 put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
102 put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
103 put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
104 put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
105 put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
106 put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
107 put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
108 put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
109 put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
110 CcType.STRING);
111 put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
112 CcType.STRING_ARRAY);
113 put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
114 CcType.STRING_ARRAY);
115 put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
116 put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
117 put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
118 put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
119 put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
120 put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
121 put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
122 put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
123 }
124 };
125
126 public TelephonyShellCommand(ITelephony binder, Context context) {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700127 mInterface = binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100128 mCarrierConfigManager =
129 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
130 mSubscriptionManager = (SubscriptionManager)
131 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700132 }
133
134 @Override
135 public int onCommand(String cmd) {
136 if (cmd == null) {
137 return handleDefaultCommands(null);
138 }
139
140 switch (cmd) {
141 case IMS_SUBCOMMAND: {
142 return handleImsCommand();
143 }
Hall Liud892bec2018-11-30 14:51:45 -0800144 case NUMBER_VERIFICATION_SUBCOMMAND:
145 return handleNumberVerificationCommand();
sqian9d4df8b2019-01-15 18:32:07 -0800146 case EMERGENCY_NUMBER_TEST_MODE:
147 return handleEmergencyNumberTestModeCommand();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100148 case CARRIER_CONFIG_SUBCOMMAND: {
149 return handleCcCommand();
150 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700151 default: {
152 return handleDefaultCommands(cmd);
153 }
154 }
155 }
156
157 @Override
158 public void onHelp() {
159 PrintWriter pw = getOutPrintWriter();
160 pw.println("Telephony Commands:");
161 pw.println(" help");
162 pw.println(" Print this help text.");
163 pw.println(" ims");
164 pw.println(" IMS Commands.");
sqian9d4df8b2019-01-15 18:32:07 -0800165 pw.println(" emergency-number-test-mode");
166 pw.println(" Emergency Number Test Mode Commands.");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100167 pw.println(" cc");
168 pw.println(" Carrier Config Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700169 onHelpIms();
sqian9d4df8b2019-01-15 18:32:07 -0800170 onHelpEmergencyNumber();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100171 onHelpCc();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700172 }
173
174 private void onHelpIms() {
175 PrintWriter pw = getOutPrintWriter();
176 pw.println("IMS Commands:");
Brad Ebinger24c29992019-12-05 13:03:21 -0800177 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700178 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
179 pw.println(" ImsService. Options are:");
180 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
181 pw.println(" is specified, it will choose the default voice SIM slot.");
182 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
183 pw.println(" -d: Override the ImsService defined in the device overlay.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800184 pw.println(" -f: Set the feature that this override if for, if no option is");
185 pw.println(" specified, the new package name will be used for all features.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700186 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
187 pw.println(" Gets the package name of the currently defined ImsService.");
188 pw.println(" Options are:");
189 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
190 pw.println(" is specified, it will choose the default voice SIM slot.");
191 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
192 pw.println(" -c: The ImsService defined as the device default ImsService.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800193 pw.println(" -f: The feature type that the query will be requested for. If none is");
194 pw.println(" specified, the returned package name will correspond to MMTEL.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700195 pw.println(" ims enable [-s SLOT_ID]");
196 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
197 pw.println(" if none is specified.");
198 pw.println(" ims disable [-s SLOT_ID]");
199 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
200 pw.println(" slot if none is specified.");
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700201 pw.println(" ims conference-event-package [enable/disable]");
202 pw.println(" enables or disables handling or network conference event package data.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700203 }
204
Hall Liud892bec2018-11-30 14:51:45 -0800205 private void onHelpNumberVerification() {
206 PrintWriter pw = getOutPrintWriter();
207 pw.println("Number verification commands");
208 pw.println(" numverify override-package PACKAGE_NAME;");
209 pw.println(" Set the authorized package for number verification.");
210 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800211 pw.println(" numverify fake-call NUMBER;");
212 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
213 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800214 }
215
sqian9d4df8b2019-01-15 18:32:07 -0800216 private void onHelpEmergencyNumber() {
217 PrintWriter pw = getOutPrintWriter();
218 pw.println("Emergency Number Test Mode Commands:");
219 pw.println(" emergency-number-test-mode ");
220 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
221 + " the test mode");
222 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian9121f982019-03-14 19:45:39 -0700223 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800224 pw.println(" -c: clear the emergency number list in the test mode.");
225 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian9121f982019-03-14 19:45:39 -0700226 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800227 pw.println(" -p: get the full emergency number list in the test mode.");
228 }
229
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100230 private void onHelpCc() {
231 PrintWriter pw = getOutPrintWriter();
232 pw.println("Carrier Config Commands:");
233 pw.println(" cc get-value [-s SLOT_ID] [KEY]");
234 pw.println(" Print carrier config values.");
235 pw.println(" Options are:");
236 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
237 pw.println(" is specified, it will choose the default voice SIM slot.");
238 pw.println(" KEY: The key to the carrier config value to print. All values are printed");
239 pw.println(" if KEY is not specified.");
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100240 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100241 pw.println(" Set carrier config KEY to NEW_VALUE.");
242 pw.println(" Options are:");
243 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
244 pw.println(" is specified, it will choose the default voice SIM slot.");
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100245 pw.println(" -p: Value will be stored persistent");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100246 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be");
247 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
248 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
249 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
250 pw.println(" cc clear-values [-s SLOT_ID]");
251 pw.println(" Clear all carrier override values that has previously been set");
252 pw.println(" with set-value");
253 pw.println(" Options are:");
254 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
255 pw.println(" is specified, it will choose the default voice SIM slot.");
256 }
257
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700258 private int handleImsCommand() {
259 String arg = getNextArg();
260 if (arg == null) {
261 onHelpIms();
262 return 0;
263 }
264
265 switch (arg) {
266 case IMS_SET_CARRIER_SERVICE: {
267 return handleImsSetServiceCommand();
268 }
269 case IMS_GET_CARRIER_SERVICE: {
270 return handleImsGetServiceCommand();
271 }
272 case IMS_ENABLE: {
273 return handleEnableIms();
274 }
275 case IMS_DISABLE: {
276 return handleDisableIms();
277 }
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700278 case IMS_CEP: {
279 return handleCepChange();
280 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700281 }
282
283 return -1;
284 }
285
sqian9d4df8b2019-01-15 18:32:07 -0800286 private int handleEmergencyNumberTestModeCommand() {
287 PrintWriter errPw = getErrPrintWriter();
288 String opt = getNextOption();
289 if (opt == null) {
290 onHelpEmergencyNumber();
291 return 0;
292 }
293
294 switch (opt) {
295 case "-a": {
296 String emergencyNumberCmd = getNextArgRequired();
297 if (emergencyNumberCmd == null
298 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700299 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800300 + " to be specified after -a in the command ");
301 return -1;
302 }
303 try {
304 mInterface.updateEmergencyNumberListTestMode(
305 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
306 new EmergencyNumber(emergencyNumberCmd, "", "",
307 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
308 new ArrayList<String>(),
309 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
310 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
311 } catch (RemoteException ex) {
312 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
313 + ", error " + ex.getMessage());
314 errPw.println("Exception: " + ex.getMessage());
315 return -1;
316 }
317 break;
318 }
319 case "-c": {
320 try {
321 mInterface.updateEmergencyNumberListTestMode(
322 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
323 } catch (RemoteException ex) {
324 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
325 errPw.println("Exception: " + ex.getMessage());
326 return -1;
327 }
328 break;
329 }
330 case "-r": {
331 String emergencyNumberCmd = getNextArgRequired();
332 if (emergencyNumberCmd == null
333 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700334 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800335 + " to be specified after -r in the command ");
336 return -1;
337 }
338 try {
339 mInterface.updateEmergencyNumberListTestMode(
340 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
341 new EmergencyNumber(emergencyNumberCmd, "", "",
342 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
343 new ArrayList<String>(),
344 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
345 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
346 } catch (RemoteException ex) {
347 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
348 + ", error " + ex.getMessage());
349 errPw.println("Exception: " + ex.getMessage());
350 return -1;
351 }
352 break;
353 }
354 case "-p": {
355 try {
356 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
357 } catch (RemoteException ex) {
358 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
359 errPw.println("Exception: " + ex.getMessage());
360 return -1;
361 }
362 break;
363 }
364 default:
365 onHelpEmergencyNumber();
366 break;
367 }
368 return 0;
369 }
370
Hall Liud892bec2018-11-30 14:51:45 -0800371 private int handleNumberVerificationCommand() {
372 String arg = getNextArg();
373 if (arg == null) {
374 onHelpNumberVerification();
375 return 0;
376 }
377
Hall Liuca5af3a2018-12-04 16:58:23 -0800378 if (!checkShellUid()) {
379 return -1;
380 }
381
Hall Liud892bec2018-11-30 14:51:45 -0800382 switch (arg) {
383 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800384 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
385 return 0;
386 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800387 case NUMBER_VERIFICATION_FAKE_CALL: {
388 boolean val = NumberVerificationManager.getInstance()
389 .checkIncomingCall(getNextArg());
390 getOutPrintWriter().println(val ? "1" : "0");
391 return 0;
392 }
Hall Liud892bec2018-11-30 14:51:45 -0800393 }
394
395 return -1;
396 }
397
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700398 // ims set-ims-service
399 private int handleImsSetServiceCommand() {
400 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700401 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700402 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800403 List<Integer> featuresList = new ArrayList<>();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700404
405 String opt;
406 while ((opt = getNextOption()) != null) {
407 switch (opt) {
408 case "-s": {
409 try {
410 slotId = Integer.parseInt(getNextArgRequired());
411 } catch (NumberFormatException e) {
412 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
413 return -1;
414 }
415 break;
416 }
417 case "-c": {
418 isCarrierService = true;
419 break;
420 }
421 case "-d": {
422 isCarrierService = false;
423 break;
424 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800425 case "-f": {
426 String featureString = getNextArgRequired();
427 String[] features = featureString.split(",");
428 for (int i = 0; i < features.length; i++) {
429 try {
430 Integer result = Integer.parseInt(features[i]);
431 if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
432 || result >= ImsFeature.FEATURE_MAX) {
433 errPw.println("ims set-ims-service -f " + result
434 + " is an invalid feature.");
435 return -1;
436 }
437 featuresList.add(result);
438 } catch (NumberFormatException e) {
439 errPw.println("ims set-ims-service -f tried to parse " + features[i]
440 + " as an integer.");
441 return -1;
442 }
443 }
444 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700445 }
446 }
447 // Mandatory param, either -c or -d
448 if (isCarrierService == null) {
449 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
450 return -1;
451 }
452
453 String packageName = getNextArg();
454
455 try {
456 if (packageName == null) {
457 packageName = "";
458 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800459 int[] featureArray = new int[featuresList.size()];
460 for (int i = 0; i < featuresList.size(); i++) {
461 featureArray[i] = featuresList.get(i);
462 }
463 boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
464 featureArray, packageName);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700465 if (VDBG) {
466 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800467 + (isCarrierService ? "-c " : "-d ")
468 + "-f " + featuresList + " "
469 + packageName + ", result=" + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700470 }
471 getOutPrintWriter().println(result);
472 } catch (RemoteException e) {
473 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800474 + (isCarrierService ? "-c " : "-d ")
475 + "-f " + featuresList + " "
476 + packageName + ", error" + e.getMessage());
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700477 errPw.println("Exception: " + e.getMessage());
478 return -1;
479 }
480 return 0;
481 }
482
483 // ims get-ims-service
484 private int handleImsGetServiceCommand() {
485 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700486 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700487 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800488 Integer featureType = ImsFeature.FEATURE_MMTEL;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700489
490 String opt;
491 while ((opt = getNextOption()) != null) {
492 switch (opt) {
493 case "-s": {
494 try {
495 slotId = Integer.parseInt(getNextArgRequired());
496 } catch (NumberFormatException e) {
497 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
498 return -1;
499 }
500 break;
501 }
502 case "-c": {
503 isCarrierService = true;
504 break;
505 }
506 case "-d": {
507 isCarrierService = false;
508 break;
509 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800510 case "-f": {
511 try {
512 featureType = Integer.parseInt(getNextArg());
513 } catch (NumberFormatException e) {
514 errPw.println("ims get-ims-service -f requires valid integer as feature.");
515 return -1;
516 }
517 if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
518 || featureType >= ImsFeature.FEATURE_MAX) {
519 errPw.println("ims get-ims-service -f invalid feature.");
520 return -1;
521 }
522 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700523 }
524 }
525 // Mandatory param, either -c or -d
526 if (isCarrierService == null) {
Brad Ebinger24c29992019-12-05 13:03:21 -0800527 errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700528 return -1;
529 }
530
531 String result;
532 try {
Brad Ebinger24c29992019-12-05 13:03:21 -0800533 result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700534 } catch (RemoteException e) {
535 return -1;
536 }
537 if (VDBG) {
538 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800539 + (isCarrierService ? "-c " : "-d ")
540 + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
541 + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700542 }
543 getOutPrintWriter().println(result);
544 return 0;
545 }
546
547 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700548 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700549 String opt;
550 while ((opt = getNextOption()) != null) {
551 switch (opt) {
552 case "-s": {
553 try {
554 slotId = Integer.parseInt(getNextArgRequired());
555 } catch (NumberFormatException e) {
556 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
557 return -1;
558 }
559 break;
560 }
561 }
562 }
563 try {
564 mInterface.enableIms(slotId);
565 } catch (RemoteException e) {
566 return -1;
567 }
568 if (VDBG) {
569 Log.v(LOG_TAG, "ims enable -s " + slotId);
570 }
571 return 0;
572 }
573
574 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700575 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700576 String opt;
577 while ((opt = getNextOption()) != null) {
578 switch (opt) {
579 case "-s": {
580 try {
581 slotId = Integer.parseInt(getNextArgRequired());
582 } catch (NumberFormatException e) {
583 getErrPrintWriter().println(
584 "ims disable requires an integer as a SLOT_ID.");
585 return -1;
586 }
587 break;
588 }
589 }
590 }
591 try {
592 mInterface.disableIms(slotId);
593 } catch (RemoteException e) {
594 return -1;
595 }
596 if (VDBG) {
597 Log.v(LOG_TAG, "ims disable -s " + slotId);
598 }
599 return 0;
600 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700601
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700602 private int handleCepChange() {
603 Log.i(LOG_TAG, "handleCepChange");
604 String opt = getNextArg();
605 if (opt == null) {
606 return -1;
607 }
608 boolean isCepEnabled = opt.equals("enable");
609
610 try {
611 mInterface.setCepEnabled(isCepEnabled);
612 } catch (RemoteException e) {
613 return -1;
614 }
615 return 0;
616 }
617
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700618 private int getDefaultSlot() {
619 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
620 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
621 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
622 // If there is no default, default to slot 0.
623 slotId = DEFAULT_PHONE_ID;
624 }
625 return slotId;
626 }
sqian2fff4a32018-11-05 14:18:37 -0800627
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100628 // Parse options related to Carrier Config Commands.
629 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100630 PrintWriter errPw = getErrPrintWriter();
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100631 CcOptionParseResult result = new CcOptionParseResult();
632 result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
633 result.mPersistent = false;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100634
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100635 String opt;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100636 while ((opt = getNextOption()) != null) {
637 switch (opt) {
638 case "-s": {
639 try {
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100640 result.mSubId = slotStringToSubId(tag, getNextArgRequired());
641 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
642 errPw.println(tag + "No valid subscription found.");
643 return null;
644 }
645
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100646 } catch (IllegalArgumentException e) {
647 // Missing slot id
648 errPw.println(tag + "SLOT_ID expected after -s.");
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100649 return null;
650 }
651 break;
652 }
653 case "-p": {
654 if (allowOptionPersistent) {
655 result.mPersistent = true;
656 } else {
657 errPw.println(tag + "Unexpected option " + opt);
658 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100659 }
660 break;
661 }
662 default: {
663 errPw.println(tag + "Unknown option " + opt);
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100664 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100665 }
666 }
667 }
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100668 return result;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100669 }
670
671 private int slotStringToSubId(String tag, String slotString) {
672 int slotId = -1;
673 try {
674 slotId = Integer.parseInt(slotString);
675 } catch (NumberFormatException e) {
676 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
677 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
678 }
679
680 SubscriptionInfo subInfo =
681 mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(slotId);
682 if (subInfo == null) {
683 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
684 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
685 }
686 return subInfo.getSubscriptionId();
687 }
688
Hall Liud892bec2018-11-30 14:51:45 -0800689 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -0800690 // adb can run as root or as shell, depending on whether the device is rooted.
691 return Binder.getCallingUid() == Process.SHELL_UID
692 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -0800693 }
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100694
695 private int handleCcCommand() {
696 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
697 // non user build.
Meng Wangc4f61042019-11-21 10:51:05 -0800698 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100699 getErrPrintWriter().println("cc: Permission denied.");
700 return -1;
701 }
702
703 String arg = getNextArg();
704 if (arg == null) {
705 onHelpCc();
706 return 0;
707 }
708
709 switch (arg) {
710 case CC_GET_VALUE: {
711 return handleCcGetValue();
712 }
713 case CC_SET_VALUE: {
714 return handleCcSetValue();
715 }
716 case CC_CLEAR_VALUES: {
717 return handleCcClearValues();
718 }
719 default: {
720 getErrPrintWriter().println("cc: Unknown argument: " + arg);
721 }
722 }
723 return -1;
724 }
725
726 // cc get-value
727 private int handleCcGetValue() {
728 PrintWriter errPw = getErrPrintWriter();
729 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
730 String key = null;
731
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100732 // Parse all options
733 CcOptionParseResult options = parseCcOptions(tag, false);
734 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100735 return -1;
736 }
737
738 // Get bundle containing all carrier configuration values.
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100739 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100740 if (bundle == null) {
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100741 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100742 return -1;
743 }
744
745 // Get the key.
746 key = getNextArg();
747 if (key != null) {
748 // A key was provided. Verify if it is a valid key
749 if (!bundle.containsKey(key)) {
750 errPw.println(tag + key + " is not a valid key.");
751 return -1;
752 }
753
754 // Print the carrier config value for key.
755 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
756 } else {
757 // No key provided. Show all values.
758 // Iterate over a sorted list of all carrier config keys and print them.
759 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
760 for (String k : sortedSet) {
761 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
762 }
763 }
764 return 0;
765 }
766
767 // cc set-value
768 private int handleCcSetValue() {
769 PrintWriter errPw = getErrPrintWriter();
770 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
771
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100772 // Parse all options
773 CcOptionParseResult options = parseCcOptions(tag, true);
774 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100775 return -1;
776 }
777
778 // Get bundle containing all current carrier configuration values.
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100779 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100780 if (originalValues == null) {
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100781 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100782 return -1;
783 }
784
785 // Get the key.
786 String key = getNextArg();
787 if (key == null || key.equals("")) {
788 errPw.println(tag + "KEY is missing");
789 return -1;
790 }
791
792 // Verify if the key is valid
793 if (!originalValues.containsKey(key)) {
794 errPw.println(tag + key + " is not a valid key.");
795 return -1;
796 }
797
798 // Remaining arguments is a list of new values. Add them all into an ArrayList.
799 ArrayList<String> valueList = new ArrayList<String>();
800 while (peekNextArg() != null) {
801 valueList.add(getNextArg());
802 }
803
804 // Find the type of the carrier config value
805 CcType type = getType(tag, key, originalValues);
806 if (type == CcType.UNKNOWN) {
807 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
808 return -1;
809 }
810
811 // Create an override bundle containing the key and value that should be overriden.
812 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
813 if (overrideBundle == null) {
814 return -1;
815 }
816
817 // Override the value
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100818 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100819
820 // Find bundle containing all new carrier configuration values after the override.
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100821 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100822 if (newValues == null) {
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100823 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100824 return -1;
825 }
826
827 // Print the original and new value.
828 String originalValueString = ccValueToString(key, type, originalValues);
829 String newValueString = ccValueToString(key, type, newValues);
830 getOutPrintWriter().println("Previous value: \n" + originalValueString);
831 getOutPrintWriter().println("New value: \n" + newValueString);
832
833 return 0;
834 }
835
836 // cc clear-values
837 private int handleCcClearValues() {
838 PrintWriter errPw = getErrPrintWriter();
839 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
840
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100841 // Parse all options
842 CcOptionParseResult options = parseCcOptions(tag, false);
843 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100844 return -1;
845 }
846
847 // Clear all values that has previously been set.
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100848 mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100849 getOutPrintWriter()
850 .println("All previously set carrier config override values has been cleared");
851 return 0;
852 }
853
854 private CcType getType(String tag, String key, PersistableBundle bundle) {
855 // Find the type by checking the type of the current value stored in the bundle.
856 Object value = bundle.get(key);
857
858 if (CC_TYPE_MAP.containsKey(key)) {
859 return CC_TYPE_MAP.get(key);
860 } else if (value != null) {
861 if (value instanceof Boolean) {
862 return CcType.BOOLEAN;
863 } else if (value instanceof Double) {
864 return CcType.DOUBLE;
865 } else if (value instanceof double[]) {
866 return CcType.DOUBLE_ARRAY;
867 } else if (value instanceof Integer) {
868 return CcType.INT;
869 } else if (value instanceof int[]) {
870 return CcType.INT_ARRAY;
871 } else if (value instanceof Long) {
872 return CcType.LONG;
873 } else if (value instanceof long[]) {
874 return CcType.LONG_ARRAY;
875 } else if (value instanceof String) {
876 return CcType.STRING;
877 } else if (value instanceof String[]) {
878 return CcType.STRING_ARRAY;
879 }
880 } else {
881 // Current value was null and can therefore not be used in order to find the type.
882 // Check the name of the key to infer the type. This check is not needed for primitive
883 // data types (boolean, double, int and long), since they can not be null.
884 if (key.endsWith("double_array")) {
885 return CcType.DOUBLE_ARRAY;
886 }
887 if (key.endsWith("int_array")) {
888 return CcType.INT_ARRAY;
889 }
890 if (key.endsWith("long_array")) {
891 return CcType.LONG_ARRAY;
892 }
893 if (key.endsWith("string")) {
894 return CcType.STRING;
895 }
896 if (key.endsWith("string_array") || key.endsWith("strings")) {
897 return CcType.STRING_ARRAY;
898 }
899 }
900
901 // Not possible to infer the type by looking at the current value or the key.
902 PrintWriter errPw = getErrPrintWriter();
903 errPw.println(tag + "ERROR: " + key + " has unknown type.");
904 return CcType.UNKNOWN;
905 }
906
907 private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
908 String result;
909 StringBuilder valueString = new StringBuilder();
910 String typeString = type.toString();
911 Object value = bundle.get(key);
912
913 if (value == null) {
914 valueString.append("null");
915 } else {
916 switch (type) {
917 case DOUBLE_ARRAY: {
918 // Format the string representation of the int array as value1 value2......
919 double[] valueArray = (double[]) value;
920 for (int i = 0; i < valueArray.length; i++) {
921 if (i != 0) {
922 valueString.append(" ");
923 }
924 valueString.append(valueArray[i]);
925 }
926 break;
927 }
928 case INT_ARRAY: {
929 // Format the string representation of the int array as value1 value2......
930 int[] valueArray = (int[]) value;
931 for (int i = 0; i < valueArray.length; i++) {
932 if (i != 0) {
933 valueString.append(" ");
934 }
935 valueString.append(valueArray[i]);
936 }
937 break;
938 }
939 case LONG_ARRAY: {
940 // Format the string representation of the int array as value1 value2......
941 long[] valueArray = (long[]) value;
942 for (int i = 0; i < valueArray.length; i++) {
943 if (i != 0) {
944 valueString.append(" ");
945 }
946 valueString.append(valueArray[i]);
947 }
948 break;
949 }
950 case STRING: {
951 valueString.append("\"" + value.toString() + "\"");
952 break;
953 }
954 case STRING_ARRAY: {
955 // Format the string representation of the string array as "value1" "value2"....
956 String[] valueArray = (String[]) value;
957 for (int i = 0; i < valueArray.length; i++) {
958 if (i != 0) {
959 valueString.append(" ");
960 }
961 if (valueArray[i] != null) {
962 valueString.append("\"" + valueArray[i] + "\"");
963 } else {
964 valueString.append("null");
965 }
966 }
967 break;
968 }
969 default: {
970 valueString.append(value.toString());
971 }
972 }
973 }
974 return String.format("%-70s %-15s %s", key, typeString, valueString);
975 }
976
977 private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
978 ArrayList<String> valueList) {
979 PrintWriter errPw = getErrPrintWriter();
980 PersistableBundle bundle = new PersistableBundle();
981
982 // First verify that a valid number of values has been provided for the type.
983 switch (type) {
984 case BOOLEAN:
985 case DOUBLE:
986 case INT:
987 case LONG: {
988 if (valueList.size() != 1) {
989 errPw.println(tag + "Expected 1 value for type " + type
990 + ". Found: " + valueList.size());
991 return null;
992 }
993 break;
994 }
995 case STRING: {
996 if (valueList.size() > 1) {
997 errPw.println(tag + "Expected 0 or 1 values for type " + type
998 + ". Found: " + valueList.size());
999 return null;
1000 }
1001 break;
1002 }
1003 }
1004
1005 // Parse the value according to type and add it to the Bundle.
1006 switch (type) {
1007 case BOOLEAN: {
1008 if ("true".equalsIgnoreCase(valueList.get(0))) {
1009 bundle.putBoolean(key, true);
1010 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1011 bundle.putBoolean(key, false);
1012 } else {
1013 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1014 return null;
1015 }
1016 break;
1017 }
1018 case DOUBLE: {
1019 try {
1020 bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1021 } catch (NumberFormatException nfe) {
1022 // Not a valid double
1023 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1024 return null;
1025 }
1026 break;
1027 }
1028 case DOUBLE_ARRAY: {
1029 double[] valueDoubleArray = null;
1030 if (valueList.size() > 0) {
1031 valueDoubleArray = new double[valueList.size()];
1032 for (int i = 0; i < valueList.size(); i++) {
1033 try {
1034 valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1035 } catch (NumberFormatException nfe) {
1036 // Not a valid double
1037 errPw.println(
1038 tag + "Unable to parse " + valueList.get(i) + " as a double.");
1039 return null;
1040 }
1041 }
1042 }
1043 bundle.putDoubleArray(key, valueDoubleArray);
1044 break;
1045 }
1046 case INT: {
1047 try {
1048 bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1049 } catch (NumberFormatException nfe) {
1050 // Not a valid integer
1051 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1052 return null;
1053 }
1054 break;
1055 }
1056 case INT_ARRAY: {
1057 int[] valueIntArray = null;
1058 if (valueList.size() > 0) {
1059 valueIntArray = new int[valueList.size()];
1060 for (int i = 0; i < valueList.size(); i++) {
1061 try {
1062 valueIntArray[i] = Integer.parseInt(valueList.get(i));
1063 } catch (NumberFormatException nfe) {
1064 // Not a valid integer
1065 errPw.println(tag
1066 + "Unable to parse " + valueList.get(i) + " as an integer.");
1067 return null;
1068 }
1069 }
1070 }
1071 bundle.putIntArray(key, valueIntArray);
1072 break;
1073 }
1074 case LONG: {
1075 try {
1076 bundle.putLong(key, Long.parseLong(valueList.get(0)));
1077 } catch (NumberFormatException nfe) {
1078 // Not a valid long
1079 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1080 return null;
1081 }
1082 break;
1083 }
1084 case LONG_ARRAY: {
1085 long[] valueLongArray = null;
1086 if (valueList.size() > 0) {
1087 valueLongArray = new long[valueList.size()];
1088 for (int i = 0; i < valueList.size(); i++) {
1089 try {
1090 valueLongArray[i] = Long.parseLong(valueList.get(i));
1091 } catch (NumberFormatException nfe) {
1092 // Not a valid long
1093 errPw.println(
1094 tag + "Unable to parse " + valueList.get(i) + " as a long");
1095 return null;
1096 }
1097 }
1098 }
1099 bundle.putLongArray(key, valueLongArray);
1100 break;
1101 }
1102 case STRING: {
1103 String value = null;
1104 if (valueList.size() > 0) {
1105 value = valueList.get(0);
1106 }
1107 bundle.putString(key, value);
1108 break;
1109 }
1110 case STRING_ARRAY: {
1111 String[] valueStringArray = null;
1112 if (valueList.size() > 0) {
1113 valueStringArray = new String[valueList.size()];
1114 valueList.toArray(valueStringArray);
1115 }
1116 bundle.putStringArray(key, valueStringArray);
1117 break;
1118 }
1119 }
1120 return bundle;
1121 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001122}