blob: c6a2f5213df730be0a0c964e7792ac8b102c7b74 [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;
Shuo Qian489d9282020-07-09 11:30:03 -070024import android.provider.BlockedNumberContract;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010025import android.telephony.CarrierConfigManager;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070026import android.telephony.SubscriptionManager;
sqian9d4df8b2019-01-15 18:32:07 -080027import android.telephony.emergency.EmergencyNumber;
Brad Ebinger24c29992019-12-05 13:03:21 -080028import android.telephony.ims.feature.ImsFeature;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070029import android.util.Log;
30
31import com.android.internal.telephony.ITelephony;
Qiong Liuf25799b2020-09-10 10:13:46 +080032import com.android.internal.telephony.Phone;
33import com.android.internal.telephony.PhoneFactory;
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;
Chiachang Wang99890092020-11-04 10:59:17 +080036import com.android.modules.utils.BasicShellCommandHandler;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070037
38import java.io.PrintWriter;
sqian9d4df8b2019-01-15 18:32:07 -080039import java.util.ArrayList;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010040import java.util.HashMap;
Brad Ebinger24c29992019-12-05 13:03:21 -080041import java.util.List;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010042import java.util.Map;
43import java.util.TreeSet;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070044
45/**
46 * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
47 * permission checks have been done before onCommand was called. Make sure any commands processed
48 * here also contain the appropriate permissions checks.
49 */
50
Hall Liua1548bd2019-12-24 14:14:12 -080051public class TelephonyShellCommand extends BasicShellCommandHandler {
Brad Ebinger4dc095a2018-04-03 15:17:52 -070052
53 private static final String LOG_TAG = "TelephonyShellCommand";
54 // Don't commit with this true.
55 private static final boolean VDBG = true;
Brad Ebinger0aa2f242018-04-12 09:49:23 -070056 private static final int DEFAULT_PHONE_ID = 0;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070057
58 private static final String IMS_SUBCOMMAND = "ims";
Hall Liud892bec2018-11-30 14:51:45 -080059 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
sqian9d4df8b2019-01-15 18:32:07 -080060 private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
Shuo Qian489d9282020-07-09 11:30:03 -070061 private static final String END_BLOCK_SUPPRESSION = "end-block-suppression";
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010062 private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
Shuo Qianf5125122019-12-16 17:03:07 -080063 private static final String DATA_TEST_MODE = "data";
64 private static final String DATA_ENABLE = "enable";
65 private static final String DATA_DISABLE = "disable";
Hall Liud892bec2018-11-30 14:51:45 -080066
Brad Ebinger4dc095a2018-04-03 15:17:52 -070067 private static final String IMS_SET_CARRIER_SERVICE = "set-ims-service";
68 private static final String IMS_GET_CARRIER_SERVICE = "get-ims-service";
69 private static final String IMS_ENABLE = "enable";
70 private static final String IMS_DISABLE = "disable";
Tyler Gunn7bcdc742019-10-04 15:56:59 -070071 // Used to disable or enable processing of conference event package data from the network.
72 // This is handy for testing scenarios where CEP data does not exist on a network which does
73 // support CEP data.
74 private static final String IMS_CEP = "conference-event-package";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070075
Hall Liud892bec2018-11-30 14:51:45 -080076 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080077 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080078
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010079 private static final String CC_GET_VALUE = "get-value";
80 private static final String CC_SET_VALUE = "set-value";
81 private static final String CC_CLEAR_VALUES = "clear-values";
82
Brad Ebinger4dc095a2018-04-03 15:17:52 -070083 // Take advantage of existing methods that already contain permissions checks when possible.
84 private final ITelephony mInterface;
85
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010086 private SubscriptionManager mSubscriptionManager;
87 private CarrierConfigManager mCarrierConfigManager;
Shuo Qian489d9282020-07-09 11:30:03 -070088 private Context mContext;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010089
90 private enum CcType {
91 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
92 STRING_ARRAY, UNKNOWN
93 }
94
Torbjorn Eklund723527a2019-02-13 11:16:25 +010095 private class CcOptionParseResult {
96 public int mSubId;
97 public boolean mPersistent;
98 }
99
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100100 // Maps carrier config keys to type. It is possible to infer the type for most carrier config
101 // keys by looking at the end of the string which usually tells the type.
102 // For instance: "xxxx_string", "xxxx_string_array", etc.
103 // The carrier config keys in this map does not follow this convention. It is therefore not
104 // possible to infer the type for these keys by looking at the string.
105 private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
106 put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
107 put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
108 put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
109 put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
110 put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
111 put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
112 put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
113 put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
114 put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
115 put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
116 put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
117 CcType.STRING);
118 put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
119 CcType.STRING_ARRAY);
120 put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
121 CcType.STRING_ARRAY);
122 put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
123 put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
124 put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
125 put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
126 put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
127 put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
128 put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
129 put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
130 }
131 };
132
133 public TelephonyShellCommand(ITelephony binder, Context context) {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700134 mInterface = binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100135 mCarrierConfigManager =
136 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
137 mSubscriptionManager = (SubscriptionManager)
138 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Shuo Qian489d9282020-07-09 11:30:03 -0700139 mContext = context;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700140 }
141
142 @Override
143 public int onCommand(String cmd) {
144 if (cmd == null) {
145 return handleDefaultCommands(null);
146 }
147
148 switch (cmd) {
149 case IMS_SUBCOMMAND: {
150 return handleImsCommand();
151 }
Hall Liud892bec2018-11-30 14:51:45 -0800152 case NUMBER_VERIFICATION_SUBCOMMAND:
153 return handleNumberVerificationCommand();
sqian9d4df8b2019-01-15 18:32:07 -0800154 case EMERGENCY_NUMBER_TEST_MODE:
155 return handleEmergencyNumberTestModeCommand();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100156 case CARRIER_CONFIG_SUBCOMMAND: {
157 return handleCcCommand();
158 }
Shuo Qianf5125122019-12-16 17:03:07 -0800159 case DATA_TEST_MODE:
160 return handleDataTestModeCommand();
Shuo Qian489d9282020-07-09 11:30:03 -0700161 case END_BLOCK_SUPPRESSION:
162 return handleEndBlockSuppressionCommand();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700163 default: {
164 return handleDefaultCommands(cmd);
165 }
166 }
167 }
168
169 @Override
170 public void onHelp() {
171 PrintWriter pw = getOutPrintWriter();
172 pw.println("Telephony Commands:");
173 pw.println(" help");
174 pw.println(" Print this help text.");
175 pw.println(" ims");
176 pw.println(" IMS Commands.");
sqian9d4df8b2019-01-15 18:32:07 -0800177 pw.println(" emergency-number-test-mode");
178 pw.println(" Emergency Number Test Mode Commands.");
Shuo Qian489d9282020-07-09 11:30:03 -0700179 pw.println(" end-block-suppression");
180 pw.println(" End Block Suppression command.");
Shuo Qianf5125122019-12-16 17:03:07 -0800181 pw.println(" data");
182 pw.println(" Data Test Mode Commands.");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100183 pw.println(" cc");
184 pw.println(" Carrier Config Commands.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700185 onHelpIms();
sqian9d4df8b2019-01-15 18:32:07 -0800186 onHelpEmergencyNumber();
Shuo Qian489d9282020-07-09 11:30:03 -0700187 onHelpEndBlockSupperssion();
Shuo Qianf5125122019-12-16 17:03:07 -0800188 onHelpDataTestMode();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100189 onHelpCc();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700190 }
191
192 private void onHelpIms() {
193 PrintWriter pw = getOutPrintWriter();
194 pw.println("IMS Commands:");
Brad Ebinger24c29992019-12-05 13:03:21 -0800195 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700196 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
197 pw.println(" ImsService. Options are:");
198 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
199 pw.println(" is specified, it will choose the default voice SIM slot.");
200 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
201 pw.println(" -d: Override the ImsService defined in the device overlay.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800202 pw.println(" -f: Set the feature that this override if for, if no option is");
203 pw.println(" specified, the new package name will be used for all features.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700204 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
205 pw.println(" Gets the package name of the currently defined ImsService.");
206 pw.println(" Options are:");
207 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
208 pw.println(" is specified, it will choose the default voice SIM slot.");
209 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
Peter Kalauskas1defdc32020-09-03 19:20:26 +0000210 pw.println(" -d: The ImsService defined as the device default ImsService.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800211 pw.println(" -f: The feature type that the query will be requested for. If none is");
212 pw.println(" specified, the returned package name will correspond to MMTEL.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700213 pw.println(" ims enable [-s SLOT_ID]");
214 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
215 pw.println(" if none is specified.");
216 pw.println(" ims disable [-s SLOT_ID]");
217 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
218 pw.println(" slot if none is specified.");
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700219 pw.println(" ims conference-event-package [enable/disable]");
220 pw.println(" enables or disables handling or network conference event package data.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700221 }
222
Hall Liud892bec2018-11-30 14:51:45 -0800223 private void onHelpNumberVerification() {
224 PrintWriter pw = getOutPrintWriter();
225 pw.println("Number verification commands");
226 pw.println(" numverify override-package PACKAGE_NAME;");
227 pw.println(" Set the authorized package for number verification.");
228 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800229 pw.println(" numverify fake-call NUMBER;");
230 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
231 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800232 }
233
Shuo Qianf5125122019-12-16 17:03:07 -0800234 private void onHelpDataTestMode() {
235 PrintWriter pw = getOutPrintWriter();
236 pw.println("Mobile Data Test Mode Commands:");
237 pw.println(" data enable: enable mobile data connectivity");
238 pw.println(" data disable: disable mobile data connectivity");
239 }
240
sqian9d4df8b2019-01-15 18:32:07 -0800241 private void onHelpEmergencyNumber() {
242 PrintWriter pw = getOutPrintWriter();
243 pw.println("Emergency Number Test Mode Commands:");
244 pw.println(" emergency-number-test-mode ");
245 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
246 + " the test mode");
247 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian9121f982019-03-14 19:45:39 -0700248 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800249 pw.println(" -c: clear the emergency number list in the test mode.");
250 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian9121f982019-03-14 19:45:39 -0700251 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800252 pw.println(" -p: get the full emergency number list in the test mode.");
253 }
254
Shuo Qian489d9282020-07-09 11:30:03 -0700255 private void onHelpEndBlockSupperssion() {
256 PrintWriter pw = getOutPrintWriter();
257 pw.println("End Block Suppression command:");
258 pw.println(" end-block-suppression: disable suppressing blocking by contact");
259 pw.println(" with emergency services.");
260 }
261
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100262 private void onHelpCc() {
263 PrintWriter pw = getOutPrintWriter();
264 pw.println("Carrier Config Commands:");
265 pw.println(" cc get-value [-s SLOT_ID] [KEY]");
266 pw.println(" Print carrier config values.");
267 pw.println(" Options are:");
268 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
269 pw.println(" is specified, it will choose the default voice SIM slot.");
270 pw.println(" KEY: The key to the carrier config value to print. All values are printed");
271 pw.println(" if KEY is not specified.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100272 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100273 pw.println(" Set carrier config KEY to NEW_VALUE.");
274 pw.println(" Options are:");
275 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
276 pw.println(" is specified, it will choose the default voice SIM slot.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100277 pw.println(" -p: Value will be stored persistent");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100278 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be");
279 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
280 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
281 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
282 pw.println(" cc clear-values [-s SLOT_ID]");
283 pw.println(" Clear all carrier override values that has previously been set");
284 pw.println(" with set-value");
285 pw.println(" Options are:");
286 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
287 pw.println(" is specified, it will choose the default voice SIM slot.");
288 }
289
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700290 private int handleImsCommand() {
291 String arg = getNextArg();
292 if (arg == null) {
293 onHelpIms();
294 return 0;
295 }
296
297 switch (arg) {
298 case IMS_SET_CARRIER_SERVICE: {
299 return handleImsSetServiceCommand();
300 }
301 case IMS_GET_CARRIER_SERVICE: {
302 return handleImsGetServiceCommand();
303 }
304 case IMS_ENABLE: {
305 return handleEnableIms();
306 }
307 case IMS_DISABLE: {
308 return handleDisableIms();
309 }
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700310 case IMS_CEP: {
311 return handleCepChange();
312 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700313 }
314
315 return -1;
316 }
317
Shuo Qianf5125122019-12-16 17:03:07 -0800318 private int handleDataTestModeCommand() {
319 PrintWriter errPw = getErrPrintWriter();
320 String arg = getNextArgRequired();
321 if (arg == null) {
322 onHelpDataTestMode();
323 return 0;
324 }
325 switch (arg) {
326 case DATA_ENABLE: {
327 try {
328 mInterface.enableDataConnectivity();
329 } catch (RemoteException ex) {
330 Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
331 errPw.println("Exception: " + ex.getMessage());
332 return -1;
333 }
334 break;
335 }
336 case DATA_DISABLE: {
337 try {
338 mInterface.disableDataConnectivity();
339 } catch (RemoteException ex) {
340 Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
341 errPw.println("Exception: " + ex.getMessage());
342 return -1;
343 }
344 break;
345 }
346 default:
347 onHelpDataTestMode();
348 break;
349 }
350 return 0;
351 }
352
sqian9d4df8b2019-01-15 18:32:07 -0800353 private int handleEmergencyNumberTestModeCommand() {
354 PrintWriter errPw = getErrPrintWriter();
355 String opt = getNextOption();
356 if (opt == null) {
357 onHelpEmergencyNumber();
358 return 0;
359 }
360
361 switch (opt) {
362 case "-a": {
363 String emergencyNumberCmd = getNextArgRequired();
364 if (emergencyNumberCmd == null
365 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700366 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800367 + " to be specified after -a in the command ");
368 return -1;
369 }
370 try {
371 mInterface.updateEmergencyNumberListTestMode(
372 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
373 new EmergencyNumber(emergencyNumberCmd, "", "",
374 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
375 new ArrayList<String>(),
376 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
377 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
378 } catch (RemoteException ex) {
379 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
380 + ", error " + ex.getMessage());
381 errPw.println("Exception: " + ex.getMessage());
382 return -1;
383 }
384 break;
385 }
386 case "-c": {
387 try {
388 mInterface.updateEmergencyNumberListTestMode(
389 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
390 } catch (RemoteException ex) {
391 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
392 errPw.println("Exception: " + ex.getMessage());
393 return -1;
394 }
395 break;
396 }
397 case "-r": {
398 String emergencyNumberCmd = getNextArgRequired();
399 if (emergencyNumberCmd == null
400 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700401 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800402 + " to be specified after -r in the command ");
403 return -1;
404 }
405 try {
406 mInterface.updateEmergencyNumberListTestMode(
407 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
408 new EmergencyNumber(emergencyNumberCmd, "", "",
409 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
410 new ArrayList<String>(),
411 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
412 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
413 } catch (RemoteException ex) {
414 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
415 + ", error " + ex.getMessage());
416 errPw.println("Exception: " + ex.getMessage());
417 return -1;
418 }
419 break;
420 }
421 case "-p": {
422 try {
423 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
424 } catch (RemoteException ex) {
425 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
426 errPw.println("Exception: " + ex.getMessage());
427 return -1;
428 }
429 break;
430 }
431 default:
432 onHelpEmergencyNumber();
433 break;
434 }
435 return 0;
436 }
437
Hall Liud892bec2018-11-30 14:51:45 -0800438 private int handleNumberVerificationCommand() {
439 String arg = getNextArg();
440 if (arg == null) {
441 onHelpNumberVerification();
442 return 0;
443 }
444
Hall Liuca5af3a2018-12-04 16:58:23 -0800445 if (!checkShellUid()) {
446 return -1;
447 }
448
Hall Liud892bec2018-11-30 14:51:45 -0800449 switch (arg) {
450 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800451 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
452 return 0;
453 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800454 case NUMBER_VERIFICATION_FAKE_CALL: {
455 boolean val = NumberVerificationManager.getInstance()
456 .checkIncomingCall(getNextArg());
457 getOutPrintWriter().println(val ? "1" : "0");
458 return 0;
459 }
Hall Liud892bec2018-11-30 14:51:45 -0800460 }
461
462 return -1;
463 }
464
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700465 // ims set-ims-service
466 private int handleImsSetServiceCommand() {
467 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700468 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700469 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800470 List<Integer> featuresList = new ArrayList<>();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700471
472 String opt;
473 while ((opt = getNextOption()) != null) {
474 switch (opt) {
475 case "-s": {
476 try {
477 slotId = Integer.parseInt(getNextArgRequired());
478 } catch (NumberFormatException e) {
479 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
480 return -1;
481 }
482 break;
483 }
484 case "-c": {
485 isCarrierService = true;
486 break;
487 }
488 case "-d": {
489 isCarrierService = false;
490 break;
491 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800492 case "-f": {
493 String featureString = getNextArgRequired();
494 String[] features = featureString.split(",");
495 for (int i = 0; i < features.length; i++) {
496 try {
497 Integer result = Integer.parseInt(features[i]);
498 if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
499 || result >= ImsFeature.FEATURE_MAX) {
500 errPw.println("ims set-ims-service -f " + result
501 + " is an invalid feature.");
502 return -1;
503 }
504 featuresList.add(result);
505 } catch (NumberFormatException e) {
506 errPw.println("ims set-ims-service -f tried to parse " + features[i]
507 + " as an integer.");
508 return -1;
509 }
510 }
511 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700512 }
513 }
514 // Mandatory param, either -c or -d
515 if (isCarrierService == null) {
516 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
517 return -1;
518 }
519
520 String packageName = getNextArg();
521
522 try {
523 if (packageName == null) {
524 packageName = "";
525 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800526 int[] featureArray = new int[featuresList.size()];
527 for (int i = 0; i < featuresList.size(); i++) {
528 featureArray[i] = featuresList.get(i);
529 }
530 boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
531 featureArray, packageName);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700532 if (VDBG) {
533 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800534 + (isCarrierService ? "-c " : "-d ")
535 + "-f " + featuresList + " "
536 + packageName + ", result=" + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700537 }
538 getOutPrintWriter().println(result);
539 } catch (RemoteException e) {
540 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800541 + (isCarrierService ? "-c " : "-d ")
542 + "-f " + featuresList + " "
543 + packageName + ", error" + e.getMessage());
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700544 errPw.println("Exception: " + e.getMessage());
545 return -1;
546 }
547 return 0;
548 }
549
550 // ims get-ims-service
551 private int handleImsGetServiceCommand() {
552 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700553 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700554 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800555 Integer featureType = ImsFeature.FEATURE_MMTEL;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700556
557 String opt;
558 while ((opt = getNextOption()) != null) {
559 switch (opt) {
560 case "-s": {
561 try {
562 slotId = Integer.parseInt(getNextArgRequired());
563 } catch (NumberFormatException e) {
564 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
565 return -1;
566 }
567 break;
568 }
569 case "-c": {
570 isCarrierService = true;
571 break;
572 }
573 case "-d": {
574 isCarrierService = false;
575 break;
576 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800577 case "-f": {
578 try {
579 featureType = Integer.parseInt(getNextArg());
580 } catch (NumberFormatException e) {
581 errPw.println("ims get-ims-service -f requires valid integer as feature.");
582 return -1;
583 }
584 if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
585 || featureType >= ImsFeature.FEATURE_MAX) {
586 errPw.println("ims get-ims-service -f invalid feature.");
587 return -1;
588 }
589 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700590 }
591 }
592 // Mandatory param, either -c or -d
593 if (isCarrierService == null) {
Brad Ebinger24c29992019-12-05 13:03:21 -0800594 errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700595 return -1;
596 }
597
598 String result;
599 try {
Brad Ebinger24c29992019-12-05 13:03:21 -0800600 result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700601 } catch (RemoteException e) {
602 return -1;
603 }
604 if (VDBG) {
605 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800606 + (isCarrierService ? "-c " : "-d ")
607 + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
608 + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700609 }
610 getOutPrintWriter().println(result);
611 return 0;
612 }
613
614 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700615 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700616 String opt;
617 while ((opt = getNextOption()) != null) {
618 switch (opt) {
619 case "-s": {
620 try {
621 slotId = Integer.parseInt(getNextArgRequired());
622 } catch (NumberFormatException e) {
623 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
624 return -1;
625 }
626 break;
627 }
628 }
629 }
630 try {
631 mInterface.enableIms(slotId);
632 } catch (RemoteException e) {
633 return -1;
634 }
635 if (VDBG) {
636 Log.v(LOG_TAG, "ims enable -s " + slotId);
637 }
638 return 0;
639 }
640
641 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700642 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700643 String opt;
644 while ((opt = getNextOption()) != null) {
645 switch (opt) {
646 case "-s": {
647 try {
648 slotId = Integer.parseInt(getNextArgRequired());
649 } catch (NumberFormatException e) {
650 getErrPrintWriter().println(
651 "ims disable requires an integer as a SLOT_ID.");
652 return -1;
653 }
654 break;
655 }
656 }
657 }
658 try {
659 mInterface.disableIms(slotId);
660 } catch (RemoteException e) {
661 return -1;
662 }
663 if (VDBG) {
664 Log.v(LOG_TAG, "ims disable -s " + slotId);
665 }
666 return 0;
667 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700668
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700669 private int handleCepChange() {
670 Log.i(LOG_TAG, "handleCepChange");
671 String opt = getNextArg();
672 if (opt == null) {
673 return -1;
674 }
675 boolean isCepEnabled = opt.equals("enable");
676
677 try {
678 mInterface.setCepEnabled(isCepEnabled);
679 } catch (RemoteException e) {
680 return -1;
681 }
682 return 0;
683 }
684
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700685 private int getDefaultSlot() {
686 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
687 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
688 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
689 // If there is no default, default to slot 0.
690 slotId = DEFAULT_PHONE_ID;
691 }
692 return slotId;
693 }
sqian2fff4a32018-11-05 14:18:37 -0800694
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100695 // Parse options related to Carrier Config Commands.
696 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100697 PrintWriter errPw = getErrPrintWriter();
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100698 CcOptionParseResult result = new CcOptionParseResult();
699 result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
700 result.mPersistent = false;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100701
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100702 String opt;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100703 while ((opt = getNextOption()) != null) {
704 switch (opt) {
705 case "-s": {
706 try {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100707 result.mSubId = slotStringToSubId(tag, getNextArgRequired());
708 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
709 errPw.println(tag + "No valid subscription found.");
710 return null;
711 }
712
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100713 } catch (IllegalArgumentException e) {
714 // Missing slot id
715 errPw.println(tag + "SLOT_ID expected after -s.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100716 return null;
717 }
718 break;
719 }
720 case "-p": {
721 if (allowOptionPersistent) {
722 result.mPersistent = true;
723 } else {
724 errPw.println(tag + "Unexpected option " + opt);
725 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100726 }
727 break;
728 }
729 default: {
730 errPw.println(tag + "Unknown option " + opt);
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100731 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100732 }
733 }
734 }
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100735 return result;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100736 }
737
738 private int slotStringToSubId(String tag, String slotString) {
739 int slotId = -1;
740 try {
741 slotId = Integer.parseInt(slotString);
742 } catch (NumberFormatException e) {
Qiong Liuf25799b2020-09-10 10:13:46 +0800743 getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID.");
744 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
745 }
746
747 if (!SubscriptionManager.isValidPhoneId(slotId)) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100748 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
749 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
750 }
751
Qiong Liuf25799b2020-09-10 10:13:46 +0800752 Phone phone = PhoneFactory.getPhone(slotId);
753 if (phone == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100754 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
755 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
756 }
Qiong Liuf25799b2020-09-10 10:13:46 +0800757 return phone.getSubId();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100758 }
759
Hall Liud892bec2018-11-30 14:51:45 -0800760 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -0800761 // adb can run as root or as shell, depending on whether the device is rooted.
762 return Binder.getCallingUid() == Process.SHELL_UID
763 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -0800764 }
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100765
766 private int handleCcCommand() {
767 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
768 // non user build.
Meng Wangc4f61042019-11-21 10:51:05 -0800769 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100770 getErrPrintWriter().println("cc: Permission denied.");
771 return -1;
772 }
773
774 String arg = getNextArg();
775 if (arg == null) {
776 onHelpCc();
777 return 0;
778 }
779
780 switch (arg) {
781 case CC_GET_VALUE: {
782 return handleCcGetValue();
783 }
784 case CC_SET_VALUE: {
785 return handleCcSetValue();
786 }
787 case CC_CLEAR_VALUES: {
788 return handleCcClearValues();
789 }
790 default: {
791 getErrPrintWriter().println("cc: Unknown argument: " + arg);
792 }
793 }
794 return -1;
795 }
796
797 // cc get-value
798 private int handleCcGetValue() {
799 PrintWriter errPw = getErrPrintWriter();
800 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
801 String key = null;
802
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100803 // Parse all options
804 CcOptionParseResult options = parseCcOptions(tag, false);
805 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100806 return -1;
807 }
808
809 // Get bundle containing all carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100810 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100811 if (bundle == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100812 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100813 return -1;
814 }
815
816 // Get the key.
817 key = getNextArg();
818 if (key != null) {
819 // A key was provided. Verify if it is a valid key
820 if (!bundle.containsKey(key)) {
821 errPw.println(tag + key + " is not a valid key.");
822 return -1;
823 }
824
825 // Print the carrier config value for key.
826 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
827 } else {
828 // No key provided. Show all values.
829 // Iterate over a sorted list of all carrier config keys and print them.
830 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
831 for (String k : sortedSet) {
832 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
833 }
834 }
835 return 0;
836 }
837
838 // cc set-value
839 private int handleCcSetValue() {
840 PrintWriter errPw = getErrPrintWriter();
841 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
842
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100843 // Parse all options
844 CcOptionParseResult options = parseCcOptions(tag, true);
845 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100846 return -1;
847 }
848
849 // Get bundle containing all current carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100850 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100851 if (originalValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100852 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100853 return -1;
854 }
855
856 // Get the key.
857 String key = getNextArg();
858 if (key == null || key.equals("")) {
859 errPw.println(tag + "KEY is missing");
860 return -1;
861 }
862
863 // Verify if the key is valid
864 if (!originalValues.containsKey(key)) {
865 errPw.println(tag + key + " is not a valid key.");
866 return -1;
867 }
868
869 // Remaining arguments is a list of new values. Add them all into an ArrayList.
870 ArrayList<String> valueList = new ArrayList<String>();
871 while (peekNextArg() != null) {
872 valueList.add(getNextArg());
873 }
874
875 // Find the type of the carrier config value
876 CcType type = getType(tag, key, originalValues);
877 if (type == CcType.UNKNOWN) {
878 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
879 return -1;
880 }
881
882 // Create an override bundle containing the key and value that should be overriden.
883 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
884 if (overrideBundle == null) {
885 return -1;
886 }
887
888 // Override the value
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100889 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100890
891 // Find bundle containing all new carrier configuration values after the override.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100892 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100893 if (newValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100894 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100895 return -1;
896 }
897
898 // Print the original and new value.
899 String originalValueString = ccValueToString(key, type, originalValues);
900 String newValueString = ccValueToString(key, type, newValues);
901 getOutPrintWriter().println("Previous value: \n" + originalValueString);
902 getOutPrintWriter().println("New value: \n" + newValueString);
903
904 return 0;
905 }
906
907 // cc clear-values
908 private int handleCcClearValues() {
909 PrintWriter errPw = getErrPrintWriter();
910 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
911
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100912 // Parse all options
913 CcOptionParseResult options = parseCcOptions(tag, false);
914 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100915 return -1;
916 }
917
918 // Clear all values that has previously been set.
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100919 mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100920 getOutPrintWriter()
921 .println("All previously set carrier config override values has been cleared");
922 return 0;
923 }
924
925 private CcType getType(String tag, String key, PersistableBundle bundle) {
926 // Find the type by checking the type of the current value stored in the bundle.
927 Object value = bundle.get(key);
928
929 if (CC_TYPE_MAP.containsKey(key)) {
930 return CC_TYPE_MAP.get(key);
931 } else if (value != null) {
932 if (value instanceof Boolean) {
933 return CcType.BOOLEAN;
934 } else if (value instanceof Double) {
935 return CcType.DOUBLE;
936 } else if (value instanceof double[]) {
937 return CcType.DOUBLE_ARRAY;
938 } else if (value instanceof Integer) {
939 return CcType.INT;
940 } else if (value instanceof int[]) {
941 return CcType.INT_ARRAY;
942 } else if (value instanceof Long) {
943 return CcType.LONG;
944 } else if (value instanceof long[]) {
945 return CcType.LONG_ARRAY;
946 } else if (value instanceof String) {
947 return CcType.STRING;
948 } else if (value instanceof String[]) {
949 return CcType.STRING_ARRAY;
950 }
951 } else {
952 // Current value was null and can therefore not be used in order to find the type.
953 // Check the name of the key to infer the type. This check is not needed for primitive
954 // data types (boolean, double, int and long), since they can not be null.
955 if (key.endsWith("double_array")) {
956 return CcType.DOUBLE_ARRAY;
957 }
958 if (key.endsWith("int_array")) {
959 return CcType.INT_ARRAY;
960 }
961 if (key.endsWith("long_array")) {
962 return CcType.LONG_ARRAY;
963 }
964 if (key.endsWith("string")) {
965 return CcType.STRING;
966 }
967 if (key.endsWith("string_array") || key.endsWith("strings")) {
968 return CcType.STRING_ARRAY;
969 }
970 }
971
972 // Not possible to infer the type by looking at the current value or the key.
973 PrintWriter errPw = getErrPrintWriter();
974 errPw.println(tag + "ERROR: " + key + " has unknown type.");
975 return CcType.UNKNOWN;
976 }
977
978 private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
979 String result;
980 StringBuilder valueString = new StringBuilder();
981 String typeString = type.toString();
982 Object value = bundle.get(key);
983
984 if (value == null) {
985 valueString.append("null");
986 } else {
987 switch (type) {
988 case DOUBLE_ARRAY: {
989 // Format the string representation of the int array as value1 value2......
990 double[] valueArray = (double[]) value;
991 for (int i = 0; i < valueArray.length; i++) {
992 if (i != 0) {
993 valueString.append(" ");
994 }
995 valueString.append(valueArray[i]);
996 }
997 break;
998 }
999 case INT_ARRAY: {
1000 // Format the string representation of the int array as value1 value2......
1001 int[] valueArray = (int[]) value;
1002 for (int i = 0; i < valueArray.length; i++) {
1003 if (i != 0) {
1004 valueString.append(" ");
1005 }
1006 valueString.append(valueArray[i]);
1007 }
1008 break;
1009 }
1010 case LONG_ARRAY: {
1011 // Format the string representation of the int array as value1 value2......
1012 long[] valueArray = (long[]) value;
1013 for (int i = 0; i < valueArray.length; i++) {
1014 if (i != 0) {
1015 valueString.append(" ");
1016 }
1017 valueString.append(valueArray[i]);
1018 }
1019 break;
1020 }
1021 case STRING: {
1022 valueString.append("\"" + value.toString() + "\"");
1023 break;
1024 }
1025 case STRING_ARRAY: {
1026 // Format the string representation of the string array as "value1" "value2"....
1027 String[] valueArray = (String[]) value;
1028 for (int i = 0; i < valueArray.length; i++) {
1029 if (i != 0) {
1030 valueString.append(" ");
1031 }
1032 if (valueArray[i] != null) {
1033 valueString.append("\"" + valueArray[i] + "\"");
1034 } else {
1035 valueString.append("null");
1036 }
1037 }
1038 break;
1039 }
1040 default: {
1041 valueString.append(value.toString());
1042 }
1043 }
1044 }
1045 return String.format("%-70s %-15s %s", key, typeString, valueString);
1046 }
1047
1048 private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
1049 ArrayList<String> valueList) {
1050 PrintWriter errPw = getErrPrintWriter();
1051 PersistableBundle bundle = new PersistableBundle();
1052
1053 // First verify that a valid number of values has been provided for the type.
1054 switch (type) {
1055 case BOOLEAN:
1056 case DOUBLE:
1057 case INT:
1058 case LONG: {
1059 if (valueList.size() != 1) {
1060 errPw.println(tag + "Expected 1 value for type " + type
1061 + ". Found: " + valueList.size());
1062 return null;
1063 }
1064 break;
1065 }
1066 case STRING: {
1067 if (valueList.size() > 1) {
1068 errPw.println(tag + "Expected 0 or 1 values for type " + type
1069 + ". Found: " + valueList.size());
1070 return null;
1071 }
1072 break;
1073 }
1074 }
1075
1076 // Parse the value according to type and add it to the Bundle.
1077 switch (type) {
1078 case BOOLEAN: {
1079 if ("true".equalsIgnoreCase(valueList.get(0))) {
1080 bundle.putBoolean(key, true);
1081 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1082 bundle.putBoolean(key, false);
1083 } else {
1084 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1085 return null;
1086 }
1087 break;
1088 }
1089 case DOUBLE: {
1090 try {
1091 bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1092 } catch (NumberFormatException nfe) {
1093 // Not a valid double
1094 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1095 return null;
1096 }
1097 break;
1098 }
1099 case DOUBLE_ARRAY: {
1100 double[] valueDoubleArray = null;
1101 if (valueList.size() > 0) {
1102 valueDoubleArray = new double[valueList.size()];
1103 for (int i = 0; i < valueList.size(); i++) {
1104 try {
1105 valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1106 } catch (NumberFormatException nfe) {
1107 // Not a valid double
1108 errPw.println(
1109 tag + "Unable to parse " + valueList.get(i) + " as a double.");
1110 return null;
1111 }
1112 }
1113 }
1114 bundle.putDoubleArray(key, valueDoubleArray);
1115 break;
1116 }
1117 case INT: {
1118 try {
1119 bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1120 } catch (NumberFormatException nfe) {
1121 // Not a valid integer
1122 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1123 return null;
1124 }
1125 break;
1126 }
1127 case INT_ARRAY: {
1128 int[] valueIntArray = null;
1129 if (valueList.size() > 0) {
1130 valueIntArray = new int[valueList.size()];
1131 for (int i = 0; i < valueList.size(); i++) {
1132 try {
1133 valueIntArray[i] = Integer.parseInt(valueList.get(i));
1134 } catch (NumberFormatException nfe) {
1135 // Not a valid integer
1136 errPw.println(tag
1137 + "Unable to parse " + valueList.get(i) + " as an integer.");
1138 return null;
1139 }
1140 }
1141 }
1142 bundle.putIntArray(key, valueIntArray);
1143 break;
1144 }
1145 case LONG: {
1146 try {
1147 bundle.putLong(key, Long.parseLong(valueList.get(0)));
1148 } catch (NumberFormatException nfe) {
1149 // Not a valid long
1150 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1151 return null;
1152 }
1153 break;
1154 }
1155 case LONG_ARRAY: {
1156 long[] valueLongArray = null;
1157 if (valueList.size() > 0) {
1158 valueLongArray = new long[valueList.size()];
1159 for (int i = 0; i < valueList.size(); i++) {
1160 try {
1161 valueLongArray[i] = Long.parseLong(valueList.get(i));
1162 } catch (NumberFormatException nfe) {
1163 // Not a valid long
1164 errPw.println(
1165 tag + "Unable to parse " + valueList.get(i) + " as a long");
1166 return null;
1167 }
1168 }
1169 }
1170 bundle.putLongArray(key, valueLongArray);
1171 break;
1172 }
1173 case STRING: {
1174 String value = null;
1175 if (valueList.size() > 0) {
1176 value = valueList.get(0);
1177 }
1178 bundle.putString(key, value);
1179 break;
1180 }
1181 case STRING_ARRAY: {
1182 String[] valueStringArray = null;
1183 if (valueList.size() > 0) {
1184 valueStringArray = new String[valueList.size()];
1185 valueList.toArray(valueStringArray);
1186 }
1187 bundle.putStringArray(key, valueStringArray);
1188 break;
1189 }
1190 }
1191 return bundle;
1192 }
Shuo Qian489d9282020-07-09 11:30:03 -07001193
1194 private int handleEndBlockSuppressionCommand() {
1195 if (!checkShellUid()) {
1196 return -1;
1197 }
1198
1199 if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) {
1200 BlockedNumberContract.SystemContract.endBlockSuppression(mContext);
1201 }
1202 return 0;
1203 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001204}