blob: ea129845b2723aa823dd595d51d03f10cf1c0b80 [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
Tyler Gunn92479152021-01-20 16:30:10 -080019import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_AUDIO_CODEC;
20import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_RADIO_ACCESS_TYPE;
21import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_BATTERY_STATE;
22import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_NETWORK_COVERAGE;
23
Hall Liuaa4211e2021-01-20 15:43:39 -080024import android.Manifest;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010025import android.content.Context;
Hall Liuaa4211e2021-01-20 15:43:39 -080026import android.net.Uri;
Hall Liud892bec2018-11-30 14:51:45 -080027import android.os.Binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010028import android.os.PersistableBundle;
Hall Liud892bec2018-11-30 14:51:45 -080029import android.os.Process;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070030import android.os.RemoteException;
Shuo Qian489d9282020-07-09 11:30:03 -070031import android.provider.BlockedNumberContract;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010032import android.telephony.CarrierConfigManager;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070033import android.telephony.SubscriptionManager;
Michele Berionne54af4632020-12-28 20:23:16 +000034import android.telephony.TelephonyManager;
sqian9d4df8b2019-01-15 18:32:07 -080035import android.telephony.emergency.EmergencyNumber;
Brad Ebinger24c29992019-12-05 13:03:21 -080036import android.telephony.ims.feature.ImsFeature;
James.cf Linbcdf8b32021-01-14 16:44:13 +080037import android.text.TextUtils;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070038import android.util.Log;
39
40import com.android.internal.telephony.ITelephony;
Qiong Liuf25799b2020-09-10 10:13:46 +080041import com.android.internal.telephony.Phone;
42import com.android.internal.telephony.PhoneFactory;
Tyler Gunn92479152021-01-20 16:30:10 -080043import com.android.internal.telephony.d2d.Communicator;
sqian9d4df8b2019-01-15 18:32:07 -080044import com.android.internal.telephony.emergency.EmergencyNumberTracker;
Meng Wangc4f61042019-11-21 10:51:05 -080045import com.android.internal.telephony.util.TelephonyUtils;
Chiachang Wang99890092020-11-04 10:59:17 +080046import com.android.modules.utils.BasicShellCommandHandler;
Hall Liuaa4211e2021-01-20 15:43:39 -080047import com.android.phone.callcomposer.CallComposerPictureManager;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070048
49import java.io.PrintWriter;
sqian9d4df8b2019-01-15 18:32:07 -080050import java.util.ArrayList;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010051import java.util.HashMap;
Brad Ebinger24c29992019-12-05 13:03:21 -080052import java.util.List;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010053import java.util.Map;
54import java.util.TreeSet;
Hall Liuaa4211e2021-01-20 15:43:39 -080055import java.util.UUID;
56import java.util.concurrent.CompletableFuture;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070057
58/**
59 * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no
60 * permission checks have been done before onCommand was called. Make sure any commands processed
61 * here also contain the appropriate permissions checks.
62 */
63
Hall Liua1548bd2019-12-24 14:14:12 -080064public class TelephonyShellCommand extends BasicShellCommandHandler {
Brad Ebinger4dc095a2018-04-03 15:17:52 -070065
66 private static final String LOG_TAG = "TelephonyShellCommand";
67 // Don't commit with this true.
68 private static final boolean VDBG = true;
Brad Ebinger0aa2f242018-04-12 09:49:23 -070069 private static final int DEFAULT_PHONE_ID = 0;
Brad Ebinger4dc095a2018-04-03 15:17:52 -070070
Hall Liuaa4211e2021-01-20 15:43:39 -080071 private static final String CALL_COMPOSER_SUBCOMMAND = "callcomposer";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070072 private static final String IMS_SUBCOMMAND = "ims";
Hall Liud892bec2018-11-30 14:51:45 -080073 private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify";
sqian9d4df8b2019-01-15 18:32:07 -080074 private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode";
Shuo Qian489d9282020-07-09 11:30:03 -070075 private static final String END_BLOCK_SUPPRESSION = "end-block-suppression";
Michele Berionne54af4632020-12-28 20:23:16 +000076 private static final String RESTART_MODEM = "restart-modem";
Michele Berionne5e411512020-11-13 02:36:59 +000077 private static final String UNATTENDED_REBOOT = "unattended-reboot";
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010078 private static final String CARRIER_CONFIG_SUBCOMMAND = "cc";
Shuo Qianf5125122019-12-16 17:03:07 -080079 private static final String DATA_TEST_MODE = "data";
Hall Liuaa4211e2021-01-20 15:43:39 -080080 private static final String ENABLE = "enable";
81 private static final String DISABLE = "disable";
82 private static final String QUERY = "query";
83
Hall Liu7135e502021-02-04 16:58:17 -080084 private static final String CALL_COMPOSER_TEST_MODE = "test-mode";
Hall Liuaa4211e2021-01-20 15:43:39 -080085 private static final String CALL_COMPOSER_SIMULATE_CALL = "simulate-outgoing-call";
Hall Liud892bec2018-11-30 14:51:45 -080086
Brad Ebinger999d3302020-11-25 14:31:39 -080087 private static final String IMS_SET_IMS_SERVICE = "set-ims-service";
88 private static final String IMS_GET_IMS_SERVICE = "get-ims-service";
89 private static final String IMS_CLEAR_SERVICE_OVERRIDE = "clear-ims-service-override";
Tyler Gunn7bcdc742019-10-04 15:56:59 -070090 // Used to disable or enable processing of conference event package data from the network.
91 // This is handy for testing scenarios where CEP data does not exist on a network which does
92 // support CEP data.
93 private static final String IMS_CEP = "conference-event-package";
Brad Ebinger4dc095a2018-04-03 15:17:52 -070094
Hall Liud892bec2018-11-30 14:51:45 -080095 private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package";
Hall Liuca5af3a2018-12-04 16:58:23 -080096 private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call";
Hall Liud892bec2018-11-30 14:51:45 -080097
Torbjorn Eklund1050cb02018-11-16 14:05:38 +010098 private static final String CC_GET_VALUE = "get-value";
99 private static final String CC_SET_VALUE = "set-value";
100 private static final String CC_CLEAR_VALUES = "clear-values";
101
Hui Wang641e81c2020-10-12 12:14:23 -0700102 private static final String GBA_SUBCOMMAND = "gba";
103 private static final String GBA_SET_SERVICE = "set-service";
104 private static final String GBA_GET_SERVICE = "get-service";
105 private static final String GBA_SET_RELEASE_TIME = "set-release";
106 private static final String GBA_GET_RELEASE_TIME = "get-release";
107
Hui Wang761a6682020-10-31 05:12:53 +0000108 private static final String SINGLE_REGISTATION_CONFIG = "src";
109 private static final String SRC_SET_DEVICE_ENABLED = "set-device-enabled";
110 private static final String SRC_GET_DEVICE_ENABLED = "get-device-enabled";
111 private static final String SRC_SET_CARRIER_ENABLED = "set-carrier-enabled";
112 private static final String SRC_GET_CARRIER_ENABLED = "get-carrier-enabled";
113
Tyler Gunn92479152021-01-20 16:30:10 -0800114 private static final String D2D_SUBCOMMAND = "d2d";
115 private static final String D2D_SEND = "send";
Tyler Gunnbabbda02021-02-10 11:05:02 -0800116 private static final String D2D_TRANSPORT = "transport";
Tyler Gunn92479152021-01-20 16:30:10 -0800117
James.cf Linbcdf8b32021-01-14 16:44:13 +0800118 private static final String RCS_UCE_COMMAND = "uce";
calvinpane4a8a1d2021-01-25 13:51:18 +0800119 private static final String UCE_GET_EAB_CONTACT = "get-eab-contact";
James.cf Linbcdf8b32021-01-14 16:44:13 +0800120 private static final String UCE_REMOVE_EAB_CONTACT = "remove-eab-contact";
James.cf Lin4b784aa2021-01-31 03:25:15 +0800121 private static final String UCE_GET_DEVICE_ENABLED = "get-device-enabled";
122 private static final String UCE_SET_DEVICE_ENABLED = "set-device-enabled";
James.cf Linbcdf8b32021-01-14 16:44:13 +0800123
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700124 // Take advantage of existing methods that already contain permissions checks when possible.
125 private final ITelephony mInterface;
126
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100127 private SubscriptionManager mSubscriptionManager;
128 private CarrierConfigManager mCarrierConfigManager;
Shuo Qian489d9282020-07-09 11:30:03 -0700129 private Context mContext;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100130
131 private enum CcType {
132 BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING,
133 STRING_ARRAY, UNKNOWN
134 }
135
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100136 private class CcOptionParseResult {
137 public int mSubId;
138 public boolean mPersistent;
139 }
140
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100141 // Maps carrier config keys to type. It is possible to infer the type for most carrier config
142 // keys by looking at the end of the string which usually tells the type.
143 // For instance: "xxxx_string", "xxxx_string_array", etc.
144 // The carrier config keys in this map does not follow this convention. It is therefore not
145 // possible to infer the type for these keys by looking at the string.
146 private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{
147 put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING);
148 put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING);
149 put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING);
150 put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING);
151 put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING);
152 put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING);
153 put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING);
154 put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING);
155 put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING);
156 put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING);
157 put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING,
158 CcType.STRING);
159 put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
160 CcType.STRING_ARRAY);
161 put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
162 CcType.STRING_ARRAY);
163 put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING);
164 put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING);
165 put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING);
166 put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING);
167 put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING);
168 put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING);
169 put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING);
170 put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY);
171 }
172 };
173
174 public TelephonyShellCommand(ITelephony binder, Context context) {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700175 mInterface = binder;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100176 mCarrierConfigManager =
177 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
178 mSubscriptionManager = (SubscriptionManager)
179 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Shuo Qian489d9282020-07-09 11:30:03 -0700180 mContext = context;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700181 }
182
183 @Override
184 public int onCommand(String cmd) {
185 if (cmd == null) {
186 return handleDefaultCommands(null);
187 }
188
189 switch (cmd) {
190 case IMS_SUBCOMMAND: {
191 return handleImsCommand();
192 }
James.cf Linbcdf8b32021-01-14 16:44:13 +0800193 case RCS_UCE_COMMAND:
194 return handleRcsUceCommand();
Hall Liud892bec2018-11-30 14:51:45 -0800195 case NUMBER_VERIFICATION_SUBCOMMAND:
196 return handleNumberVerificationCommand();
sqian9d4df8b2019-01-15 18:32:07 -0800197 case EMERGENCY_NUMBER_TEST_MODE:
198 return handleEmergencyNumberTestModeCommand();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100199 case CARRIER_CONFIG_SUBCOMMAND: {
200 return handleCcCommand();
201 }
Shuo Qianf5125122019-12-16 17:03:07 -0800202 case DATA_TEST_MODE:
203 return handleDataTestModeCommand();
Shuo Qian489d9282020-07-09 11:30:03 -0700204 case END_BLOCK_SUPPRESSION:
205 return handleEndBlockSuppressionCommand();
Hui Wang641e81c2020-10-12 12:14:23 -0700206 case GBA_SUBCOMMAND:
207 return handleGbaCommand();
Tyler Gunn92479152021-01-20 16:30:10 -0800208 case D2D_SUBCOMMAND:
209 return handleD2dCommand();
Hui Wang761a6682020-10-31 05:12:53 +0000210 case SINGLE_REGISTATION_CONFIG:
211 return handleSingleRegistrationConfigCommand();
Michele Berionne54af4632020-12-28 20:23:16 +0000212 case RESTART_MODEM:
213 return handleRestartModemCommand();
Hall Liuaa4211e2021-01-20 15:43:39 -0800214 case CALL_COMPOSER_SUBCOMMAND:
215 return handleCallComposerCommand();
Michele Berionne5e411512020-11-13 02:36:59 +0000216 case UNATTENDED_REBOOT:
217 return handleUnattendedReboot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700218 default: {
219 return handleDefaultCommands(cmd);
220 }
221 }
222 }
223
224 @Override
225 public void onHelp() {
226 PrintWriter pw = getOutPrintWriter();
227 pw.println("Telephony Commands:");
228 pw.println(" help");
229 pw.println(" Print this help text.");
230 pw.println(" ims");
231 pw.println(" IMS Commands.");
James.cf Linbcdf8b32021-01-14 16:44:13 +0800232 pw.println(" uce");
233 pw.println(" RCS User Capability Exchange Commands.");
sqian9d4df8b2019-01-15 18:32:07 -0800234 pw.println(" emergency-number-test-mode");
235 pw.println(" Emergency Number Test Mode Commands.");
Shuo Qian489d9282020-07-09 11:30:03 -0700236 pw.println(" end-block-suppression");
237 pw.println(" End Block Suppression command.");
Shuo Qianf5125122019-12-16 17:03:07 -0800238 pw.println(" data");
239 pw.println(" Data Test Mode Commands.");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100240 pw.println(" cc");
241 pw.println(" Carrier Config Commands.");
Hui Wang641e81c2020-10-12 12:14:23 -0700242 pw.println(" gba");
243 pw.println(" GBA Commands.");
Hui Wang761a6682020-10-31 05:12:53 +0000244 pw.println(" src");
245 pw.println(" RCS VoLTE Single Registration Config Commands.");
Michele Berionne54af4632020-12-28 20:23:16 +0000246 pw.println(" restart-modem");
247 pw.println(" Restart modem command.");
Michele Berionne5e411512020-11-13 02:36:59 +0000248 pw.println(" unattended-reboot");
249 pw.println(" Prepare for unattended reboot.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700250 onHelpIms();
James.cf Linbcdf8b32021-01-14 16:44:13 +0800251 onHelpUce();
sqian9d4df8b2019-01-15 18:32:07 -0800252 onHelpEmergencyNumber();
Shuo Qian489d9282020-07-09 11:30:03 -0700253 onHelpEndBlockSupperssion();
Shuo Qianf5125122019-12-16 17:03:07 -0800254 onHelpDataTestMode();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100255 onHelpCc();
Hui Wang641e81c2020-10-12 12:14:23 -0700256 onHelpGba();
Hui Wang761a6682020-10-31 05:12:53 +0000257 onHelpSrc();
Tyler Gunn92479152021-01-20 16:30:10 -0800258 onHelpD2D();
259 }
260
261 private void onHelpD2D() {
262 PrintWriter pw = getOutPrintWriter();
263 pw.println("D2D Comms Commands:");
264 pw.println(" d2d send TYPE VALUE");
265 pw.println(" Sends a D2D message of specified type and value.");
266 pw.println(" Type: " + MESSAGE_CALL_RADIO_ACCESS_TYPE + " - "
267 + Communicator.messageToString(MESSAGE_CALL_RADIO_ACCESS_TYPE));
268 pw.println(" Type: " + MESSAGE_CALL_AUDIO_CODEC + " - " + Communicator.messageToString(
269 MESSAGE_CALL_AUDIO_CODEC));
270 pw.println(" Type: " + MESSAGE_DEVICE_BATTERY_STATE + " - "
271 + Communicator.messageToString(
272 MESSAGE_DEVICE_BATTERY_STATE));
273 pw.println(" Type: " + MESSAGE_DEVICE_NETWORK_COVERAGE + " - "
274 + Communicator.messageToString(MESSAGE_DEVICE_NETWORK_COVERAGE));
Tyler Gunnbabbda02021-02-10 11:05:02 -0800275 pw.println(" d2d transport TYPE");
276 pw.println(" Forces the specified D2D transport TYPE to be active. Use the");
277 pw.println(" short class name of the transport; i.e. DtmfTransport or RtpTransport.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700278 }
279
280 private void onHelpIms() {
281 PrintWriter pw = getOutPrintWriter();
282 pw.println("IMS Commands:");
Brad Ebinger24c29992019-12-05 13:03:21 -0800283 pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700284 pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
285 pw.println(" ImsService. Options are:");
286 pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
287 pw.println(" is specified, it will choose the default voice SIM slot.");
288 pw.println(" -c: Override the ImsService defined in the carrier configuration.");
289 pw.println(" -d: Override the ImsService defined in the device overlay.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800290 pw.println(" -f: Set the feature that this override if for, if no option is");
291 pw.println(" specified, the new package name will be used for all features.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700292 pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
293 pw.println(" Gets the package name of the currently defined ImsService.");
294 pw.println(" Options are:");
295 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
296 pw.println(" is specified, it will choose the default voice SIM slot.");
297 pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
Peter Kalauskas1defdc32020-09-03 19:20:26 +0000298 pw.println(" -d: The ImsService defined as the device default ImsService.");
Brad Ebinger24c29992019-12-05 13:03:21 -0800299 pw.println(" -f: The feature type that the query will be requested for. If none is");
300 pw.println(" specified, the returned package name will correspond to MMTEL.");
Brad Ebinger999d3302020-11-25 14:31:39 -0800301 pw.println(" ims clear-ims-service-override [-s SLOT_ID]");
302 pw.println(" Clear all carrier ImsService overrides. This does not work for device ");
303 pw.println(" configuration overrides. Options are:");
304 pw.println(" -s: The SIM slot ID for the registered ImsService. If no option");
305 pw.println(" is specified, it will choose the default voice SIM slot.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700306 pw.println(" ims enable [-s SLOT_ID]");
307 pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
308 pw.println(" if none is specified.");
309 pw.println(" ims disable [-s SLOT_ID]");
310 pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM");
311 pw.println(" slot if none is specified.");
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700312 pw.println(" ims conference-event-package [enable/disable]");
313 pw.println(" enables or disables handling or network conference event package data.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700314 }
315
James.cf Linbcdf8b32021-01-14 16:44:13 +0800316 private void onHelpUce() {
317 PrintWriter pw = getOutPrintWriter();
318 pw.println("User Capability Exchange Commands:");
calvinpane4a8a1d2021-01-25 13:51:18 +0800319 pw.println(" uce get-eab-contact [PHONE_NUMBER]");
320 pw.println(" Get the EAB contacts from the EAB database.");
321 pw.println(" Options are:");
322 pw.println(" PHONE_NUMBER: The phone numbers to be removed from the EAB databases");
323 pw.println(" Expected output format :");
324 pw.println(" [PHONE_NUMBER],[RAW_CONTACT_ID],[CONTACT_ID],[DATA_ID]");
James.cf Linbcdf8b32021-01-14 16:44:13 +0800325 pw.println(" uce remove-eab-contact [-s SLOT_ID] [PHONE_NUMBER]");
326 pw.println(" Remove the EAB contacts from the EAB database.");
327 pw.println(" Options are:");
328 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
329 pw.println(" is specified, it will choose the default voice SIM slot.");
330 pw.println(" PHONE_NUMBER: The phone numbers to be removed from the EAB databases");
James.cf Lin4b784aa2021-01-31 03:25:15 +0800331 pw.println(" uce get-device-enabled");
332 pw.println(" Get the config to check whether the device supports RCS UCE or not.");
333 pw.println(" uce set-device-enabled true|false");
334 pw.println(" Set the device config for RCS User Capability Exchange to the value.");
335 pw.println(" The value could be true, false.");
James.cf Linbcdf8b32021-01-14 16:44:13 +0800336 }
337
Hall Liud892bec2018-11-30 14:51:45 -0800338 private void onHelpNumberVerification() {
339 PrintWriter pw = getOutPrintWriter();
340 pw.println("Number verification commands");
341 pw.println(" numverify override-package PACKAGE_NAME;");
342 pw.println(" Set the authorized package for number verification.");
343 pw.println(" Leave the package name blank to reset.");
Hall Liuca5af3a2018-12-04 16:58:23 -0800344 pw.println(" numverify fake-call NUMBER;");
345 pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be");
346 pw.println(" 1 if the call would have been intercepted, 0 otherwise.");
Hall Liud892bec2018-11-30 14:51:45 -0800347 }
348
Shuo Qianf5125122019-12-16 17:03:07 -0800349 private void onHelpDataTestMode() {
350 PrintWriter pw = getOutPrintWriter();
351 pw.println("Mobile Data Test Mode Commands:");
352 pw.println(" data enable: enable mobile data connectivity");
353 pw.println(" data disable: disable mobile data connectivity");
354 }
355
sqian9d4df8b2019-01-15 18:32:07 -0800356 private void onHelpEmergencyNumber() {
357 PrintWriter pw = getOutPrintWriter();
358 pw.println("Emergency Number Test Mode Commands:");
359 pw.println(" emergency-number-test-mode ");
360 pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in"
361 + " the test mode");
362 pw.println(" -a <emergency number address>: add an emergency number address for the"
sqian9121f982019-03-14 19:45:39 -0700363 + " test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800364 pw.println(" -c: clear the emergency number list in the test mode.");
365 pw.println(" -r <emergency number address>: remove an existing emergency number"
sqian9121f982019-03-14 19:45:39 -0700366 + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'.");
sqian9d4df8b2019-01-15 18:32:07 -0800367 pw.println(" -p: get the full emergency number list in the test mode.");
368 }
369
Shuo Qian489d9282020-07-09 11:30:03 -0700370 private void onHelpEndBlockSupperssion() {
371 PrintWriter pw = getOutPrintWriter();
372 pw.println("End Block Suppression command:");
373 pw.println(" end-block-suppression: disable suppressing blocking by contact");
374 pw.println(" with emergency services.");
375 }
376
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100377 private void onHelpCc() {
378 PrintWriter pw = getOutPrintWriter();
379 pw.println("Carrier Config Commands:");
380 pw.println(" cc get-value [-s SLOT_ID] [KEY]");
381 pw.println(" Print carrier config values.");
382 pw.println(" Options are:");
383 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
384 pw.println(" is specified, it will choose the default voice SIM slot.");
385 pw.println(" KEY: The key to the carrier config value to print. All values are printed");
386 pw.println(" if KEY is not specified.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100387 pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100388 pw.println(" Set carrier config KEY to NEW_VALUE.");
389 pw.println(" Options are:");
390 pw.println(" -s: The SIM slot ID to set carrier config value for. If no option");
391 pw.println(" is specified, it will choose the default voice SIM slot.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100392 pw.println(" -p: Value will be stored persistent");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100393 pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be");
394 pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with");
395 pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\"");
396 pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\"");
397 pw.println(" cc clear-values [-s SLOT_ID]");
398 pw.println(" Clear all carrier override values that has previously been set");
399 pw.println(" with set-value");
400 pw.println(" Options are:");
401 pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option");
402 pw.println(" is specified, it will choose the default voice SIM slot.");
403 }
404
Hui Wang641e81c2020-10-12 12:14:23 -0700405 private void onHelpGba() {
406 PrintWriter pw = getOutPrintWriter();
407 pw.println("Gba Commands:");
408 pw.println(" gba set-service [-s SLOT_ID] PACKAGE_NAME");
409 pw.println(" Sets the GbaService defined in PACKAGE_NAME to to be the bound.");
410 pw.println(" Options are:");
411 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
412 pw.println(" is specified, it will choose the default voice SIM slot.");
413 pw.println(" gba get-service [-s SLOT_ID]");
414 pw.println(" Gets the package name of the currently defined GbaService.");
415 pw.println(" Options are:");
416 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
417 pw.println(" is specified, it will choose the default voice SIM slot.");
418 pw.println(" gba set-release [-s SLOT_ID] n");
419 pw.println(" Sets the time to release/unbind GbaService in n milli-second.");
420 pw.println(" Do not release/unbind if n is -1.");
421 pw.println(" Options are:");
422 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
423 pw.println(" is specified, it will choose the default voice SIM slot.");
424 pw.println(" gba get-release [-s SLOT_ID]");
425 pw.println(" Gets the time to release/unbind GbaService in n milli-sencond.");
426 pw.println(" Options are:");
427 pw.println(" -s: The SIM slot ID to read carrier config value for. If no option");
428 pw.println(" is specified, it will choose the default voice SIM slot.");
429 }
430
Hui Wang761a6682020-10-31 05:12:53 +0000431 private void onHelpSrc() {
432 PrintWriter pw = getOutPrintWriter();
433 pw.println("RCS VoLTE Single Registration Config Commands:");
434 pw.println(" src set-device-enabled true|false|null");
435 pw.println(" Sets the device config for RCS VoLTE single registration to the value.");
436 pw.println(" The value could be true, false, or null(undefined).");
437 pw.println(" src get-device-enabled");
438 pw.println(" Gets the device config for RCS VoLTE single registration.");
439 pw.println(" src set-carrier-enabled [-s SLOT_ID] true|false|null");
440 pw.println(" Sets the carrier config for RCS VoLTE single registration to the value.");
441 pw.println(" The value could be true, false, or null(undefined).");
442 pw.println(" Options are:");
443 pw.println(" -s: The SIM slot ID to set the config value for. If no option");
444 pw.println(" is specified, it will choose the default voice SIM slot.");
445 pw.println(" src get-carrier-enabled [-s SLOT_ID]");
446 pw.println(" Gets the carrier config for RCS VoLTE single registration.");
447 pw.println(" Options are:");
448 pw.println(" -s: The SIM slot ID to read the config value for. If no option");
449 pw.println(" is specified, it will choose the default voice SIM slot.");
450 }
451
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700452 private int handleImsCommand() {
453 String arg = getNextArg();
454 if (arg == null) {
455 onHelpIms();
456 return 0;
457 }
458
459 switch (arg) {
Brad Ebinger999d3302020-11-25 14:31:39 -0800460 case IMS_SET_IMS_SERVICE: {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700461 return handleImsSetServiceCommand();
462 }
Brad Ebinger999d3302020-11-25 14:31:39 -0800463 case IMS_GET_IMS_SERVICE: {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700464 return handleImsGetServiceCommand();
465 }
Brad Ebinger999d3302020-11-25 14:31:39 -0800466 case IMS_CLEAR_SERVICE_OVERRIDE: {
467 return handleImsClearCarrierServiceCommand();
468 }
Hall Liuaa4211e2021-01-20 15:43:39 -0800469 case ENABLE: {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700470 return handleEnableIms();
471 }
Hall Liuaa4211e2021-01-20 15:43:39 -0800472 case DISABLE: {
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700473 return handleDisableIms();
474 }
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700475 case IMS_CEP: {
476 return handleCepChange();
477 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700478 }
479
480 return -1;
481 }
482
Shuo Qianf5125122019-12-16 17:03:07 -0800483 private int handleDataTestModeCommand() {
484 PrintWriter errPw = getErrPrintWriter();
485 String arg = getNextArgRequired();
486 if (arg == null) {
487 onHelpDataTestMode();
488 return 0;
489 }
490 switch (arg) {
Hall Liuaa4211e2021-01-20 15:43:39 -0800491 case ENABLE: {
Shuo Qianf5125122019-12-16 17:03:07 -0800492 try {
493 mInterface.enableDataConnectivity();
494 } catch (RemoteException ex) {
495 Log.w(LOG_TAG, "data enable, error " + ex.getMessage());
496 errPw.println("Exception: " + ex.getMessage());
497 return -1;
498 }
499 break;
500 }
Hall Liuaa4211e2021-01-20 15:43:39 -0800501 case DISABLE: {
Shuo Qianf5125122019-12-16 17:03:07 -0800502 try {
503 mInterface.disableDataConnectivity();
504 } catch (RemoteException ex) {
505 Log.w(LOG_TAG, "data disable, error " + ex.getMessage());
506 errPw.println("Exception: " + ex.getMessage());
507 return -1;
508 }
509 break;
510 }
511 default:
512 onHelpDataTestMode();
513 break;
514 }
515 return 0;
516 }
517
sqian9d4df8b2019-01-15 18:32:07 -0800518 private int handleEmergencyNumberTestModeCommand() {
519 PrintWriter errPw = getErrPrintWriter();
520 String opt = getNextOption();
521 if (opt == null) {
522 onHelpEmergencyNumber();
523 return 0;
524 }
525
526 switch (opt) {
527 case "-a": {
528 String emergencyNumberCmd = getNextArgRequired();
529 if (emergencyNumberCmd == null
530 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700531 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800532 + " to be specified after -a in the command ");
533 return -1;
534 }
535 try {
536 mInterface.updateEmergencyNumberListTestMode(
537 EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE,
538 new EmergencyNumber(emergencyNumberCmd, "", "",
539 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
540 new ArrayList<String>(),
541 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
542 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
543 } catch (RemoteException ex) {
544 Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd
545 + ", error " + ex.getMessage());
546 errPw.println("Exception: " + ex.getMessage());
547 return -1;
548 }
549 break;
550 }
551 case "-c": {
552 try {
553 mInterface.updateEmergencyNumberListTestMode(
554 EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null);
555 } catch (RemoteException ex) {
556 Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage());
557 errPw.println("Exception: " + ex.getMessage());
558 return -1;
559 }
560 break;
561 }
562 case "-r": {
563 String emergencyNumberCmd = getNextArgRequired();
564 if (emergencyNumberCmd == null
565 || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) {
sqian9121f982019-03-14 19:45:39 -0700566 errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs"
sqian9d4df8b2019-01-15 18:32:07 -0800567 + " to be specified after -r in the command ");
568 return -1;
569 }
570 try {
571 mInterface.updateEmergencyNumberListTestMode(
572 EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE,
573 new EmergencyNumber(emergencyNumberCmd, "", "",
574 EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
575 new ArrayList<String>(),
576 EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST,
577 EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
578 } catch (RemoteException ex) {
579 Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd
580 + ", error " + ex.getMessage());
581 errPw.println("Exception: " + ex.getMessage());
582 return -1;
583 }
584 break;
585 }
586 case "-p": {
587 try {
588 getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode());
589 } catch (RemoteException ex) {
590 Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage());
591 errPw.println("Exception: " + ex.getMessage());
592 return -1;
593 }
594 break;
595 }
596 default:
597 onHelpEmergencyNumber();
598 break;
599 }
600 return 0;
601 }
602
Hall Liud892bec2018-11-30 14:51:45 -0800603 private int handleNumberVerificationCommand() {
604 String arg = getNextArg();
605 if (arg == null) {
606 onHelpNumberVerification();
607 return 0;
608 }
609
Hall Liuca5af3a2018-12-04 16:58:23 -0800610 if (!checkShellUid()) {
611 return -1;
612 }
613
Hall Liud892bec2018-11-30 14:51:45 -0800614 switch (arg) {
615 case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: {
Hall Liud892bec2018-11-30 14:51:45 -0800616 NumberVerificationManager.overrideAuthorizedPackage(getNextArg());
617 return 0;
618 }
Hall Liuca5af3a2018-12-04 16:58:23 -0800619 case NUMBER_VERIFICATION_FAKE_CALL: {
620 boolean val = NumberVerificationManager.getInstance()
621 .checkIncomingCall(getNextArg());
622 getOutPrintWriter().println(val ? "1" : "0");
623 return 0;
624 }
Hall Liud892bec2018-11-30 14:51:45 -0800625 }
626
627 return -1;
628 }
629
Tyler Gunn92479152021-01-20 16:30:10 -0800630 private int handleD2dCommand() {
631 String arg = getNextArg();
632 if (arg == null) {
633 onHelpD2D();
634 return 0;
635 }
636
637 switch (arg) {
638 case D2D_SEND: {
639 return handleD2dSendCommand();
640 }
Tyler Gunnbabbda02021-02-10 11:05:02 -0800641 case D2D_TRANSPORT: {
642 return handleD2dTransportCommand();
643 }
Tyler Gunn92479152021-01-20 16:30:10 -0800644 }
645
646 return -1;
647 }
648
649 private int handleD2dSendCommand() {
650 PrintWriter errPw = getErrPrintWriter();
Tyler Gunn92479152021-01-20 16:30:10 -0800651 int messageType = -1;
652 int messageValue = -1;
653
Tyler Gunn92479152021-01-20 16:30:10 -0800654 String arg = getNextArg();
655 if (arg == null) {
656 onHelpD2D();
657 return 0;
658 }
659 try {
660 messageType = Integer.parseInt(arg);
661 } catch (NumberFormatException e) {
662 errPw.println("message type must be a valid integer");
663 return -1;
664 }
665
666 arg = getNextArg();
667 if (arg == null) {
668 onHelpD2D();
669 return 0;
670 }
671 try {
672 messageValue = Integer.parseInt(arg);
673 } catch (NumberFormatException e) {
674 errPw.println("message value must be a valid integer");
675 return -1;
676 }
677
678 try {
679 mInterface.sendDeviceToDeviceMessage(messageType, messageValue);
680 } catch (RemoteException e) {
681 Log.w(LOG_TAG, "d2d send error: " + e.getMessage());
682 errPw.println("Exception: " + e.getMessage());
683 return -1;
684 }
685
686 return 0;
687 }
688
Tyler Gunnbabbda02021-02-10 11:05:02 -0800689 private int handleD2dTransportCommand() {
690 PrintWriter errPw = getErrPrintWriter();
691
692 String arg = getNextArg();
693 if (arg == null) {
694 onHelpD2D();
695 return 0;
696 }
697
698 try {
699 mInterface.setActiveDeviceToDeviceTransport(arg);
700 } catch (RemoteException e) {
701 Log.w(LOG_TAG, "d2d transport error: " + e.getMessage());
702 errPw.println("Exception: " + e.getMessage());
703 return -1;
704 }
705 return 0;
706 }
707
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700708 // ims set-ims-service
709 private int handleImsSetServiceCommand() {
710 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700711 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700712 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800713 List<Integer> featuresList = new ArrayList<>();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700714
715 String opt;
716 while ((opt = getNextOption()) != null) {
717 switch (opt) {
718 case "-s": {
719 try {
720 slotId = Integer.parseInt(getNextArgRequired());
721 } catch (NumberFormatException e) {
722 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
723 return -1;
724 }
725 break;
726 }
727 case "-c": {
728 isCarrierService = true;
729 break;
730 }
731 case "-d": {
732 isCarrierService = false;
733 break;
734 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800735 case "-f": {
736 String featureString = getNextArgRequired();
737 String[] features = featureString.split(",");
738 for (int i = 0; i < features.length; i++) {
739 try {
740 Integer result = Integer.parseInt(features[i]);
741 if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
742 || result >= ImsFeature.FEATURE_MAX) {
743 errPw.println("ims set-ims-service -f " + result
744 + " is an invalid feature.");
745 return -1;
746 }
747 featuresList.add(result);
748 } catch (NumberFormatException e) {
749 errPw.println("ims set-ims-service -f tried to parse " + features[i]
750 + " as an integer.");
751 return -1;
752 }
753 }
754 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700755 }
756 }
757 // Mandatory param, either -c or -d
758 if (isCarrierService == null) {
759 errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
760 return -1;
761 }
762
763 String packageName = getNextArg();
764
765 try {
766 if (packageName == null) {
767 packageName = "";
768 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800769 int[] featureArray = new int[featuresList.size()];
770 for (int i = 0; i < featuresList.size(); i++) {
771 featureArray[i] = featuresList.get(i);
772 }
773 boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
774 featureArray, packageName);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700775 if (VDBG) {
776 Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800777 + (isCarrierService ? "-c " : "-d ")
778 + "-f " + featuresList + " "
779 + packageName + ", result=" + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700780 }
781 getOutPrintWriter().println(result);
782 } catch (RemoteException e) {
783 Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800784 + (isCarrierService ? "-c " : "-d ")
785 + "-f " + featuresList + " "
786 + packageName + ", error" + e.getMessage());
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700787 errPw.println("Exception: " + e.getMessage());
788 return -1;
789 }
790 return 0;
791 }
792
Brad Ebinger999d3302020-11-25 14:31:39 -0800793 // ims clear-ims-service-override
794 private int handleImsClearCarrierServiceCommand() {
795 PrintWriter errPw = getErrPrintWriter();
796 int slotId = getDefaultSlot();
797
798 String opt;
799 while ((opt = getNextOption()) != null) {
800 switch (opt) {
801 case "-s": {
802 try {
803 slotId = Integer.parseInt(getNextArgRequired());
804 } catch (NumberFormatException e) {
805 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
806 return -1;
807 }
808 break;
809 }
810 }
811 }
812
813 try {
814 boolean result = mInterface.clearCarrierImsServiceOverride(slotId);
815 if (VDBG) {
816 Log.v(LOG_TAG, "ims clear-ims-service-override -s " + slotId
817 + ", result=" + result);
818 }
819 getOutPrintWriter().println(result);
820 } catch (RemoteException e) {
821 Log.w(LOG_TAG, "ims clear-ims-service-override -s " + slotId
822 + ", error" + e.getMessage());
823 errPw.println("Exception: " + e.getMessage());
824 return -1;
825 }
826 return 0;
827 }
828
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700829 // ims get-ims-service
830 private int handleImsGetServiceCommand() {
831 PrintWriter errPw = getErrPrintWriter();
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700832 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700833 Boolean isCarrierService = null;
Brad Ebinger24c29992019-12-05 13:03:21 -0800834 Integer featureType = ImsFeature.FEATURE_MMTEL;
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700835
836 String opt;
837 while ((opt = getNextOption()) != null) {
838 switch (opt) {
839 case "-s": {
840 try {
841 slotId = Integer.parseInt(getNextArgRequired());
842 } catch (NumberFormatException e) {
843 errPw.println("ims set-ims-service requires an integer as a SLOT_ID.");
844 return -1;
845 }
846 break;
847 }
848 case "-c": {
849 isCarrierService = true;
850 break;
851 }
852 case "-d": {
853 isCarrierService = false;
854 break;
855 }
Brad Ebinger24c29992019-12-05 13:03:21 -0800856 case "-f": {
857 try {
858 featureType = Integer.parseInt(getNextArg());
859 } catch (NumberFormatException e) {
860 errPw.println("ims get-ims-service -f requires valid integer as feature.");
861 return -1;
862 }
863 if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
864 || featureType >= ImsFeature.FEATURE_MAX) {
865 errPw.println("ims get-ims-service -f invalid feature.");
866 return -1;
867 }
868 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700869 }
870 }
871 // Mandatory param, either -c or -d
872 if (isCarrierService == null) {
Brad Ebinger24c29992019-12-05 13:03:21 -0800873 errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700874 return -1;
875 }
876
877 String result;
878 try {
Brad Ebinger24c29992019-12-05 13:03:21 -0800879 result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700880 } catch (RemoteException e) {
881 return -1;
882 }
883 if (VDBG) {
884 Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
Brad Ebinger24c29992019-12-05 13:03:21 -0800885 + (isCarrierService ? "-c " : "-d ")
886 + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
887 + result);
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700888 }
889 getOutPrintWriter().println(result);
890 return 0;
891 }
892
893 private int handleEnableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700894 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700895 String opt;
896 while ((opt = getNextOption()) != null) {
897 switch (opt) {
898 case "-s": {
899 try {
900 slotId = Integer.parseInt(getNextArgRequired());
901 } catch (NumberFormatException e) {
902 getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID.");
903 return -1;
904 }
905 break;
906 }
907 }
908 }
909 try {
910 mInterface.enableIms(slotId);
911 } catch (RemoteException e) {
912 return -1;
913 }
914 if (VDBG) {
915 Log.v(LOG_TAG, "ims enable -s " + slotId);
916 }
917 return 0;
918 }
919
920 private int handleDisableIms() {
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700921 int slotId = getDefaultSlot();
Brad Ebinger4dc095a2018-04-03 15:17:52 -0700922 String opt;
923 while ((opt = getNextOption()) != null) {
924 switch (opt) {
925 case "-s": {
926 try {
927 slotId = Integer.parseInt(getNextArgRequired());
928 } catch (NumberFormatException e) {
929 getErrPrintWriter().println(
930 "ims disable requires an integer as a SLOT_ID.");
931 return -1;
932 }
933 break;
934 }
935 }
936 }
937 try {
938 mInterface.disableIms(slotId);
939 } catch (RemoteException e) {
940 return -1;
941 }
942 if (VDBG) {
943 Log.v(LOG_TAG, "ims disable -s " + slotId);
944 }
945 return 0;
946 }
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700947
Tyler Gunn7bcdc742019-10-04 15:56:59 -0700948 private int handleCepChange() {
949 Log.i(LOG_TAG, "handleCepChange");
950 String opt = getNextArg();
951 if (opt == null) {
952 return -1;
953 }
954 boolean isCepEnabled = opt.equals("enable");
955
956 try {
957 mInterface.setCepEnabled(isCepEnabled);
958 } catch (RemoteException e) {
959 return -1;
960 }
961 return 0;
962 }
963
Brad Ebinger0aa2f242018-04-12 09:49:23 -0700964 private int getDefaultSlot() {
965 int slotId = SubscriptionManager.getDefaultVoicePhoneId();
966 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX
967 || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
968 // If there is no default, default to slot 0.
969 slotId = DEFAULT_PHONE_ID;
970 }
971 return slotId;
972 }
sqian2fff4a32018-11-05 14:18:37 -0800973
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100974 // Parse options related to Carrier Config Commands.
975 private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100976 PrintWriter errPw = getErrPrintWriter();
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100977 CcOptionParseResult result = new CcOptionParseResult();
978 result.mSubId = SubscriptionManager.getDefaultSubscriptionId();
979 result.mPersistent = false;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100980
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100981 String opt;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100982 while ((opt = getNextOption()) != null) {
983 switch (opt) {
984 case "-s": {
985 try {
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100986 result.mSubId = slotStringToSubId(tag, getNextArgRequired());
987 if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) {
988 errPw.println(tag + "No valid subscription found.");
989 return null;
990 }
991
Torbjorn Eklund1050cb02018-11-16 14:05:38 +0100992 } catch (IllegalArgumentException e) {
993 // Missing slot id
994 errPw.println(tag + "SLOT_ID expected after -s.");
Torbjorn Eklund723527a2019-02-13 11:16:25 +0100995 return null;
996 }
997 break;
998 }
999 case "-p": {
1000 if (allowOptionPersistent) {
1001 result.mPersistent = true;
1002 } else {
1003 errPw.println(tag + "Unexpected option " + opt);
1004 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001005 }
1006 break;
1007 }
1008 default: {
1009 errPw.println(tag + "Unknown option " + opt);
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001010 return null;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001011 }
1012 }
1013 }
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001014 return result;
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001015 }
1016
1017 private int slotStringToSubId(String tag, String slotString) {
1018 int slotId = -1;
1019 try {
1020 slotId = Integer.parseInt(slotString);
1021 } catch (NumberFormatException e) {
Qiong Liuf25799b2020-09-10 10:13:46 +08001022 getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID.");
1023 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1024 }
1025
1026 if (!SubscriptionManager.isValidPhoneId(slotId)) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001027 getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID.");
1028 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1029 }
1030
Qiong Liuf25799b2020-09-10 10:13:46 +08001031 Phone phone = PhoneFactory.getPhone(slotId);
1032 if (phone == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001033 getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + ".");
1034 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1035 }
Qiong Liuf25799b2020-09-10 10:13:46 +08001036 return phone.getSubId();
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001037 }
1038
Hall Liud892bec2018-11-30 14:51:45 -08001039 private boolean checkShellUid() {
Hall Liu2ddfc7e2018-12-06 13:09:45 -08001040 // adb can run as root or as shell, depending on whether the device is rooted.
1041 return Binder.getCallingUid() == Process.SHELL_UID
1042 || Binder.getCallingUid() == Process.ROOT_UID;
Hall Liud892bec2018-11-30 14:51:45 -08001043 }
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001044
1045 private int handleCcCommand() {
1046 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
1047 // non user build.
Meng Wangc4f61042019-11-21 10:51:05 -08001048 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001049 getErrPrintWriter().println("cc: Permission denied.");
1050 return -1;
1051 }
1052
1053 String arg = getNextArg();
1054 if (arg == null) {
1055 onHelpCc();
1056 return 0;
1057 }
1058
1059 switch (arg) {
1060 case CC_GET_VALUE: {
1061 return handleCcGetValue();
1062 }
1063 case CC_SET_VALUE: {
1064 return handleCcSetValue();
1065 }
1066 case CC_CLEAR_VALUES: {
1067 return handleCcClearValues();
1068 }
1069 default: {
1070 getErrPrintWriter().println("cc: Unknown argument: " + arg);
1071 }
1072 }
1073 return -1;
1074 }
1075
1076 // cc get-value
1077 private int handleCcGetValue() {
1078 PrintWriter errPw = getErrPrintWriter();
1079 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": ";
1080 String key = null;
1081
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001082 // Parse all options
1083 CcOptionParseResult options = parseCcOptions(tag, false);
1084 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001085 return -1;
1086 }
1087
1088 // Get bundle containing all carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001089 PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001090 if (bundle == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001091 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001092 return -1;
1093 }
1094
1095 // Get the key.
1096 key = getNextArg();
1097 if (key != null) {
1098 // A key was provided. Verify if it is a valid key
1099 if (!bundle.containsKey(key)) {
1100 errPw.println(tag + key + " is not a valid key.");
1101 return -1;
1102 }
1103
1104 // Print the carrier config value for key.
1105 getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle));
1106 } else {
1107 // No key provided. Show all values.
1108 // Iterate over a sorted list of all carrier config keys and print them.
1109 TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet());
1110 for (String k : sortedSet) {
1111 getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle));
1112 }
1113 }
1114 return 0;
1115 }
1116
1117 // cc set-value
1118 private int handleCcSetValue() {
1119 PrintWriter errPw = getErrPrintWriter();
1120 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": ";
1121
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001122 // Parse all options
1123 CcOptionParseResult options = parseCcOptions(tag, true);
1124 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001125 return -1;
1126 }
1127
1128 // Get bundle containing all current carrier configuration values.
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001129 PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001130 if (originalValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001131 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001132 return -1;
1133 }
1134
1135 // Get the key.
1136 String key = getNextArg();
1137 if (key == null || key.equals("")) {
1138 errPw.println(tag + "KEY is missing");
1139 return -1;
1140 }
1141
1142 // Verify if the key is valid
1143 if (!originalValues.containsKey(key)) {
1144 errPw.println(tag + key + " is not a valid key.");
1145 return -1;
1146 }
1147
1148 // Remaining arguments is a list of new values. Add them all into an ArrayList.
1149 ArrayList<String> valueList = new ArrayList<String>();
1150 while (peekNextArg() != null) {
1151 valueList.add(getNextArg());
1152 }
1153
1154 // Find the type of the carrier config value
1155 CcType type = getType(tag, key, originalValues);
1156 if (type == CcType.UNKNOWN) {
1157 errPw.println(tag + "ERROR: Not possible to override key with unknown type.");
1158 return -1;
1159 }
1160
1161 // Create an override bundle containing the key and value that should be overriden.
1162 PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList);
1163 if (overrideBundle == null) {
1164 return -1;
1165 }
1166
1167 // Override the value
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001168 mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001169
1170 // Find bundle containing all new carrier configuration values after the override.
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001171 PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001172 if (newValues == null) {
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001173 errPw.println(tag + "No carrier config values found for subId " + options.mSubId + ".");
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001174 return -1;
1175 }
1176
1177 // Print the original and new value.
1178 String originalValueString = ccValueToString(key, type, originalValues);
1179 String newValueString = ccValueToString(key, type, newValues);
1180 getOutPrintWriter().println("Previous value: \n" + originalValueString);
1181 getOutPrintWriter().println("New value: \n" + newValueString);
1182
1183 return 0;
1184 }
1185
1186 // cc clear-values
1187 private int handleCcClearValues() {
1188 PrintWriter errPw = getErrPrintWriter();
1189 String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": ";
1190
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001191 // Parse all options
1192 CcOptionParseResult options = parseCcOptions(tag, false);
1193 if (options == null) {
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001194 return -1;
1195 }
1196
1197 // Clear all values that has previously been set.
Torbjorn Eklund723527a2019-02-13 11:16:25 +01001198 mCarrierConfigManager.overrideConfig(options.mSubId, null, true);
Torbjorn Eklund1050cb02018-11-16 14:05:38 +01001199 getOutPrintWriter()
1200 .println("All previously set carrier config override values has been cleared");
1201 return 0;
1202 }
1203
1204 private CcType getType(String tag, String key, PersistableBundle bundle) {
1205 // Find the type by checking the type of the current value stored in the bundle.
1206 Object value = bundle.get(key);
1207
1208 if (CC_TYPE_MAP.containsKey(key)) {
1209 return CC_TYPE_MAP.get(key);
1210 } else if (value != null) {
1211 if (value instanceof Boolean) {
1212 return CcType.BOOLEAN;
1213 } else if (value instanceof Double) {
1214 return CcType.DOUBLE;
1215 } else if (value instanceof double[]) {
1216 return CcType.DOUBLE_ARRAY;
1217 } else if (value instanceof Integer) {
1218 return CcType.INT;
1219 } else if (value instanceof int[]) {
1220 return CcType.INT_ARRAY;
1221 } else if (value instanceof Long) {
1222 return CcType.LONG;
1223 } else if (value instanceof long[]) {
1224 return CcType.LONG_ARRAY;
1225 } else if (value instanceof String) {
1226 return CcType.STRING;
1227 } else if (value instanceof String[]) {
1228 return CcType.STRING_ARRAY;
1229 }
1230 } else {
1231 // Current value was null and can therefore not be used in order to find the type.
1232 // Check the name of the key to infer the type. This check is not needed for primitive
1233 // data types (boolean, double, int and long), since they can not be null.
1234 if (key.endsWith("double_array")) {
1235 return CcType.DOUBLE_ARRAY;
1236 }
1237 if (key.endsWith("int_array")) {
1238 return CcType.INT_ARRAY;
1239 }
1240 if (key.endsWith("long_array")) {
1241 return CcType.LONG_ARRAY;
1242 }
1243 if (key.endsWith("string")) {
1244 return CcType.STRING;
1245 }
1246 if (key.endsWith("string_array") || key.endsWith("strings")) {
1247 return CcType.STRING_ARRAY;
1248 }
1249 }
1250
1251 // Not possible to infer the type by looking at the current value or the key.
1252 PrintWriter errPw = getErrPrintWriter();
1253 errPw.println(tag + "ERROR: " + key + " has unknown type.");
1254 return CcType.UNKNOWN;
1255 }
1256
1257 private String ccValueToString(String key, CcType type, PersistableBundle bundle) {
1258 String result;
1259 StringBuilder valueString = new StringBuilder();
1260 String typeString = type.toString();
1261 Object value = bundle.get(key);
1262
1263 if (value == null) {
1264 valueString.append("null");
1265 } else {
1266 switch (type) {
1267 case DOUBLE_ARRAY: {
1268 // Format the string representation of the int array as value1 value2......
1269 double[] valueArray = (double[]) value;
1270 for (int i = 0; i < valueArray.length; i++) {
1271 if (i != 0) {
1272 valueString.append(" ");
1273 }
1274 valueString.append(valueArray[i]);
1275 }
1276 break;
1277 }
1278 case INT_ARRAY: {
1279 // Format the string representation of the int array as value1 value2......
1280 int[] valueArray = (int[]) value;
1281 for (int i = 0; i < valueArray.length; i++) {
1282 if (i != 0) {
1283 valueString.append(" ");
1284 }
1285 valueString.append(valueArray[i]);
1286 }
1287 break;
1288 }
1289 case LONG_ARRAY: {
1290 // Format the string representation of the int array as value1 value2......
1291 long[] valueArray = (long[]) value;
1292 for (int i = 0; i < valueArray.length; i++) {
1293 if (i != 0) {
1294 valueString.append(" ");
1295 }
1296 valueString.append(valueArray[i]);
1297 }
1298 break;
1299 }
1300 case STRING: {
1301 valueString.append("\"" + value.toString() + "\"");
1302 break;
1303 }
1304 case STRING_ARRAY: {
1305 // Format the string representation of the string array as "value1" "value2"....
1306 String[] valueArray = (String[]) value;
1307 for (int i = 0; i < valueArray.length; i++) {
1308 if (i != 0) {
1309 valueString.append(" ");
1310 }
1311 if (valueArray[i] != null) {
1312 valueString.append("\"" + valueArray[i] + "\"");
1313 } else {
1314 valueString.append("null");
1315 }
1316 }
1317 break;
1318 }
1319 default: {
1320 valueString.append(value.toString());
1321 }
1322 }
1323 }
1324 return String.format("%-70s %-15s %s", key, typeString, valueString);
1325 }
1326
1327 private PersistableBundle getOverrideBundle(String tag, CcType type, String key,
1328 ArrayList<String> valueList) {
1329 PrintWriter errPw = getErrPrintWriter();
1330 PersistableBundle bundle = new PersistableBundle();
1331
1332 // First verify that a valid number of values has been provided for the type.
1333 switch (type) {
1334 case BOOLEAN:
1335 case DOUBLE:
1336 case INT:
1337 case LONG: {
1338 if (valueList.size() != 1) {
1339 errPw.println(tag + "Expected 1 value for type " + type
1340 + ". Found: " + valueList.size());
1341 return null;
1342 }
1343 break;
1344 }
1345 case STRING: {
1346 if (valueList.size() > 1) {
1347 errPw.println(tag + "Expected 0 or 1 values for type " + type
1348 + ". Found: " + valueList.size());
1349 return null;
1350 }
1351 break;
1352 }
1353 }
1354
1355 // Parse the value according to type and add it to the Bundle.
1356 switch (type) {
1357 case BOOLEAN: {
1358 if ("true".equalsIgnoreCase(valueList.get(0))) {
1359 bundle.putBoolean(key, true);
1360 } else if ("false".equalsIgnoreCase(valueList.get(0))) {
1361 bundle.putBoolean(key, false);
1362 } else {
1363 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1364 return null;
1365 }
1366 break;
1367 }
1368 case DOUBLE: {
1369 try {
1370 bundle.putDouble(key, Double.parseDouble(valueList.get(0)));
1371 } catch (NumberFormatException nfe) {
1372 // Not a valid double
1373 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1374 return null;
1375 }
1376 break;
1377 }
1378 case DOUBLE_ARRAY: {
1379 double[] valueDoubleArray = null;
1380 if (valueList.size() > 0) {
1381 valueDoubleArray = new double[valueList.size()];
1382 for (int i = 0; i < valueList.size(); i++) {
1383 try {
1384 valueDoubleArray[i] = Double.parseDouble(valueList.get(i));
1385 } catch (NumberFormatException nfe) {
1386 // Not a valid double
1387 errPw.println(
1388 tag + "Unable to parse " + valueList.get(i) + " as a double.");
1389 return null;
1390 }
1391 }
1392 }
1393 bundle.putDoubleArray(key, valueDoubleArray);
1394 break;
1395 }
1396 case INT: {
1397 try {
1398 bundle.putInt(key, Integer.parseInt(valueList.get(0)));
1399 } catch (NumberFormatException nfe) {
1400 // Not a valid integer
1401 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type);
1402 return null;
1403 }
1404 break;
1405 }
1406 case INT_ARRAY: {
1407 int[] valueIntArray = null;
1408 if (valueList.size() > 0) {
1409 valueIntArray = new int[valueList.size()];
1410 for (int i = 0; i < valueList.size(); i++) {
1411 try {
1412 valueIntArray[i] = Integer.parseInt(valueList.get(i));
1413 } catch (NumberFormatException nfe) {
1414 // Not a valid integer
1415 errPw.println(tag
1416 + "Unable to parse " + valueList.get(i) + " as an integer.");
1417 return null;
1418 }
1419 }
1420 }
1421 bundle.putIntArray(key, valueIntArray);
1422 break;
1423 }
1424 case LONG: {
1425 try {
1426 bundle.putLong(key, Long.parseLong(valueList.get(0)));
1427 } catch (NumberFormatException nfe) {
1428 // Not a valid long
1429 errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type);
1430 return null;
1431 }
1432 break;
1433 }
1434 case LONG_ARRAY: {
1435 long[] valueLongArray = null;
1436 if (valueList.size() > 0) {
1437 valueLongArray = new long[valueList.size()];
1438 for (int i = 0; i < valueList.size(); i++) {
1439 try {
1440 valueLongArray[i] = Long.parseLong(valueList.get(i));
1441 } catch (NumberFormatException nfe) {
1442 // Not a valid long
1443 errPw.println(
1444 tag + "Unable to parse " + valueList.get(i) + " as a long");
1445 return null;
1446 }
1447 }
1448 }
1449 bundle.putLongArray(key, valueLongArray);
1450 break;
1451 }
1452 case STRING: {
1453 String value = null;
1454 if (valueList.size() > 0) {
1455 value = valueList.get(0);
1456 }
1457 bundle.putString(key, value);
1458 break;
1459 }
1460 case STRING_ARRAY: {
1461 String[] valueStringArray = null;
1462 if (valueList.size() > 0) {
1463 valueStringArray = new String[valueList.size()];
1464 valueList.toArray(valueStringArray);
1465 }
1466 bundle.putStringArray(key, valueStringArray);
1467 break;
1468 }
1469 }
1470 return bundle;
1471 }
Shuo Qian489d9282020-07-09 11:30:03 -07001472
1473 private int handleEndBlockSuppressionCommand() {
1474 if (!checkShellUid()) {
1475 return -1;
1476 }
1477
1478 if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) {
1479 BlockedNumberContract.SystemContract.endBlockSuppression(mContext);
1480 }
1481 return 0;
1482 }
Hui Wang641e81c2020-10-12 12:14:23 -07001483
Michele Berionne54af4632020-12-28 20:23:16 +00001484 private int handleRestartModemCommand() {
1485 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
1486 // non user build.
1487 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
1488 getErrPrintWriter().println("RestartModem: Permission denied.");
1489 return -1;
1490 }
1491
1492 boolean result = TelephonyManager.getDefault().rebootRadio();
1493 getOutPrintWriter().println(result);
1494
1495 return result ? 0 : -1;
1496 }
1497
Michele Berionne5e411512020-11-13 02:36:59 +00001498 private int handleUnattendedReboot() {
1499 // Verify that the user is allowed to run the command. Only allowed in rooted device in a
1500 // non user build.
1501 if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) {
1502 getErrPrintWriter().println("UnattendedReboot: Permission denied.");
1503 return -1;
1504 }
1505
1506 int result = TelephonyManager.getDefault().prepareForUnattendedReboot();
1507 getOutPrintWriter().println("result: " + result);
1508
1509 return result != TelephonyManager.PREPARE_UNATTENDED_REBOOT_ERROR ? 0 : -1;
1510 }
1511
Hui Wang641e81c2020-10-12 12:14:23 -07001512 private int handleGbaCommand() {
1513 String arg = getNextArg();
1514 if (arg == null) {
1515 onHelpGba();
1516 return 0;
1517 }
1518
1519 switch (arg) {
1520 case GBA_SET_SERVICE: {
1521 return handleGbaSetServiceCommand();
1522 }
1523 case GBA_GET_SERVICE: {
1524 return handleGbaGetServiceCommand();
1525 }
1526 case GBA_SET_RELEASE_TIME: {
1527 return handleGbaSetReleaseCommand();
1528 }
1529 case GBA_GET_RELEASE_TIME: {
1530 return handleGbaGetReleaseCommand();
1531 }
1532 }
1533
1534 return -1;
1535 }
1536
1537 private int getSubId(String cmd) {
1538 int slotId = getDefaultSlot();
1539 String opt = getNextOption();
1540 if (opt != null && opt.equals("-s")) {
1541 try {
1542 slotId = Integer.parseInt(getNextArgRequired());
1543 } catch (NumberFormatException e) {
1544 getErrPrintWriter().println(cmd + " requires an integer as a SLOT_ID.");
1545 return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1546 }
1547 }
1548 int[] subIds = SubscriptionManager.getSubId(slotId);
1549 return subIds[0];
1550 }
1551
1552 private int handleGbaSetServiceCommand() {
1553 int subId = getSubId("gba set-service");
1554 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1555 return -1;
1556 }
1557
1558 String packageName = getNextArg();
1559 try {
1560 if (packageName == null) {
1561 packageName = "";
1562 }
1563 boolean result = mInterface.setBoundGbaServiceOverride(subId, packageName);
1564 if (VDBG) {
1565 Log.v(LOG_TAG, "gba set-service -s " + subId + " "
1566 + packageName + ", result=" + result);
1567 }
1568 getOutPrintWriter().println(result);
1569 } catch (RemoteException e) {
1570 Log.w(LOG_TAG, "gba set-service " + subId + " "
1571 + packageName + ", error" + e.getMessage());
1572 getErrPrintWriter().println("Exception: " + e.getMessage());
1573 return -1;
1574 }
1575 return 0;
1576 }
1577
1578 private int handleGbaGetServiceCommand() {
1579 String result;
1580
1581 int subId = getSubId("gba get-service");
1582 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1583 return -1;
1584 }
1585
1586 try {
1587 result = mInterface.getBoundGbaService(subId);
1588 } catch (RemoteException e) {
1589 return -1;
1590 }
1591 if (VDBG) {
1592 Log.v(LOG_TAG, "gba get-service -s " + subId + ", returned: " + result);
1593 }
1594 getOutPrintWriter().println(result);
1595 return 0;
1596 }
1597
1598 private int handleGbaSetReleaseCommand() {
1599 //the release time value could be -1
1600 int subId = getRemainingArgsCount() > 1 ? getSubId("gba set-release")
1601 : SubscriptionManager.getDefaultSubscriptionId();
1602 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1603 return -1;
1604 }
1605
1606 String intervalStr = getNextArg();
1607 if (intervalStr == null) {
1608 return -1;
1609 }
1610
1611 try {
1612 int interval = Integer.parseInt(intervalStr);
1613 boolean result = mInterface.setGbaReleaseTimeOverride(subId, interval);
1614 if (VDBG) {
1615 Log.v(LOG_TAG, "gba set-release -s " + subId + " "
1616 + intervalStr + ", result=" + result);
1617 }
1618 getOutPrintWriter().println(result);
1619 } catch (NumberFormatException | RemoteException e) {
1620 Log.w(LOG_TAG, "gba set-release -s " + subId + " "
1621 + intervalStr + ", error" + e.getMessage());
1622 getErrPrintWriter().println("Exception: " + e.getMessage());
1623 return -1;
1624 }
1625 return 0;
1626 }
1627
1628 private int handleGbaGetReleaseCommand() {
1629 int subId = getSubId("gba get-release");
1630 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1631 return -1;
1632 }
1633
1634 int result = 0;
1635 try {
1636 result = mInterface.getGbaReleaseTime(subId);
1637 } catch (RemoteException e) {
1638 return -1;
1639 }
1640 if (VDBG) {
1641 Log.v(LOG_TAG, "gba get-release -s " + subId + ", returned: " + result);
1642 }
1643 getOutPrintWriter().println(result);
1644 return 0;
1645 }
Hui Wang761a6682020-10-31 05:12:53 +00001646
1647 private int handleSingleRegistrationConfigCommand() {
1648 String arg = getNextArg();
1649 if (arg == null) {
1650 onHelpSrc();
1651 return 0;
1652 }
1653
1654 switch (arg) {
1655 case SRC_SET_DEVICE_ENABLED: {
1656 return handleSrcSetDeviceEnabledCommand();
1657 }
1658 case SRC_GET_DEVICE_ENABLED: {
1659 return handleSrcGetDeviceEnabledCommand();
1660 }
1661 case SRC_SET_CARRIER_ENABLED: {
1662 return handleSrcSetCarrierEnabledCommand();
1663 }
1664 case SRC_GET_CARRIER_ENABLED: {
1665 return handleSrcGetCarrierEnabledCommand();
1666 }
1667 }
1668
1669 return -1;
1670 }
1671
James.cf Linbcdf8b32021-01-14 16:44:13 +08001672 private int handleRcsUceCommand() {
1673 String arg = getNextArg();
1674 if (arg == null) {
1675 Log.w(LOG_TAG, "cannot get uce parameter");
1676 return -1;
1677 }
1678
1679 switch (arg) {
1680 case UCE_REMOVE_EAB_CONTACT:
1681 return handleRemovingEabContactCommand();
calvinpane4a8a1d2021-01-25 13:51:18 +08001682 case UCE_GET_EAB_CONTACT:
1683 return handleGettingEabContactCommand();
James.cf Lin4b784aa2021-01-31 03:25:15 +08001684 case UCE_GET_DEVICE_ENABLED:
1685 return handleUceGetDeviceEnabledCommand();
1686 case UCE_SET_DEVICE_ENABLED:
1687 return handleUceSetDeviceEnabledCommand();
James.cf Linbcdf8b32021-01-14 16:44:13 +08001688 }
1689 return -1;
1690 }
1691
1692 private int handleRemovingEabContactCommand() {
1693 int subId = getSubId("uce remove-eab-contact");
1694 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1695 return -1;
1696 }
1697
1698 String phoneNumber = getNextArgRequired();
1699 if (TextUtils.isEmpty(phoneNumber)) {
1700 return -1;
1701 }
1702 int result = 0;
1703 try {
1704 result = mInterface.removeContactFromEab(subId, phoneNumber);
1705 } catch (RemoteException e) {
1706 Log.w(LOG_TAG, "uce remove-eab-contact -s " + subId + ", error " + e.getMessage());
1707 getErrPrintWriter().println("Exception: " + e.getMessage());
1708 return -1;
1709 }
1710
1711 if (VDBG) {
1712 Log.v(LOG_TAG, "uce remove-eab-contact -s " + subId + ", result: " + result);
1713 }
calvinpan293ea1b2021-02-04 17:52:13 +08001714 return 0;
James.cf Linbcdf8b32021-01-14 16:44:13 +08001715 }
1716
calvinpane4a8a1d2021-01-25 13:51:18 +08001717 private int handleGettingEabContactCommand() {
1718 String phoneNumber = getNextArgRequired();
1719 if (TextUtils.isEmpty(phoneNumber)) {
1720 return -1;
1721 }
1722 String result = "";
1723 try {
1724 result = mInterface.getContactFromEab(phoneNumber);
1725
1726 } catch (RemoteException e) {
1727 Log.w(LOG_TAG, "uce get-eab-contact, error " + e.getMessage());
1728 getErrPrintWriter().println("Exception: " + e.getMessage());
1729 return -1;
1730 }
1731
1732 if (VDBG) {
1733 Log.v(LOG_TAG, "uce get-eab-contact, result: " + result);
1734 }
calvinpan293ea1b2021-02-04 17:52:13 +08001735 getOutPrintWriter().println(result);
James.cf Lin4b784aa2021-01-31 03:25:15 +08001736 return 0;
1737 }
1738
1739 private int handleUceGetDeviceEnabledCommand() {
1740 boolean result = false;
1741 try {
1742 result = mInterface.getDeviceUceEnabled();
1743 } catch (RemoteException e) {
1744 Log.w(LOG_TAG, "uce get-device-enabled, error " + e.getMessage());
1745 return -1;
1746 }
1747 if (VDBG) {
1748 Log.v(LOG_TAG, "uce get-device-enabled, returned: " + result);
1749 }
calvinpane4a8a1d2021-01-25 13:51:18 +08001750 getOutPrintWriter().println(result);
1751 return 0;
1752 }
1753
James.cf Lin4b784aa2021-01-31 03:25:15 +08001754 private int handleUceSetDeviceEnabledCommand() {
1755 String enabledStr = getNextArg();
1756 if (TextUtils.isEmpty(enabledStr)) {
1757 return -1;
1758 }
1759
1760 try {
1761 boolean isEnabled = Boolean.parseBoolean(enabledStr);
1762 mInterface.setDeviceUceEnabled(isEnabled);
1763 if (VDBG) {
1764 Log.v(LOG_TAG, "uce set-device-enabled " + enabledStr + ", done");
1765 }
1766 } catch (NumberFormatException | RemoteException e) {
1767 Log.w(LOG_TAG, "uce set-device-enabled " + enabledStr + ", error " + e.getMessage());
1768 getErrPrintWriter().println("Exception: " + e.getMessage());
1769 return -1;
1770 }
1771 return 0;
1772 }
1773
Hui Wang761a6682020-10-31 05:12:53 +00001774 private int handleSrcSetDeviceEnabledCommand() {
1775 String enabledStr = getNextArg();
1776 if (enabledStr == null) {
1777 return -1;
1778 }
1779
1780 try {
1781 mInterface.setDeviceSingleRegistrationEnabledOverride(enabledStr);
1782 if (VDBG) {
1783 Log.v(LOG_TAG, "src set-device-enabled " + enabledStr + ", done");
1784 }
1785 getOutPrintWriter().println("Done");
1786 } catch (NumberFormatException | RemoteException e) {
1787 Log.w(LOG_TAG, "src set-device-enabled " + enabledStr + ", error" + e.getMessage());
1788 getErrPrintWriter().println("Exception: " + e.getMessage());
1789 return -1;
1790 }
1791 return 0;
1792 }
1793
1794 private int handleSrcGetDeviceEnabledCommand() {
1795 boolean result = false;
1796 try {
1797 result = mInterface.getDeviceSingleRegistrationEnabled();
1798 } catch (RemoteException e) {
1799 return -1;
1800 }
1801 if (VDBG) {
1802 Log.v(LOG_TAG, "src get-device-enabled, returned: " + result);
1803 }
1804 getOutPrintWriter().println(result);
1805 return 0;
1806 }
1807
1808 private int handleSrcSetCarrierEnabledCommand() {
1809 //the release time value could be -1
1810 int subId = getRemainingArgsCount() > 1 ? getSubId("src set-carrier-enabled")
1811 : SubscriptionManager.getDefaultSubscriptionId();
1812 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1813 return -1;
1814 }
1815
1816 String enabledStr = getNextArg();
1817 if (enabledStr == null) {
1818 return -1;
1819 }
1820
1821 try {
1822 boolean result =
1823 mInterface.setCarrierSingleRegistrationEnabledOverride(subId, enabledStr);
1824 if (VDBG) {
1825 Log.v(LOG_TAG, "src set-carrier-enabled -s " + subId + " "
1826 + enabledStr + ", result=" + result);
1827 }
1828 getOutPrintWriter().println(result);
1829 } catch (NumberFormatException | RemoteException e) {
1830 Log.w(LOG_TAG, "src set-carrier-enabled -s " + subId + " "
1831 + enabledStr + ", error" + e.getMessage());
1832 getErrPrintWriter().println("Exception: " + e.getMessage());
1833 return -1;
1834 }
1835 return 0;
1836 }
1837
1838 private int handleSrcGetCarrierEnabledCommand() {
1839 int subId = getSubId("src get-carrier-enabled");
1840 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1841 return -1;
1842 }
1843
1844 boolean result = false;
1845 try {
1846 result = mInterface.getCarrierSingleRegistrationEnabled(subId);
1847 } catch (RemoteException e) {
1848 return -1;
1849 }
1850 if (VDBG) {
1851 Log.v(LOG_TAG, "src get-carrier-enabled -s " + subId + ", returned: " + result);
1852 }
1853 getOutPrintWriter().println(result);
1854 return 0;
1855 }
Hall Liuaa4211e2021-01-20 15:43:39 -08001856
1857 private void onHelpCallComposer() {
1858 PrintWriter pw = getOutPrintWriter();
1859 pw.println("Call composer commands");
1860 pw.println(" callcomposer test-mode enable|disable|query");
1861 pw.println(" Enables or disables test mode for call composer. In test mode, picture");
1862 pw.println(" upload/download from carrier servers is disabled, and operations are");
1863 pw.println(" performed using emulated local files instead.");
1864 pw.println(" callcomposer simulate-outgoing-call [subId] [UUID]");
1865 pw.println(" Simulates an outgoing call being placed with the picture ID as");
1866 pw.println(" the provided UUID. This triggers storage to the call log.");
1867 }
1868
1869 private int handleCallComposerCommand() {
1870 String arg = getNextArg();
1871 if (arg == null) {
1872 onHelpCallComposer();
1873 return 0;
1874 }
1875
1876 mContext.enforceCallingPermission(Manifest.permission.MODIFY_PHONE_STATE,
1877 "MODIFY_PHONE_STATE required for call composer shell cmds");
1878 switch (arg) {
1879 case CALL_COMPOSER_TEST_MODE: {
1880 String enabledStr = getNextArg();
1881 if (ENABLE.equals(enabledStr)) {
1882 CallComposerPictureManager.sTestMode = true;
1883 } else if (DISABLE.equals(enabledStr)) {
1884 CallComposerPictureManager.sTestMode = false;
1885 } else if (QUERY.equals(enabledStr)) {
1886 getOutPrintWriter().println(CallComposerPictureManager.sTestMode);
1887 } else {
1888 onHelpCallComposer();
1889 return 1;
1890 }
1891 break;
1892 }
1893 case CALL_COMPOSER_SIMULATE_CALL: {
1894 int subscriptionId = Integer.valueOf(getNextArg());
1895 String uuidString = getNextArg();
1896 UUID uuid = UUID.fromString(uuidString);
1897 CompletableFuture<Uri> storageUriFuture = new CompletableFuture<>();
1898 Binder.withCleanCallingIdentity(() -> {
1899 CallComposerPictureManager.getInstance(mContext, subscriptionId)
1900 .storeUploadedPictureToCallLog(uuid, storageUriFuture::complete);
1901 });
1902 try {
1903 Uri uri = storageUriFuture.get();
1904 getOutPrintWriter().println(String.valueOf(uri));
1905 } catch (Exception e) {
1906 throw new RuntimeException(e);
1907 }
1908 break;
1909 }
1910 }
1911
1912 return 0;
1913 }
Brad Ebinger4dc095a2018-04-03 15:17:52 -07001914}