blob: 0806fd11e6d9c7ba1a6ba1f482eb00f18b71f9ac [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 Ebinger4dc095a2018-04-03 15:17:52 -070029import android.util.Log;
30
31import com.android.internal.telephony.ITelephony;
sqian9d4df8b2019-01-15 18:32:07 -080032import com.android.internal.telephony.emergency.EmergencyNumberTracker;
Meng Wangc4f61042019-11-21 10:51:05 -080033import com.android.internal.telephony.util.TelephonyUtils;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070034
35import java.io.PrintWriter;
sqian9d4df8b2019-01-15 18:32:07 -080036import java.util.ArrayList;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010037import java.util.HashMap;
38import java.util.Map;
39import java.util.TreeSet;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070040
41/**
42 * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
43 * permission checks have been done before onCommand was called. Make sure any commands processed
44 * here also contain the appropriate permissions checks.
45 */
46
47public class TelephonyShellCommand extends ShellCommand {
48
49 private static final String LOG_TAG = "TelephonyShellCommand";
50 // Don't commit with this true.
51 private static final boolean VDBG = true;
Brad Ebinger0aa2f242018-04-12 09:49:23 -070052 private static final int DEFAULT_PHONE_ID = 0;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070053
54 private static final String IMS_SUBCOMMAND = "ims";
Hall Liud892bec2018-11-30 14:51:45 -080055 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
sqian9d4df8b2019-01-15 18:32:07 -080056 private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010057 private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
Shuo Qianf5125122019-12-16 17:03:07 -080058 private static final String DATA_TEST_MODE = "data";
59 private static final String DATA_ENABLE = "enable";
60 private static final String DATA_DISABLE = "disable";
Hall Liud892bec2018-11-30 14:51:45 -080061
Brad Ebinger4dc095a2018-04-03 15:17:52 -070062 private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
63 private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
64 private static final String IMS_ENABLE = "enable";
65 private static final String IMS_DISABLE = "disable";
Tyler Gunn7bcdc742019-10-04 15:56:59 -070066 // Used to disable or enable processing of conference event package data from the network.
67 // This is handy for testing scenarios where CEP data does not exist on a network which does
68 // support CEP data.
69 private static final String IMS_CEP = "conference-event-package";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070070
Hall Liud892bec2018-11-30 14:51:45 -080071 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080072 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080073
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010074 private static final String CC_GET_VALUE = "get-value";
75 private static final String CC_SET_VALUE = "set-value";
76 private static final String CC_CLEAR_VALUES = "clear-values";
77
Brad Ebinger4dc095a2018-04-03 15:17:52 -070078 // Take advantage of existing methods that already contain permissions checks when possible.
79 private final ITelephony mInterface;
80
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010081 private SubscriptionManager mSubscriptionManager;
82 private CarrierConfigManager mCarrierConfigManager;
83
84 private enum CcType {
85 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
86 STRING_ARRAY, UNKNOWN
87 }
88
Torbjorn Eklundcbd73752019-02-13 11:16:25 +010089 private class CcOptionParseResult {
90 public int mSubId;
91 public boolean mPersistent;
92 }
93
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010094 // Maps carrier config keys to type. It is possible to infer the type for most carrier config
95 // keys by looking at the end of the string which usually tells the type.
96 // For instance: "xxxx_string", "xxxx_string_array", etc.
97 // The carrier config keys in this map does not follow this convention. It is therefore not
98 // possible to infer the type for these keys by looking at the string.
99 private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
100 put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
101 put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
102 put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
103 put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
104 put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
105 put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
106 put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
107 put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
108 put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
109 put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
110 put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
111 CcType.STRING);
112 put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
113 CcType.STRING_ARRAY);
114 put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
115 CcType.STRING_ARRAY);
116 put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
117 put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
118 put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
119 put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
120 put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
121 put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
122 put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
123 put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
124 }
125 };
126
127 public TelephonyShellCommand(ITelephony binder, Context context) {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700128 mInterface = binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100129 mCarrierConfigManager =
130 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
131 mSubscriptionManager = (SubscriptionManager)
132 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700133 }
134
135 @Override
136 public int onCommand(String cmd) {
137 if (cmd == null) {
138 return handleDefaultCommands(null);
139 }
140
141 switch (cmd) {
142 case IMS_SUBCOMMAND: {
143 return handleImsCommand();
144 }
Hall Liud892bec2018-11-30 14:51:45 -0800145 case NUMBER_VERIFICATION_SUBCOMMAND:
146 return handleNumberVerificationCommand();
sqian9d4df8b2019-01-15 18:32:07 -0800147 case EMERGENCY_NUMBER_TEST_MODE:
148 return handleEmergencyNumberTestModeCommand();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100149 case CARRIER_CONFIG_SUBCOMMAND: {
150 return handleCcCommand();
151 }
Shuo Qianf5125122019-12-16 17:03:07 -0800152 case DATA_TEST_MODE:
153 return handleDataTestModeCommand();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700154 default: {
155 return handleDefaultCommands(cmd);
156 }
157 }
158 }
159
160 @Override
161 public void onHelp() {
162 PrintWriter pw = getOutPrintWriter();
163 pw.println("Telephony Commands:");
164 pw.println(" help");
165 pw.println(" Print this help text.");
166 pw.println(" ims");
167 pw.println(" IMS Commands.");
sqian9d4df8b2019-01-15 18:32:07 -0800168 pw.println(" emergency-number-test-mode");
169 pw.println(" Emergency Number Test Mode Commands.");
Shuo Qianf5125122019-12-16 17:03:07 -0800170 pw.println(" data");
171 pw.println(" Data Test Mode Commands.");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100172 pw.println(" cc");
173 pw.println(" Carrier Config Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700174 onHelpIms();
sqian9d4df8b2019-01-15 18:32:07 -0800175 onHelpEmergencyNumber();
Shuo Qianf5125122019-12-16 17:03:07 -0800176 onHelpDataTestMode();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100177 onHelpCc();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700178 }
179
180 private void onHelpIms() {
181 PrintWriter pw = getOutPrintWriter();
182 pw.println("IMS Commands:");
183 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d) PACKAGE_NAME");
184 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
185 pw.println(" ImsService. Options are:");
186 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
187 pw.println(" is specified, it will choose the default voice SIM slot.");
188 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
189 pw.println(" -d: Override the ImsService defined in the device overlay.");
190 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
191 pw.println(" Gets the package name of the currently defined ImsService.");
192 pw.println(" Options are:");
193 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
194 pw.println(" is specified, it will choose the default voice SIM slot.");
195 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
196 pw.println(" -c: The ImsService defined as the device default ImsService.");
197 pw.println(" ims enable [-s SLOT_ID]");
198 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
199 pw.println(" if none is specified.");
200 pw.println(" ims disable [-s SLOT_ID]");
201 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
202 pw.println(" slot if none is specified.");
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700203 pw.println(" ims conference-event-package [enable/disable]");
204 pw.println(" enables or disables handling or network conference event package data.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700205 }
206
Hall Liud892bec2018-11-30 14:51:45 -0800207 private void onHelpNumberVerification() {
208 PrintWriter pw = getOutPrintWriter();
209 pw.println("Number verification commands");
210 pw.println(" numverify override-package PACKAGE_NAME;");
211 pw.println(" Set the authorized package for number verification.");
212 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800213 pw.println(" numverify fake-call NUMBER;");
214 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
215 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800216 }
217
Shuo Qianf5125122019-12-16 17:03:07 -0800218 private void onHelpDataTestMode() {
219 PrintWriter pw = getOutPrintWriter();
220 pw.println("Mobile Data Test Mode Commands:");
221 pw.println(" data enable: enable mobile data connectivity");
222 pw.println(" data disable: disable mobile data connectivity");
223 }
224
sqian9d4df8b2019-01-15 18:32:07 -0800225 private void onHelpEmergencyNumber() {
226 PrintWriter pw = getOutPrintWriter();
227 pw.println("Emergency Number Test Mode Commands:");
228 pw.println(" emergency-number-test-mode ");
229 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
230 + " the test mode");
231 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian9121f982019-03-14 19:45:39 -0700232 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800233 pw.println(" -c: clear the emergency number list in the test mode.");
234 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian9121f982019-03-14 19:45:39 -0700235 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800236 pw.println(" -p: get the full emergency number list in the test mode.");
237 }
238
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100239 private void onHelpCc() {
240 PrintWriter pw = getOutPrintWriter();
241 pw.println("Carrier Config Commands:");
242 pw.println(" cc get-value [-s SLOT_ID] [KEY]");
243 pw.println(" Print carrier config values.");
244 pw.println(" Options are:");
245 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
246 pw.println(" is specified, it will choose the default voice SIM slot.");
247 pw.println(" KEY: The key to the carrier config value to print. All values are printed");
248 pw.println(" if KEY is not specified.");
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100249 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100250 pw.println(" Set carrier config KEY to NEW_VALUE.");
251 pw.println(" Options are:");
252 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
253 pw.println(" is specified, it will choose the default voice SIM slot.");
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100254 pw.println(" -p: Value will be stored persistent");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100255 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be");
256 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
257 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
258 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
259 pw.println(" cc clear-values [-s SLOT_ID]");
260 pw.println(" Clear all carrier override values that has previously been set");
261 pw.println(" with set-value");
262 pw.println(" Options are:");
263 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
264 pw.println(" is specified, it will choose the default voice SIM slot.");
265 }
266
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700267 private int handleImsCommand() {
268 String arg = getNextArg();
269 if (arg == null) {
270 onHelpIms();
271 return 0;
272 }
273
274 switch (arg) {
275 case IMS_SET_CARRIER_SERVICE: {
276 return handleImsSetServiceCommand();
277 }
278 case IMS_GET_CARRIER_SERVICE: {
279 return handleImsGetServiceCommand();
280 }
281 case IMS_ENABLE: {
282 return handleEnableIms();
283 }
284 case IMS_DISABLE: {
285 return handleDisableIms();
286 }
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700287 case IMS_CEP: {
288 return handleCepChange();
289 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700290 }
291
292 return -1;
293 }
294
Shuo Qianf5125122019-12-16 17:03:07 -0800295 private int handleDataTestModeCommand() {
296 PrintWriter errPw = getErrPrintWriter();
297 String arg = getNextArgRequired();
298 if (arg == null) {
299 onHelpDataTestMode();
300 return 0;
301 }
302 switch (arg) {
303 case DATA_ENABLE: {
304 try {
305 mInterface.enableDataConnectivity();
306 } catch (RemoteException ex) {
307 Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
308 errPw.println("Exception: " + ex.getMessage());
309 return -1;
310 }
311 break;
312 }
313 case DATA_DISABLE: {
314 try {
315 mInterface.disableDataConnectivity();
316 } catch (RemoteException ex) {
317 Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
318 errPw.println("Exception: " + ex.getMessage());
319 return -1;
320 }
321 break;
322 }
323 default:
324 onHelpDataTestMode();
325 break;
326 }
327 return 0;
328 }
329
sqian9d4df8b2019-01-15 18:32:07 -0800330 private int handleEmergencyNumberTestModeCommand() {
331 PrintWriter errPw = getErrPrintWriter();
332 String opt = getNextOption();
333 if (opt == null) {
334 onHelpEmergencyNumber();
335 return 0;
336 }
337
338 switch (opt) {
339 case "-a": {
340 String emergencyNumberCmd = getNextArgRequired();
341 if (emergencyNumberCmd == null
342 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700343 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800344 + " to be specified after -a in the command ");
345 return -1;
346 }
347 try {
348 mInterface.updateEmergencyNumberListTestMode(
349 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
350 new EmergencyNumber(emergencyNumberCmd, "", "",
351 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
352 new ArrayList<String>(),
353 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
354 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
355 } catch (RemoteException ex) {
356 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
357 + ", error " + ex.getMessage());
358 errPw.println("Exception: " + ex.getMessage());
359 return -1;
360 }
361 break;
362 }
363 case "-c": {
364 try {
365 mInterface.updateEmergencyNumberListTestMode(
366 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
367 } catch (RemoteException ex) {
368 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
369 errPw.println("Exception: " + ex.getMessage());
370 return -1;
371 }
372 break;
373 }
374 case "-r": {
375 String emergencyNumberCmd = getNextArgRequired();
376 if (emergencyNumberCmd == null
377 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700378 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800379 + " to be specified after -r in the command ");
380 return -1;
381 }
382 try {
383 mInterface.updateEmergencyNumberListTestMode(
384 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
385 new EmergencyNumber(emergencyNumberCmd, "", "",
386 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
387 new ArrayList<String>(),
388 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
389 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
390 } catch (RemoteException ex) {
391 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
392 + ", error " + ex.getMessage());
393 errPw.println("Exception: " + ex.getMessage());
394 return -1;
395 }
396 break;
397 }
398 case "-p": {
399 try {
400 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
401 } catch (RemoteException ex) {
402 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
403 errPw.println("Exception: " + ex.getMessage());
404 return -1;
405 }
406 break;
407 }
408 default:
409 onHelpEmergencyNumber();
410 break;
411 }
412 return 0;
413 }
414
Hall Liud892bec2018-11-30 14:51:45 -0800415 private int handleNumberVerificationCommand() {
416 String arg = getNextArg();
417 if (arg == null) {
418 onHelpNumberVerification();
419 return 0;
420 }
421
Hall Liuca5af3a2018-12-04 16:58:23 -0800422 if (!checkShellUid()) {
423 return -1;
424 }
425
Hall Liud892bec2018-11-30 14:51:45 -0800426 switch (arg) {
427 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800428 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
429 return 0;
430 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800431 case NUMBER_VERIFICATION_FAKE_CALL: {
432 boolean val = NumberVerificationManager.getInstance()
433 .checkIncomingCall(getNextArg());
434 getOutPrintWriter().println(val ? "1" : "0");
435 return 0;
436 }
Hall Liud892bec2018-11-30 14:51:45 -0800437 }
438
439 return -1;
440 }
441
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700442 // ims set-ims-service
443 private int handleImsSetServiceCommand() {
444 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700445 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700446 Boolean isCarrierService = null;
447
448 String opt;
449 while ((opt = getNextOption()) != null) {
450 switch (opt) {
451 case "-s": {
452 try {
453 slotId = Integer.parseInt(getNextArgRequired());
454 } catch (NumberFormatException e) {
455 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
456 return -1;
457 }
458 break;
459 }
460 case "-c": {
461 isCarrierService = true;
462 break;
463 }
464 case "-d": {
465 isCarrierService = false;
466 break;
467 }
468 }
469 }
470 // Mandatory param, either -c or -d
471 if (isCarrierService == null) {
472 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
473 return -1;
474 }
475
476 String packageName = getNextArg();
477
478 try {
479 if (packageName == null) {
480 packageName = "";
481 }
482 boolean result = mInterface.setImsService(slotId, isCarrierService, packageName);
483 if (VDBG) {
484 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
485 + (isCarrierService ? "-c " : "-d ") + packageName + ", result=" + result);
486 }
487 getOutPrintWriter().println(result);
488 } catch (RemoteException e) {
489 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
490 + (isCarrierService ? "-c " : "-d ") + packageName + ", error"
491 + e.getMessage());
492 errPw.println("Exception: " + e.getMessage());
493 return -1;
494 }
495 return 0;
496 }
497
498 // ims get-ims-service
499 private int handleImsGetServiceCommand() {
500 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700501 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700502 Boolean isCarrierService = null;
503
504 String opt;
505 while ((opt = getNextOption()) != null) {
506 switch (opt) {
507 case "-s": {
508 try {
509 slotId = Integer.parseInt(getNextArgRequired());
510 } catch (NumberFormatException e) {
511 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
512 return -1;
513 }
514 break;
515 }
516 case "-c": {
517 isCarrierService = true;
518 break;
519 }
520 case "-d": {
521 isCarrierService = false;
522 break;
523 }
524 }
525 }
526 // Mandatory param, either -c or -d
527 if (isCarrierService == null) {
528 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
529 return -1;
530 }
531
532 String result;
533 try {
534 result = mInterface.getImsService(slotId, isCarrierService);
535 } catch (RemoteException e) {
536 return -1;
537 }
538 if (VDBG) {
539 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
540 + (isCarrierService ? "-c " : "-d ") + ", returned: " + result);
541 }
542 getOutPrintWriter().println(result);
543 return 0;
544 }
545
546 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700547 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700548 String opt;
549 while ((opt = getNextOption()) != null) {
550 switch (opt) {
551 case "-s": {
552 try {
553 slotId = Integer.parseInt(getNextArgRequired());
554 } catch (NumberFormatException e) {
555 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
556 return -1;
557 }
558 break;
559 }
560 }
561 }
562 try {
563 mInterface.enableIms(slotId);
564 } catch (RemoteException e) {
565 return -1;
566 }
567 if (VDBG) {
568 Log.v(LOG_TAG, "ims enable -s " + slotId);
569 }
570 return 0;
571 }
572
573 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700574 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700575 String opt;
576 while ((opt = getNextOption()) != null) {
577 switch (opt) {
578 case "-s": {
579 try {
580 slotId = Integer.parseInt(getNextArgRequired());
581 } catch (NumberFormatException e) {
582 getErrPrintWriter().println(
583 "ims disable requires an integer as a SLOT_ID.");
584 return -1;
585 }
586 break;
587 }
588 }
589 }
590 try {
591 mInterface.disableIms(slotId);
592 } catch (RemoteException e) {
593 return -1;
594 }
595 if (VDBG) {
596 Log.v(LOG_TAG, "ims disable -s " + slotId);
597 }
598 return 0;
599 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700600
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700601 private int handleCepChange() {
602 Log.i(LOG_TAG, "handleCepChange");
603 String opt = getNextArg();
604 if (opt == null) {
605 return -1;
606 }
607 boolean isCepEnabled = opt.equals("enable");
608
609 try {
610 mInterface.setCepEnabled(isCepEnabled);
611 } catch (RemoteException e) {
612 return -1;
613 }
614 return 0;
615 }
616
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700617 private int getDefaultSlot() {
618 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
619 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
620 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
621 // If there is no default, default to slot 0.
622 slotId = DEFAULT_PHONE_ID;
623 }
624 return slotId;
625 }
sqian2fff4a32018-11-05 14:18:37 -0800626
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100627 // Parse options related to Carrier Config Commands.
628 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100629 PrintWriter errPw = getErrPrintWriter();
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100630 CcOptionParseResult result = new CcOptionParseResult();
631 result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
632 result.mPersistent = false;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100633
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100634 String opt;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100635 while ((opt = getNextOption()) != null) {
636 switch (opt) {
637 case "-s": {
638 try {
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100639 result.mSubId = slotStringToSubId(tag, getNextArgRequired());
640 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
641 errPw.println(tag + "No valid subscription found.");
642 return null;
643 }
644
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100645 } catch (IllegalArgumentException e) {
646 // Missing slot id
647 errPw.println(tag + "SLOT_ID expected after -s.");
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100648 return null;
649 }
650 break;
651 }
652 case "-p": {
653 if (allowOptionPersistent) {
654 result.mPersistent = true;
655 } else {
656 errPw.println(tag + "Unexpected option " + opt);
657 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100658 }
659 break;
660 }
661 default: {
662 errPw.println(tag + "Unknown option " + opt);
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100663 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100664 }
665 }
666 }
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100667 return result;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100668 }
669
670 private int slotStringToSubId(String tag, String slotString) {
671 int slotId = -1;
672 try {
673 slotId = Integer.parseInt(slotString);
674 } catch (NumberFormatException e) {
675 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
676 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
677 }
678
679 SubscriptionInfo subInfo =
680 mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(slotId);
681 if (subInfo == null) {
682 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
683 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
684 }
685 return subInfo.getSubscriptionId();
686 }
687
Hall Liud892bec2018-11-30 14:51:45 -0800688 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -0800689 // adb can run as root or as shell, depending on whether the device is rooted.
690 return Binder.getCallingUid() == Process.SHELL_UID
691 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -0800692 }
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100693
694 private int handleCcCommand() {
695 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
696 // non user build.
Meng Wangc4f61042019-11-21 10:51:05 -0800697 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100698 getErrPrintWriter().println("cc: Permission denied.");
699 return -1;
700 }
701
702 String arg = getNextArg();
703 if (arg == null) {
704 onHelpCc();
705 return 0;
706 }
707
708 switch (arg) {
709 case CC_GET_VALUE: {
710 return handleCcGetValue();
711 }
712 case CC_SET_VALUE: {
713 return handleCcSetValue();
714 }
715 case CC_CLEAR_VALUES: {
716 return handleCcClearValues();
717 }
718 default: {
719 getErrPrintWriter().println("cc: Unknown argument: " + arg);
720 }
721 }
722 return -1;
723 }
724
725 // cc get-value
726 private int handleCcGetValue() {
727 PrintWriter errPw = getErrPrintWriter();
728 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
729 String key = null;
730
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100731 // Parse all options
732 CcOptionParseResult options = parseCcOptions(tag, false);
733 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100734 return -1;
735 }
736
737 // Get bundle containing all carrier configuration values.
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100738 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100739 if (bundle == null) {
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100740 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100741 return -1;
742 }
743
744 // Get the key.
745 key = getNextArg();
746 if (key != null) {
747 // A key was provided. Verify if it is a valid key
748 if (!bundle.containsKey(key)) {
749 errPw.println(tag + key + " is not a valid key.");
750 return -1;
751 }
752
753 // Print the carrier config value for key.
754 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
755 } else {
756 // No key provided. Show all values.
757 // Iterate over a sorted list of all carrier config keys and print them.
758 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
759 for (String k : sortedSet) {
760 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
761 }
762 }
763 return 0;
764 }
765
766 // cc set-value
767 private int handleCcSetValue() {
768 PrintWriter errPw = getErrPrintWriter();
769 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
770
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100771 // Parse all options
772 CcOptionParseResult options = parseCcOptions(tag, true);
773 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100774 return -1;
775 }
776
777 // Get bundle containing all current carrier configuration values.
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100778 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100779 if (originalValues == null) {
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100780 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100781 return -1;
782 }
783
784 // Get the key.
785 String key = getNextArg();
786 if (key == null || key.equals("")) {
787 errPw.println(tag + "KEY is missing");
788 return -1;
789 }
790
791 // Verify if the key is valid
792 if (!originalValues.containsKey(key)) {
793 errPw.println(tag + key + " is not a valid key.");
794 return -1;
795 }
796
797 // Remaining arguments is a list of new values. Add them all into an ArrayList.
798 ArrayList<String> valueList = new ArrayList<String>();
799 while (peekNextArg() != null) {
800 valueList.add(getNextArg());
801 }
802
803 // Find the type of the carrier config value
804 CcType type = getType(tag, key, originalValues);
805 if (type == CcType.UNKNOWN) {
806 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
807 return -1;
808 }
809
810 // Create an override bundle containing the key and value that should be overriden.
811 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
812 if (overrideBundle == null) {
813 return -1;
814 }
815
816 // Override the value
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100817 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100818
819 // Find bundle containing all new carrier configuration values after the override.
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100820 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100821 if (newValues == null) {
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100822 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100823 return -1;
824 }
825
826 // Print the original and new value.
827 String originalValueString = ccValueToString(key, type, originalValues);
828 String newValueString = ccValueToString(key, type, newValues);
829 getOutPrintWriter().println("Previous value: \n" + originalValueString);
830 getOutPrintWriter().println("New value: \n" + newValueString);
831
832 return 0;
833 }
834
835 // cc clear-values
836 private int handleCcClearValues() {
837 PrintWriter errPw = getErrPrintWriter();
838 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
839
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100840 // Parse all options
841 CcOptionParseResult options = parseCcOptions(tag, false);
842 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100843 return -1;
844 }
845
846 // Clear all values that has previously been set.
Torbjorn Eklundcbd73752019-02-13 11:16:25 +0100847 mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100848 getOutPrintWriter()
849 .println("All previously set carrier config override values has been cleared");
850 return 0;
851 }
852
853 private CcType getType(String tag, String key, PersistableBundle bundle) {
854 // Find the type by checking the type of the current value stored in the bundle.
855 Object value = bundle.get(key);
856
857 if (CC_TYPE_MAP.containsKey(key)) {
858 return CC_TYPE_MAP.get(key);
859 } else if (value != null) {
860 if (value instanceof Boolean) {
861 return CcType.BOOLEAN;
862 } else if (value instanceof Double) {
863 return CcType.DOUBLE;
864 } else if (value instanceof double[]) {
865 return CcType.DOUBLE_ARRAY;
866 } else if (value instanceof Integer) {
867 return CcType.INT;
868 } else if (value instanceof int[]) {
869 return CcType.INT_ARRAY;
870 } else if (value instanceof Long) {
871 return CcType.LONG;
872 } else if (value instanceof long[]) {
873 return CcType.LONG_ARRAY;
874 } else if (value instanceof String) {
875 return CcType.STRING;
876 } else if (value instanceof String[]) {
877 return CcType.STRING_ARRAY;
878 }
879 } else {
880 // Current value was null and can therefore not be used in order to find the type.
881 // Check the name of the key to infer the type. This check is not needed for primitive
882 // data types (boolean, double, int and long), since they can not be null.
883 if (key.endsWith("double_array")) {
884 return CcType.DOUBLE_ARRAY;
885 }
886 if (key.endsWith("int_array")) {
887 return CcType.INT_ARRAY;
888 }
889 if (key.endsWith("long_array")) {
890 return CcType.LONG_ARRAY;
891 }
892 if (key.endsWith("string")) {
893 return CcType.STRING;
894 }
895 if (key.endsWith("string_array") || key.endsWith("strings")) {
896 return CcType.STRING_ARRAY;
897 }
898 }
899
900 // Not possible to infer the type by looking at the current value or the key.
901 PrintWriter errPw = getErrPrintWriter();
902 errPw.println(tag + "ERROR: " + key + " has unknown type.");
903 return CcType.UNKNOWN;
904 }
905
906 private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
907 String result;
908 StringBuilder valueString = new StringBuilder();
909 String typeString = type.toString();
910 Object value = bundle.get(key);
911
912 if (value == null) {
913 valueString.append("null");
914 } else {
915 switch (type) {
916 case DOUBLE_ARRAY: {
917 // Format the string representation of the int array as value1 value2......
918 double[] valueArray = (double[]) value;
919 for (int i = 0; i < valueArray.length; i++) {
920 if (i != 0) {
921 valueString.append(" ");
922 }
923 valueString.append(valueArray[i]);
924 }
925 break;
926 }
927 case INT_ARRAY: {
928 // Format the string representation of the int array as value1 value2......
929 int[] valueArray = (int[]) value;
930 for (int i = 0; i < valueArray.length; i++) {
931 if (i != 0) {
932 valueString.append(" ");
933 }
934 valueString.append(valueArray[i]);
935 }
936 break;
937 }
938 case LONG_ARRAY: {
939 // Format the string representation of the int array as value1 value2......
940 long[] valueArray = (long[]) value;
941 for (int i = 0; i < valueArray.length; i++) {
942 if (i != 0) {
943 valueString.append(" ");
944 }
945 valueString.append(valueArray[i]);
946 }
947 break;
948 }
949 case STRING: {
950 valueString.append("\"" + value.toString() + "\"");
951 break;
952 }
953 case STRING_ARRAY: {
954 // Format the string representation of the string array as "value1" "value2"....
955 String[] valueArray = (String[]) value;
956 for (int i = 0; i < valueArray.length; i++) {
957 if (i != 0) {
958 valueString.append(" ");
959 }
960 if (valueArray[i] != null) {
961 valueString.append("\"" + valueArray[i] + "\"");
962 } else {
963 valueString.append("null");
964 }
965 }
966 break;
967 }
968 default: {
969 valueString.append(value.toString());
970 }
971 }
972 }
973 return String.format("%-70s %-15s %s", key, typeString, valueString);
974 }
975
976 private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
977 ArrayList<String> valueList) {
978 PrintWriter errPw = getErrPrintWriter();
979 PersistableBundle bundle = new PersistableBundle();
980
981 // First verify that a valid number of values has been provided for the type.
982 switch (type) {
983 case BOOLEAN:
984 case DOUBLE:
985 case INT:
986 case LONG: {
987 if (valueList.size() != 1) {
988 errPw.println(tag + "Expected 1 value for type " + type
989 + ". Found: " + valueList.size());
990 return null;
991 }
992 break;
993 }
994 case STRING: {
995 if (valueList.size() > 1) {
996 errPw.println(tag + "Expected 0 or 1 values for type " + type
997 + ". Found: " + valueList.size());
998 return null;
999 }
1000 break;
1001 }
1002 }
1003
1004 // Parse the value according to type and add it to the Bundle.
1005 switch (type) {
1006 case BOOLEAN: {
1007 if ("true".equalsIgnoreCase(valueList.get(0))) {
1008 bundle.putBoolean(key, true);
1009 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1010 bundle.putBoolean(key, false);
1011 } else {
1012 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1013 return null;
1014 }
1015 break;
1016 }
1017 case DOUBLE: {
1018 try {
1019 bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1020 } catch (NumberFormatException nfe) {
1021 // Not a valid double
1022 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1023 return null;
1024 }
1025 break;
1026 }
1027 case DOUBLE_ARRAY: {
1028 double[] valueDoubleArray = null;
1029 if (valueList.size() > 0) {
1030 valueDoubleArray = new double[valueList.size()];
1031 for (int i = 0; i < valueList.size(); i++) {
1032 try {
1033 valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1034 } catch (NumberFormatException nfe) {
1035 // Not a valid double
1036 errPw.println(
1037 tag + "Unable to parse " + valueList.get(i) + " as a double.");
1038 return null;
1039 }
1040 }
1041 }
1042 bundle.putDoubleArray(key, valueDoubleArray);
1043 break;
1044 }
1045 case INT: {
1046 try {
1047 bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1048 } catch (NumberFormatException nfe) {
1049 // Not a valid integer
1050 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1051 return null;
1052 }
1053 break;
1054 }
1055 case INT_ARRAY: {
1056 int[] valueIntArray = null;
1057 if (valueList.size() > 0) {
1058 valueIntArray = new int[valueList.size()];
1059 for (int i = 0; i < valueList.size(); i++) {
1060 try {
1061 valueIntArray[i] = Integer.parseInt(valueList.get(i));
1062 } catch (NumberFormatException nfe) {
1063 // Not a valid integer
1064 errPw.println(tag
1065 + "Unable to parse " + valueList.get(i) + " as an integer.");
1066 return null;
1067 }
1068 }
1069 }
1070 bundle.putIntArray(key, valueIntArray);
1071 break;
1072 }
1073 case LONG: {
1074 try {
1075 bundle.putLong(key, Long.parseLong(valueList.get(0)));
1076 } catch (NumberFormatException nfe) {
1077 // Not a valid long
1078 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1079 return null;
1080 }
1081 break;
1082 }
1083 case LONG_ARRAY: {
1084 long[] valueLongArray = null;
1085 if (valueList.size() > 0) {
1086 valueLongArray = new long[valueList.size()];
1087 for (int i = 0; i < valueList.size(); i++) {
1088 try {
1089 valueLongArray[i] = Long.parseLong(valueList.get(i));
1090 } catch (NumberFormatException nfe) {
1091 // Not a valid long
1092 errPw.println(
1093 tag + "Unable to parse " + valueList.get(i) + " as a long");
1094 return null;
1095 }
1096 }
1097 }
1098 bundle.putLongArray(key, valueLongArray);
1099 break;
1100 }
1101 case STRING: {
1102 String value = null;
1103 if (valueList.size() > 0) {
1104 value = valueList.get(0);
1105 }
1106 bundle.putString(key, value);
1107 break;
1108 }
1109 case STRING_ARRAY: {
1110 String[] valueStringArray = null;
1111 if (valueList.size() > 0) {
1112 valueStringArray = new String[valueList.size()];
1113 valueList.toArray(valueStringArray);
1114 }
1115 bundle.putStringArray(key, valueStringArray);
1116 break;
1117 }
1118 }
1119 return bundle;
1120 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001121}