blob: 512ca03265c52d04819e38f6e569330ea76c8f97 [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;
Shuo Qian489d9282020-07-09 11:30:03 -070025import android.provider.BlockedNumberContract;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010026import android.telephony.CarrierConfigManager;
27import android.telephony.SubscriptionInfo;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070028import android.telephony.SubscriptionManager;
sqian9d4df8b2019-01-15 18:32:07 -080029import android.telephony.emergency.EmergencyNumber;
Brad Ebinger24c29992019-12-05 13:03:21 -080030import android.telephony.ims.feature.ImsFeature;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070031import android.util.Log;
32
33import com.android.internal.telephony.ITelephony;
sqian9d4df8b2019-01-15 18:32:07 -080034import com.android.internal.telephony.emergency.EmergencyNumberTracker;
Meng Wangc4f61042019-11-21 10:51:05 -080035import com.android.internal.telephony.util.TelephonyUtils;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070036
37import java.io.PrintWriter;
sqian9d4df8b2019-01-15 18:32:07 -080038import java.util.ArrayList;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010039import java.util.HashMap;
Brad Ebinger24c29992019-12-05 13:03:21 -080040import java.util.List;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010041import java.util.Map;
42import java.util.TreeSet;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070043
44/**
45 * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
46 * permission checks have been done before onCommand was called. Make sure any commands processed
47 * here also contain the appropriate permissions checks.
48 */
49
Hall Liua1548bd2019-12-24 14:14:12 -080050public class TelephonyShellCommand extends BasicShellCommandHandler {
Brad Ebinger4dc095a2018-04-03 15:17:52 -070051
52 private static final String LOG_TAG = "TelephonyShellCommand";
53 // Don't commit with this true.
54 private static final boolean VDBG = true;
Brad Ebinger0aa2f242018-04-12 09:49:23 -070055 private static final int DEFAULT_PHONE_ID = 0;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070056
57 private static final String IMS_SUBCOMMAND = "ims";
Hall Liud892bec2018-11-30 14:51:45 -080058 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
sqian9d4df8b2019-01-15 18:32:07 -080059 private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
Shuo Qian489d9282020-07-09 11:30:03 -070060 private static final String END_BLOCK_SUPPRESSION = "end-block-suppression";
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010061 private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
Shuo Qianf5125122019-12-16 17:03:07 -080062 private static final String DATA_TEST_MODE = "data";
63 private static final String DATA_ENABLE = "enable";
64 private static final String DATA_DISABLE = "disable";
Hall Liud892bec2018-11-30 14:51:45 -080065
Brad Ebinger4dc095a2018-04-03 15:17:52 -070066 private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
67 private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
68 private static final String IMS_ENABLE = "enable";
69 private static final String IMS_DISABLE = "disable";
Tyler Gunn7bcdc742019-10-04 15:56:59 -070070 // Used to disable or enable processing of conference event package data from the network.
71 // This is handy for testing scenarios where CEP data does not exist on a network which does
72 // support CEP data.
73 private static final String IMS_CEP = "conference-event-package";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070074
Hall Liud892bec2018-11-30 14:51:45 -080075 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080076 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080077
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010078 private static final String CC_GET_VALUE = "get-value";
79 private static final String CC_SET_VALUE = "set-value";
80 private static final String CC_CLEAR_VALUES = "clear-values";
81
Brad Ebinger4dc095a2018-04-03 15:17:52 -070082 // Take advantage of existing methods that already contain permissions checks when possible.
83 private final ITelephony mInterface;
84
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010085 private SubscriptionManager mSubscriptionManager;
86 private CarrierConfigManager mCarrierConfigManager;
Shuo Qian489d9282020-07-09 11:30:03 -070087 private Context mContext;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010088
89 private enum CcType {
90 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
91 STRING_ARRAY, UNKNOWN
92 }
93
Torbjorn Eklund723527a2019-02-13 11:16:25 +010094 private class CcOptionParseResult {
95 public int mSubId;
96 public boolean mPersistent;
97 }
98
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010099 // Maps carrier config keys to type. It is possible to infer the type for most carrier config
100 // keys by looking at the end of the string which usually tells the type.
101 // For instance: "xxxx_string", "xxxx_string_array", etc.
102 // The carrier config keys in this map does not follow this convention. It is therefore not
103 // possible to infer the type for these keys by looking at the string.
104 private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
105 put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
106 put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
107 put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
108 put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
109 put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
110 put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
111 put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
112 put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
113 put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
114 put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
115 put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
116 CcType.STRING);
117 put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
118 CcType.STRING_ARRAY);
119 put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
120 CcType.STRING_ARRAY);
121 put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
122 put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
123 put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
124 put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
125 put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
126 put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
127 put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
128 put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
129 }
130 };
131
132 public TelephonyShellCommand(ITelephony binder, Context context) {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700133 mInterface = binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100134 mCarrierConfigManager =
135 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
136 mSubscriptionManager = (SubscriptionManager)
137 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Shuo Qian489d9282020-07-09 11:30:03 -0700138 mContext = context;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700139 }
140
141 @Override
142 public int onCommand(String cmd) {
143 if (cmd == null) {
144 return handleDefaultCommands(null);
145 }
146
147 switch (cmd) {
148 case IMS_SUBCOMMAND: {
149 return handleImsCommand();
150 }
Hall Liud892bec2018-11-30 14:51:45 -0800151 case NUMBER_VERIFICATION_SUBCOMMAND:
152 return handleNumberVerificationCommand();
sqian9d4df8b2019-01-15 18:32:07 -0800153 case EMERGENCY_NUMBER_TEST_MODE:
154 return handleEmergencyNumberTestModeCommand();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100155 case CARRIER_CONFIG_SUBCOMMAND: {
156 return handleCcCommand();
157 }
Shuo Qianf5125122019-12-16 17:03:07 -0800158 case DATA_TEST_MODE:
159 return handleDataTestModeCommand();
Shuo Qian489d9282020-07-09 11:30:03 -0700160 case END_BLOCK_SUPPRESSION:
161 return handleEndBlockSuppressionCommand();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700162 default: {
163 return handleDefaultCommands(cmd);
164 }
165 }
166 }
167
168 @Override
169 public void onHelp() {
170 PrintWriter pw = getOutPrintWriter();
171 pw.println("Telephony Commands:");
172 pw.println(" help");
173 pw.println(" Print this help text.");
174 pw.println(" ims");
175 pw.println(" IMS Commands.");
sqian9d4df8b2019-01-15 18:32:07 -0800176 pw.println(" emergency-number-test-mode");
177 pw.println(" Emergency Number Test Mode Commands.");
Shuo Qian489d9282020-07-09 11:30:03 -0700178 pw.println(" end-block-suppression");
179 pw.println(" End Block Suppression command.");
Shuo Qianf5125122019-12-16 17:03:07 -0800180 pw.println(" data");
181 pw.println(" Data Test Mode Commands.");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100182 pw.println(" cc");
183 pw.println(" Carrier Config Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700184 onHelpIms();
sqian9d4df8b2019-01-15 18:32:07 -0800185 onHelpEmergencyNumber();
Shuo Qian489d9282020-07-09 11:30:03 -0700186 onHelpEndBlockSupperssion();
Shuo Qianf5125122019-12-16 17:03:07 -0800187 onHelpDataTestMode();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100188 onHelpCc();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700189 }
190
191 private void onHelpIms() {
192 PrintWriter pw = getOutPrintWriter();
193 pw.println("IMS Commands:");
Brad Ebinger24c29992019-12-05 13:03:21 -0800194 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700195 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
196 pw.println(" ImsService. Options are:");
197 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
198 pw.println(" is specified, it will choose the default voice SIM slot.");
199 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
200 pw.println(" -d: Override the ImsService defined in the device overlay.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800201 pw.println(" -f: Set the feature that this override if for, if no option is");
202 pw.println(" specified, the new package name will be used for all features.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700203 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
204 pw.println(" Gets the package name of the currently defined ImsService.");
205 pw.println(" Options are:");
206 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
207 pw.println(" is specified, it will choose the default voice SIM slot.");
208 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
209 pw.println(" -c: The ImsService defined as the device default ImsService.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800210 pw.println(" -f: The feature type that the query will be requested for. If none is");
211 pw.println(" specified, the returned package name will correspond to MMTEL.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700212 pw.println(" ims enable [-s SLOT_ID]");
213 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
214 pw.println(" if none is specified.");
215 pw.println(" ims disable [-s SLOT_ID]");
216 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
217 pw.println(" slot if none is specified.");
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700218 pw.println(" ims conference-event-package [enable/disable]");
219 pw.println(" enables or disables handling or network conference event package data.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700220 }
221
Hall Liud892bec2018-11-30 14:51:45 -0800222 private void onHelpNumberVerification() {
223 PrintWriter pw = getOutPrintWriter();
224 pw.println("Number verification commands");
225 pw.println(" numverify override-package PACKAGE_NAME;");
226 pw.println(" Set the authorized package for number verification.");
227 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800228 pw.println(" numverify fake-call NUMBER;");
229 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
230 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800231 }
232
Shuo Qianf5125122019-12-16 17:03:07 -0800233 private void onHelpDataTestMode() {
234 PrintWriter pw = getOutPrintWriter();
235 pw.println("Mobile Data Test Mode Commands:");
236 pw.println(" data enable: enable mobile data connectivity");
237 pw.println(" data disable: disable mobile data connectivity");
238 }
239
sqian9d4df8b2019-01-15 18:32:07 -0800240 private void onHelpEmergencyNumber() {
241 PrintWriter pw = getOutPrintWriter();
242 pw.println("Emergency Number Test Mode Commands:");
243 pw.println(" emergency-number-test-mode ");
244 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
245 + " the test mode");
246 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian9121f982019-03-14 19:45:39 -0700247 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800248 pw.println(" -c: clear the emergency number list in the test mode.");
249 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian9121f982019-03-14 19:45:39 -0700250 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800251 pw.println(" -p: get the full emergency number list in the test mode.");
252 }
253
Shuo Qian489d9282020-07-09 11:30:03 -0700254 private void onHelpEndBlockSupperssion() {
255 PrintWriter pw = getOutPrintWriter();
256 pw.println("End Block Suppression command:");
257 pw.println(" end-block-suppression: disable suppressing blocking by contact");
258 pw.println(" with emergency services.");
259 }
260
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100261 private void onHelpCc() {
262 PrintWriter pw = getOutPrintWriter();
263 pw.println("Carrier Config Commands:");
264 pw.println(" cc get-value [-s SLOT_ID] [KEY]");
265 pw.println(" Print carrier config values.");
266 pw.println(" Options are:");
267 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
268 pw.println(" is specified, it will choose the default voice SIM slot.");
269 pw.println(" KEY: The key to the carrier config value to print. All values are printed");
270 pw.println(" if KEY is not specified.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100271 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100272 pw.println(" Set carrier config KEY to NEW_VALUE.");
273 pw.println(" Options are:");
274 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
275 pw.println(" is specified, it will choose the default voice SIM slot.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100276 pw.println(" -p: Value will be stored persistent");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100277 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be");
278 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
279 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
280 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
281 pw.println(" cc clear-values [-s SLOT_ID]");
282 pw.println(" Clear all carrier override values that has previously been set");
283 pw.println(" with set-value");
284 pw.println(" Options are:");
285 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
286 pw.println(" is specified, it will choose the default voice SIM slot.");
287 }
288
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700289 private int handleImsCommand() {
290 String arg = getNextArg();
291 if (arg == null) {
292 onHelpIms();
293 return 0;
294 }
295
296 switch (arg) {
297 case IMS_SET_CARRIER_SERVICE: {
298 return handleImsSetServiceCommand();
299 }
300 case IMS_GET_CARRIER_SERVICE: {
301 return handleImsGetServiceCommand();
302 }
303 case IMS_ENABLE: {
304 return handleEnableIms();
305 }
306 case IMS_DISABLE: {
307 return handleDisableIms();
308 }
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700309 case IMS_CEP: {
310 return handleCepChange();
311 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700312 }
313
314 return -1;
315 }
316
Shuo Qianf5125122019-12-16 17:03:07 -0800317 private int handleDataTestModeCommand() {
318 PrintWriter errPw = getErrPrintWriter();
319 String arg = getNextArgRequired();
320 if (arg == null) {
321 onHelpDataTestMode();
322 return 0;
323 }
324 switch (arg) {
325 case DATA_ENABLE: {
326 try {
327 mInterface.enableDataConnectivity();
328 } catch (RemoteException ex) {
329 Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
330 errPw.println("Exception: " + ex.getMessage());
331 return -1;
332 }
333 break;
334 }
335 case DATA_DISABLE: {
336 try {
337 mInterface.disableDataConnectivity();
338 } catch (RemoteException ex) {
339 Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
340 errPw.println("Exception: " + ex.getMessage());
341 return -1;
342 }
343 break;
344 }
345 default:
346 onHelpDataTestMode();
347 break;
348 }
349 return 0;
350 }
351
sqian9d4df8b2019-01-15 18:32:07 -0800352 private int handleEmergencyNumberTestModeCommand() {
353 PrintWriter errPw = getErrPrintWriter();
354 String opt = getNextOption();
355 if (opt == null) {
356 onHelpEmergencyNumber();
357 return 0;
358 }
359
360 switch (opt) {
361 case "-a": {
362 String emergencyNumberCmd = getNextArgRequired();
363 if (emergencyNumberCmd == null
364 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700365 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800366 + " to be specified after -a in the command ");
367 return -1;
368 }
369 try {
370 mInterface.updateEmergencyNumberListTestMode(
371 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
372 new EmergencyNumber(emergencyNumberCmd, "", "",
373 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
374 new ArrayList<String>(),
375 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
376 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
377 } catch (RemoteException ex) {
378 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
379 + ", error " + ex.getMessage());
380 errPw.println("Exception: " + ex.getMessage());
381 return -1;
382 }
383 break;
384 }
385 case "-c": {
386 try {
387 mInterface.updateEmergencyNumberListTestMode(
388 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
389 } catch (RemoteException ex) {
390 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
391 errPw.println("Exception: " + ex.getMessage());
392 return -1;
393 }
394 break;
395 }
396 case "-r": {
397 String emergencyNumberCmd = getNextArgRequired();
398 if (emergencyNumberCmd == null
399 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700400 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800401 + " to be specified after -r in the command ");
402 return -1;
403 }
404 try {
405 mInterface.updateEmergencyNumberListTestMode(
406 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
407 new EmergencyNumber(emergencyNumberCmd, "", "",
408 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
409 new ArrayList<String>(),
410 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
411 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
412 } catch (RemoteException ex) {
413 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
414 + ", error " + ex.getMessage());
415 errPw.println("Exception: " + ex.getMessage());
416 return -1;
417 }
418 break;
419 }
420 case "-p": {
421 try {
422 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
423 } catch (RemoteException ex) {
424 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
425 errPw.println("Exception: " + ex.getMessage());
426 return -1;
427 }
428 break;
429 }
430 default:
431 onHelpEmergencyNumber();
432 break;
433 }
434 return 0;
435 }
436
Hall Liud892bec2018-11-30 14:51:45 -0800437 private int handleNumberVerificationCommand() {
438 String arg = getNextArg();
439 if (arg == null) {
440 onHelpNumberVerification();
441 return 0;
442 }
443
Hall Liuca5af3a2018-12-04 16:58:23 -0800444 if (!checkShellUid()) {
445 return -1;
446 }
447
Hall Liud892bec2018-11-30 14:51:45 -0800448 switch (arg) {
449 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800450 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
451 return 0;
452 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800453 case NUMBER_VERIFICATION_FAKE_CALL: {
454 boolean val = NumberVerificationManager.getInstance()
455 .checkIncomingCall(getNextArg());
456 getOutPrintWriter().println(val ? "1" : "0");
457 return 0;
458 }
Hall Liud892bec2018-11-30 14:51:45 -0800459 }
460
461 return -1;
462 }
463
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700464 // ims set-ims-service
465 private int handleImsSetServiceCommand() {
466 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700467 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700468 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800469 List<Integer> featuresList = new ArrayList<>();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700470
471 String opt;
472 while ((opt = getNextOption()) != null) {
473 switch (opt) {
474 case "-s": {
475 try {
476 slotId = Integer.parseInt(getNextArgRequired());
477 } catch (NumberFormatException e) {
478 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
479 return -1;
480 }
481 break;
482 }
483 case "-c": {
484 isCarrierService = true;
485 break;
486 }
487 case "-d": {
488 isCarrierService = false;
489 break;
490 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800491 case "-f": {
492 String featureString = getNextArgRequired();
493 String[] features = featureString.split(",");
494 for (int i = 0; i < features.length; i++) {
495 try {
496 Integer result = Integer.parseInt(features[i]);
497 if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
498 || result >= ImsFeature.FEATURE_MAX) {
499 errPw.println("ims set-ims-service -f " + result
500 + " is an invalid feature.");
501 return -1;
502 }
503 featuresList.add(result);
504 } catch (NumberFormatException e) {
505 errPw.println("ims set-ims-service -f tried to parse " + features[i]
506 + " as an integer.");
507 return -1;
508 }
509 }
510 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700511 }
512 }
513 // Mandatory param, either -c or -d
514 if (isCarrierService == null) {
515 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
516 return -1;
517 }
518
519 String packageName = getNextArg();
520
521 try {
522 if (packageName == null) {
523 packageName = "";
524 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800525 int[] featureArray = new int[featuresList.size()];
526 for (int i = 0; i < featuresList.size(); i++) {
527 featureArray[i] = featuresList.get(i);
528 }
529 boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
530 featureArray, packageName);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700531 if (VDBG) {
532 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800533 + (isCarrierService ? "-c " : "-d ")
534 + "-f " + featuresList + " "
535 + packageName + ", result=" + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700536 }
537 getOutPrintWriter().println(result);
538 } catch (RemoteException e) {
539 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800540 + (isCarrierService ? "-c " : "-d ")
541 + "-f " + featuresList + " "
542 + packageName + ", error" + e.getMessage());
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700543 errPw.println("Exception: " + e.getMessage());
544 return -1;
545 }
546 return 0;
547 }
548
549 // ims get-ims-service
550 private int handleImsGetServiceCommand() {
551 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700552 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700553 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800554 Integer featureType = ImsFeature.FEATURE_MMTEL;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700555
556 String opt;
557 while ((opt = getNextOption()) != null) {
558 switch (opt) {
559 case "-s": {
560 try {
561 slotId = Integer.parseInt(getNextArgRequired());
562 } catch (NumberFormatException e) {
563 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
564 return -1;
565 }
566 break;
567 }
568 case "-c": {
569 isCarrierService = true;
570 break;
571 }
572 case "-d": {
573 isCarrierService = false;
574 break;
575 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800576 case "-f": {
577 try {
578 featureType = Integer.parseInt(getNextArg());
579 } catch (NumberFormatException e) {
580 errPw.println("ims get-ims-service -f requires valid integer as feature.");
581 return -1;
582 }
583 if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
584 || featureType >= ImsFeature.FEATURE_MAX) {
585 errPw.println("ims get-ims-service -f invalid feature.");
586 return -1;
587 }
588 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700589 }
590 }
591 // Mandatory param, either -c or -d
592 if (isCarrierService == null) {
Brad Ebinger24c29992019-12-05 13:03:21 -0800593 errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700594 return -1;
595 }
596
597 String result;
598 try {
Brad Ebinger24c29992019-12-05 13:03:21 -0800599 result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700600 } catch (RemoteException e) {
601 return -1;
602 }
603 if (VDBG) {
604 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800605 + (isCarrierService ? "-c " : "-d ")
606 + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
607 + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700608 }
609 getOutPrintWriter().println(result);
610 return 0;
611 }
612
613 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700614 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700615 String opt;
616 while ((opt = getNextOption()) != null) {
617 switch (opt) {
618 case "-s": {
619 try {
620 slotId = Integer.parseInt(getNextArgRequired());
621 } catch (NumberFormatException e) {
622 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
623 return -1;
624 }
625 break;
626 }
627 }
628 }
629 try {
630 mInterface.enableIms(slotId);
631 } catch (RemoteException e) {
632 return -1;
633 }
634 if (VDBG) {
635 Log.v(LOG_TAG, "ims enable -s " + slotId);
636 }
637 return 0;
638 }
639
640 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700641 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700642 String opt;
643 while ((opt = getNextOption()) != null) {
644 switch (opt) {
645 case "-s": {
646 try {
647 slotId = Integer.parseInt(getNextArgRequired());
648 } catch (NumberFormatException e) {
649 getErrPrintWriter().println(
650 "ims disable requires an integer as a SLOT_ID.");
651 return -1;
652 }
653 break;
654 }
655 }
656 }
657 try {
658 mInterface.disableIms(slotId);
659 } catch (RemoteException e) {
660 return -1;
661 }
662 if (VDBG) {
663 Log.v(LOG_TAG, "ims disable -s " + slotId);
664 }
665 return 0;
666 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700667
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700668 private int handleCepChange() {
669 Log.i(LOG_TAG, "handleCepChange");
670 String opt = getNextArg();
671 if (opt == null) {
672 return -1;
673 }
674 boolean isCepEnabled = opt.equals("enable");
675
676 try {
677 mInterface.setCepEnabled(isCepEnabled);
678 } catch (RemoteException e) {
679 return -1;
680 }
681 return 0;
682 }
683
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700684 private int getDefaultSlot() {
685 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
686 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
687 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
688 // If there is no default, default to slot 0.
689 slotId = DEFAULT_PHONE_ID;
690 }
691 return slotId;
692 }
sqian2fff4a32018-11-05 14:18:37 -0800693
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100694 // Parse options related to Carrier Config Commands.
695 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100696 PrintWriter errPw = getErrPrintWriter();
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100697 CcOptionParseResult result = new CcOptionParseResult();
698 result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
699 result.mPersistent = false;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100700
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100701 String opt;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100702 while ((opt = getNextOption()) != null) {
703 switch (opt) {
704 case "-s": {
705 try {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100706 result.mSubId = slotStringToSubId(tag, getNextArgRequired());
707 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
708 errPw.println(tag + "No valid subscription found.");
709 return null;
710 }
711
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100712 } catch (IllegalArgumentException e) {
713 // Missing slot id
714 errPw.println(tag + "SLOT_ID expected after -s.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100715 return null;
716 }
717 break;
718 }
719 case "-p": {
720 if (allowOptionPersistent) {
721 result.mPersistent = true;
722 } else {
723 errPw.println(tag + "Unexpected option " + opt);
724 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100725 }
726 break;
727 }
728 default: {
729 errPw.println(tag + "Unknown option " + opt);
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100730 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100731 }
732 }
733 }
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100734 return result;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100735 }
736
737 private int slotStringToSubId(String tag, String slotString) {
738 int slotId = -1;
739 try {
740 slotId = Integer.parseInt(slotString);
741 } catch (NumberFormatException e) {
742 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
743 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
744 }
745
746 SubscriptionInfo subInfo =
747 mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(slotId);
748 if (subInfo == null) {
749 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
750 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
751 }
752 return subInfo.getSubscriptionId();
753 }
754
Hall Liud892bec2018-11-30 14:51:45 -0800755 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -0800756 // adb can run as root or as shell, depending on whether the device is rooted.
757 return Binder.getCallingUid() == Process.SHELL_UID
758 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -0800759 }
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100760
761 private int handleCcCommand() {
762 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
763 // non user build.
Meng Wangc4f61042019-11-21 10:51:05 -0800764 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100765 getErrPrintWriter().println("cc: Permission denied.");
766 return -1;
767 }
768
769 String arg = getNextArg();
770 if (arg == null) {
771 onHelpCc();
772 return 0;
773 }
774
775 switch (arg) {
776 case CC_GET_VALUE: {
777 return handleCcGetValue();
778 }
779 case CC_SET_VALUE: {
780 return handleCcSetValue();
781 }
782 case CC_CLEAR_VALUES: {
783 return handleCcClearValues();
784 }
785 default: {
786 getErrPrintWriter().println("cc: Unknown argument: " + arg);
787 }
788 }
789 return -1;
790 }
791
792 // cc get-value
793 private int handleCcGetValue() {
794 PrintWriter errPw = getErrPrintWriter();
795 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
796 String key = null;
797
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100798 // Parse all options
799 CcOptionParseResult options = parseCcOptions(tag, false);
800 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100801 return -1;
802 }
803
804 // Get bundle containing all carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100805 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100806 if (bundle == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100807 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100808 return -1;
809 }
810
811 // Get the key.
812 key = getNextArg();
813 if (key != null) {
814 // A key was provided. Verify if it is a valid key
815 if (!bundle.containsKey(key)) {
816 errPw.println(tag + key + " is not a valid key.");
817 return -1;
818 }
819
820 // Print the carrier config value for key.
821 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
822 } else {
823 // No key provided. Show all values.
824 // Iterate over a sorted list of all carrier config keys and print them.
825 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
826 for (String k : sortedSet) {
827 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
828 }
829 }
830 return 0;
831 }
832
833 // cc set-value
834 private int handleCcSetValue() {
835 PrintWriter errPw = getErrPrintWriter();
836 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
837
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100838 // Parse all options
839 CcOptionParseResult options = parseCcOptions(tag, true);
840 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100841 return -1;
842 }
843
844 // Get bundle containing all current carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100845 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100846 if (originalValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100847 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100848 return -1;
849 }
850
851 // Get the key.
852 String key = getNextArg();
853 if (key == null || key.equals("")) {
854 errPw.println(tag + "KEY is missing");
855 return -1;
856 }
857
858 // Verify if the key is valid
859 if (!originalValues.containsKey(key)) {
860 errPw.println(tag + key + " is not a valid key.");
861 return -1;
862 }
863
864 // Remaining arguments is a list of new values. Add them all into an ArrayList.
865 ArrayList<String> valueList = new ArrayList<String>();
866 while (peekNextArg() != null) {
867 valueList.add(getNextArg());
868 }
869
870 // Find the type of the carrier config value
871 CcType type = getType(tag, key, originalValues);
872 if (type == CcType.UNKNOWN) {
873 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
874 return -1;
875 }
876
877 // Create an override bundle containing the key and value that should be overriden.
878 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
879 if (overrideBundle == null) {
880 return -1;
881 }
882
883 // Override the value
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100884 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100885
886 // Find bundle containing all new carrier configuration values after the override.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100887 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100888 if (newValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100889 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100890 return -1;
891 }
892
893 // Print the original and new value.
894 String originalValueString = ccValueToString(key, type, originalValues);
895 String newValueString = ccValueToString(key, type, newValues);
896 getOutPrintWriter().println("Previous value: \n" + originalValueString);
897 getOutPrintWriter().println("New value: \n" + newValueString);
898
899 return 0;
900 }
901
902 // cc clear-values
903 private int handleCcClearValues() {
904 PrintWriter errPw = getErrPrintWriter();
905 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
906
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100907 // Parse all options
908 CcOptionParseResult options = parseCcOptions(tag, false);
909 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100910 return -1;
911 }
912
913 // Clear all values that has previously been set.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100914 mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100915 getOutPrintWriter()
916 .println("All previously set carrier config override values has been cleared");
917 return 0;
918 }
919
920 private CcType getType(String tag, String key, PersistableBundle bundle) {
921 // Find the type by checking the type of the current value stored in the bundle.
922 Object value = bundle.get(key);
923
924 if (CC_TYPE_MAP.containsKey(key)) {
925 return CC_TYPE_MAP.get(key);
926 } else if (value != null) {
927 if (value instanceof Boolean) {
928 return CcType.BOOLEAN;
929 } else if (value instanceof Double) {
930 return CcType.DOUBLE;
931 } else if (value instanceof double[]) {
932 return CcType.DOUBLE_ARRAY;
933 } else if (value instanceof Integer) {
934 return CcType.INT;
935 } else if (value instanceof int[]) {
936 return CcType.INT_ARRAY;
937 } else if (value instanceof Long) {
938 return CcType.LONG;
939 } else if (value instanceof long[]) {
940 return CcType.LONG_ARRAY;
941 } else if (value instanceof String) {
942 return CcType.STRING;
943 } else if (value instanceof String[]) {
944 return CcType.STRING_ARRAY;
945 }
946 } else {
947 // Current value was null and can therefore not be used in order to find the type.
948 // Check the name of the key to infer the type. This check is not needed for primitive
949 // data types (boolean, double, int and long), since they can not be null.
950 if (key.endsWith("double_array")) {
951 return CcType.DOUBLE_ARRAY;
952 }
953 if (key.endsWith("int_array")) {
954 return CcType.INT_ARRAY;
955 }
956 if (key.endsWith("long_array")) {
957 return CcType.LONG_ARRAY;
958 }
959 if (key.endsWith("string")) {
960 return CcType.STRING;
961 }
962 if (key.endsWith("string_array") || key.endsWith("strings")) {
963 return CcType.STRING_ARRAY;
964 }
965 }
966
967 // Not possible to infer the type by looking at the current value or the key.
968 PrintWriter errPw = getErrPrintWriter();
969 errPw.println(tag + "ERROR: " + key + " has unknown type.");
970 return CcType.UNKNOWN;
971 }
972
973 private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
974 String result;
975 StringBuilder valueString = new StringBuilder();
976 String typeString = type.toString();
977 Object value = bundle.get(key);
978
979 if (value == null) {
980 valueString.append("null");
981 } else {
982 switch (type) {
983 case DOUBLE_ARRAY: {
984 // Format the string representation of the int array as value1 value2......
985 double[] valueArray = (double[]) value;
986 for (int i = 0; i < valueArray.length; i++) {
987 if (i != 0) {
988 valueString.append(" ");
989 }
990 valueString.append(valueArray[i]);
991 }
992 break;
993 }
994 case INT_ARRAY: {
995 // Format the string representation of the int array as value1 value2......
996 int[] valueArray = (int[]) value;
997 for (int i = 0; i < valueArray.length; i++) {
998 if (i != 0) {
999 valueString.append(" ");
1000 }
1001 valueString.append(valueArray[i]);
1002 }
1003 break;
1004 }
1005 case LONG_ARRAY: {
1006 // Format the string representation of the int array as value1 value2......
1007 long[] valueArray = (long[]) value;
1008 for (int i = 0; i < valueArray.length; i++) {
1009 if (i != 0) {
1010 valueString.append(" ");
1011 }
1012 valueString.append(valueArray[i]);
1013 }
1014 break;
1015 }
1016 case STRING: {
1017 valueString.append("\"" + value.toString() + "\"");
1018 break;
1019 }
1020 case STRING_ARRAY: {
1021 // Format the string representation of the string array as "value1" "value2"....
1022 String[] valueArray = (String[]) value;
1023 for (int i = 0; i < valueArray.length; i++) {
1024 if (i != 0) {
1025 valueString.append(" ");
1026 }
1027 if (valueArray[i] != null) {
1028 valueString.append("\"" + valueArray[i] + "\"");
1029 } else {
1030 valueString.append("null");
1031 }
1032 }
1033 break;
1034 }
1035 default: {
1036 valueString.append(value.toString());
1037 }
1038 }
1039 }
1040 return String.format("%-70s %-15s %s", key, typeString, valueString);
1041 }
1042
1043 private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
1044 ArrayList<String> valueList) {
1045 PrintWriter errPw = getErrPrintWriter();
1046 PersistableBundle bundle = new PersistableBundle();
1047
1048 // First verify that a valid number of values has been provided for the type.
1049 switch (type) {
1050 case BOOLEAN:
1051 case DOUBLE:
1052 case INT:
1053 case LONG: {
1054 if (valueList.size() != 1) {
1055 errPw.println(tag + "Expected 1 value for type " + type
1056 + ". Found: " + valueList.size());
1057 return null;
1058 }
1059 break;
1060 }
1061 case STRING: {
1062 if (valueList.size() > 1) {
1063 errPw.println(tag + "Expected 0 or 1 values for type " + type
1064 + ". Found: " + valueList.size());
1065 return null;
1066 }
1067 break;
1068 }
1069 }
1070
1071 // Parse the value according to type and add it to the Bundle.
1072 switch (type) {
1073 case BOOLEAN: {
1074 if ("true".equalsIgnoreCase(valueList.get(0))) {
1075 bundle.putBoolean(key, true);
1076 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1077 bundle.putBoolean(key, false);
1078 } else {
1079 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1080 return null;
1081 }
1082 break;
1083 }
1084 case DOUBLE: {
1085 try {
1086 bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1087 } catch (NumberFormatException nfe) {
1088 // Not a valid double
1089 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1090 return null;
1091 }
1092 break;
1093 }
1094 case DOUBLE_ARRAY: {
1095 double[] valueDoubleArray = null;
1096 if (valueList.size() > 0) {
1097 valueDoubleArray = new double[valueList.size()];
1098 for (int i = 0; i < valueList.size(); i++) {
1099 try {
1100 valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1101 } catch (NumberFormatException nfe) {
1102 // Not a valid double
1103 errPw.println(
1104 tag + "Unable to parse " + valueList.get(i) + " as a double.");
1105 return null;
1106 }
1107 }
1108 }
1109 bundle.putDoubleArray(key, valueDoubleArray);
1110 break;
1111 }
1112 case INT: {
1113 try {
1114 bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1115 } catch (NumberFormatException nfe) {
1116 // Not a valid integer
1117 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1118 return null;
1119 }
1120 break;
1121 }
1122 case INT_ARRAY: {
1123 int[] valueIntArray = null;
1124 if (valueList.size() > 0) {
1125 valueIntArray = new int[valueList.size()];
1126 for (int i = 0; i < valueList.size(); i++) {
1127 try {
1128 valueIntArray[i] = Integer.parseInt(valueList.get(i));
1129 } catch (NumberFormatException nfe) {
1130 // Not a valid integer
1131 errPw.println(tag
1132 + "Unable to parse " + valueList.get(i) + " as an integer.");
1133 return null;
1134 }
1135 }
1136 }
1137 bundle.putIntArray(key, valueIntArray);
1138 break;
1139 }
1140 case LONG: {
1141 try {
1142 bundle.putLong(key, Long.parseLong(valueList.get(0)));
1143 } catch (NumberFormatException nfe) {
1144 // Not a valid long
1145 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1146 return null;
1147 }
1148 break;
1149 }
1150 case LONG_ARRAY: {
1151 long[] valueLongArray = null;
1152 if (valueList.size() > 0) {
1153 valueLongArray = new long[valueList.size()];
1154 for (int i = 0; i < valueList.size(); i++) {
1155 try {
1156 valueLongArray[i] = Long.parseLong(valueList.get(i));
1157 } catch (NumberFormatException nfe) {
1158 // Not a valid long
1159 errPw.println(
1160 tag + "Unable to parse " + valueList.get(i) + " as a long");
1161 return null;
1162 }
1163 }
1164 }
1165 bundle.putLongArray(key, valueLongArray);
1166 break;
1167 }
1168 case STRING: {
1169 String value = null;
1170 if (valueList.size() > 0) {
1171 value = valueList.get(0);
1172 }
1173 bundle.putString(key, value);
1174 break;
1175 }
1176 case STRING_ARRAY: {
1177 String[] valueStringArray = null;
1178 if (valueList.size() > 0) {
1179 valueStringArray = new String[valueList.size()];
1180 valueList.toArray(valueStringArray);
1181 }
1182 bundle.putStringArray(key, valueStringArray);
1183 break;
1184 }
1185 }
1186 return bundle;
1187 }
Shuo Qian489d9282020-07-09 11:30:03 -07001188
1189 private int handleEndBlockSuppressionCommand() {
1190 if (!checkShellUid()) {
1191 return -1;
1192 }
1193
1194 if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) {
1195 BlockedNumberContract.SystemContract.endBlockSuppression(mContext);
1196 }
1197 return 0;
1198 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001199}