| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.phone; |
| |
| import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_AUDIO_CODEC; |
| import static com.android.internal.telephony.d2d.Communicator.MESSAGE_CALL_RADIO_ACCESS_TYPE; |
| import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_BATTERY_STATE; |
| import static com.android.internal.telephony.d2d.Communicator.MESSAGE_DEVICE_NETWORK_COVERAGE; |
| |
| import android.Manifest; |
| import android.content.Context; |
| import android.net.Uri; |
| import android.os.Binder; |
| import android.os.PersistableBundle; |
| import android.os.Process; |
| import android.os.RemoteException; |
| import android.os.ServiceSpecificException; |
| import android.provider.BlockedNumberContract; |
| import android.provider.DeviceConfig; |
| import android.telephony.BarringInfo; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.SubscriptionInfo; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.telephony.TelephonyRegistryManager; |
| import android.telephony.emergency.EmergencyNumber; |
| import android.telephony.ims.ImsException; |
| import android.telephony.ims.RcsContactUceCapability; |
| import android.telephony.ims.feature.ImsFeature; |
| import android.text.TextUtils; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.util.SparseArray; |
| |
| import com.android.ims.rcs.uce.util.FeatureTags; |
| import com.android.internal.telephony.ITelephony; |
| import com.android.internal.telephony.Phone; |
| import com.android.internal.telephony.PhoneFactory; |
| import com.android.internal.telephony.d2d.Communicator; |
| import com.android.internal.telephony.emergency.EmergencyNumberTracker; |
| import com.android.internal.telephony.util.TelephonyUtils; |
| import com.android.modules.utils.BasicShellCommandHandler; |
| import com.android.phone.callcomposer.CallComposerPictureManager; |
| |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| import java.util.UUID; |
| import java.util.concurrent.CompletableFuture; |
| |
| /** |
| * Takes actions based on the adb commands given by "adb shell cmd phone ...". Be careful, no |
| * permission checks have been done before onCommand was called. Make sure any commands processed |
| * here also contain the appropriate permissions checks. |
| */ |
| |
| public class TelephonyShellCommand extends BasicShellCommandHandler { |
| |
| private static final String LOG_TAG = "TelephonyShellCommand"; |
| // Don't commit with this true. |
| private static final boolean VDBG = true; |
| private static final int DEFAULT_PHONE_ID = 0; |
| |
| private static final String CALL_COMPOSER_SUBCOMMAND = "callcomposer"; |
| private static final String IMS_SUBCOMMAND = "ims"; |
| private static final String NUMBER_VERIFICATION_SUBCOMMAND = "numverify"; |
| private static final String EMERGENCY_CALLBACK_MODE = "emergency-callback-mode"; |
| private static final String EMERGENCY_NUMBER_TEST_MODE = "emergency-number-test-mode"; |
| private static final String END_BLOCK_SUPPRESSION = "end-block-suppression"; |
| private static final String RESTART_MODEM = "restart-modem"; |
| private static final String UNATTENDED_REBOOT = "unattended-reboot"; |
| private static final String CARRIER_CONFIG_SUBCOMMAND = "cc"; |
| private static final String DATA_TEST_MODE = "data"; |
| private static final String ENABLE = "enable"; |
| private static final String DISABLE = "disable"; |
| private static final String QUERY = "query"; |
| |
| private static final String CALL_COMPOSER_TEST_MODE = "test-mode"; |
| private static final String CALL_COMPOSER_SIMULATE_CALL = "simulate-outgoing-call"; |
| private static final String CALL_COMPOSER_USER_SETTING = "user-setting"; |
| |
| private static final String IMS_SET_IMS_SERVICE = "set-ims-service"; |
| private static final String IMS_GET_IMS_SERVICE = "get-ims-service"; |
| private static final String IMS_CLEAR_SERVICE_OVERRIDE = "clear-ims-service-override"; |
| // Used to disable or enable processing of conference event package data from the network. |
| // This is handy for testing scenarios where CEP data does not exist on a network which does |
| // support CEP data. |
| private static final String IMS_CEP = "conference-event-package"; |
| |
| private static final String NUMBER_VERIFICATION_OVERRIDE_PACKAGE = "override-package"; |
| private static final String NUMBER_VERIFICATION_FAKE_CALL = "fake-call"; |
| |
| private static final String CC_GET_VALUE = "get-value"; |
| private static final String CC_SET_VALUE = "set-value"; |
| private static final String CC_CLEAR_VALUES = "clear-values"; |
| |
| private static final String GBA_SUBCOMMAND = "gba"; |
| private static final String GBA_SET_SERVICE = "set-service"; |
| private static final String GBA_GET_SERVICE = "get-service"; |
| private static final String GBA_SET_RELEASE_TIME = "set-release"; |
| private static final String GBA_GET_RELEASE_TIME = "get-release"; |
| |
| private static final String SINGLE_REGISTATION_CONFIG = "src"; |
| private static final String SRC_SET_DEVICE_ENABLED = "set-device-enabled"; |
| private static final String SRC_GET_DEVICE_ENABLED = "get-device-enabled"; |
| private static final String SRC_SET_CARRIER_ENABLED = "set-carrier-enabled"; |
| private static final String SRC_GET_CARRIER_ENABLED = "get-carrier-enabled"; |
| private static final String SRC_SET_TEST_ENABLED = "set-test-enabled"; |
| private static final String SRC_GET_TEST_ENABLED = "get-test-enabled"; |
| private static final String SRC_SET_FEATURE_ENABLED = "set-feature-validation"; |
| private static final String SRC_GET_FEATURE_ENABLED = "get-feature-validation"; |
| |
| private static final String D2D_SUBCOMMAND = "d2d"; |
| private static final String D2D_SEND = "send"; |
| private static final String D2D_TRANSPORT = "transport"; |
| private static final String D2D_SET_DEVICE_SUPPORT = "set-device-support"; |
| |
| private static final String BARRING_SUBCOMMAND = "barring"; |
| private static final String BARRING_SEND_INFO = "send"; |
| |
| private static final String RCS_UCE_COMMAND = "uce"; |
| private static final String UCE_GET_EAB_CONTACT = "get-eab-contact"; |
| private static final String UCE_GET_EAB_CAPABILITY = "get-eab-capability"; |
| private static final String UCE_REMOVE_EAB_CONTACT = "remove-eab-contact"; |
| private static final String UCE_GET_DEVICE_ENABLED = "get-device-enabled"; |
| private static final String UCE_SET_DEVICE_ENABLED = "set-device-enabled"; |
| private static final String UCE_OVERRIDE_PUBLISH_CAPS = "override-published-caps"; |
| private static final String UCE_GET_LAST_PIDF_XML = "get-last-publish-pidf"; |
| private static final String UCE_REMOVE_REQUEST_DISALLOWED_STATUS = |
| "remove-request-disallowed-status"; |
| private static final String UCE_SET_CAPABILITY_REQUEST_TIMEOUT = |
| "set-capabilities-request-timeout"; |
| |
| // Check if a package has carrier privileges on any SIM, regardless of subId/phoneId. |
| private static final String HAS_CARRIER_PRIVILEGES_COMMAND = "has-carrier-privileges"; |
| |
| private static final String DISABLE_PHYSICAL_SUBSCRIPTION = "disable-physical-subscription"; |
| private static final String ENABLE_PHYSICAL_SUBSCRIPTION = "enable-physical-subscription"; |
| |
| private static final String THERMAL_MITIGATION_COMMAND = "thermal-mitigation"; |
| private static final String ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "allow-package"; |
| private static final String DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND = "disallow-package"; |
| |
| private static final String GET_ALLOWED_NETWORK_TYPES_FOR_USER = |
| "get-allowed-network-types-for-users"; |
| private static final String SET_ALLOWED_NETWORK_TYPES_FOR_USER = |
| "set-allowed-network-types-for-users"; |
| // Check if telephony new data stack is enabled. |
| private static final String GET_DATA_MODE = "get-data-mode"; |
| // Take advantage of existing methods that already contain permissions checks when possible. |
| private final ITelephony mInterface; |
| |
| private SubscriptionManager mSubscriptionManager; |
| private CarrierConfigManager mCarrierConfigManager; |
| private TelephonyRegistryManager mTelephonyRegistryManager; |
| private Context mContext; |
| |
| private enum CcType { |
| BOOLEAN, DOUBLE, DOUBLE_ARRAY, INT, INT_ARRAY, LONG, LONG_ARRAY, STRING, |
| STRING_ARRAY, UNKNOWN |
| } |
| |
| private class CcOptionParseResult { |
| public int mSubId; |
| public boolean mPersistent; |
| } |
| |
| // Maps carrier config keys to type. It is possible to infer the type for most carrier config |
| // keys by looking at the end of the string which usually tells the type. |
| // For instance: "xxxx_string", "xxxx_string_array", etc. |
| // The carrier config keys in this map does not follow this convention. It is therefore not |
| // possible to infer the type for these keys by looking at the string. |
| private static final Map<String, CcType> CC_TYPE_MAP = new HashMap<String, CcType>() {{ |
| put(CarrierConfigManager.Gps.KEY_A_GLONASS_POS_PROTOCOL_SELECT_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_GPS_LOCK_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_LPP_PROFILE_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_NFW_PROXY_APPS_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_SUPL_ES_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_SUPL_HOST_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_SUPL_MODE_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_SUPL_PORT_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_SUPL_VER_STRING, CcType.STRING); |
| put(CarrierConfigManager.Gps.KEY_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_STRING, |
| CcType.STRING); |
| put(CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, |
| CcType.STRING_ARRAY); |
| put(CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY, |
| CcType.STRING_ARRAY); |
| put(CarrierConfigManager.KEY_CARRIER_CALL_SCREENING_APP_STRING, CcType.STRING); |
| put(CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, CcType.STRING); |
| put(CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING, CcType.STRING); |
| put(CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING, CcType.STRING); |
| put(CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING, CcType.STRING); |
| put(CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING, CcType.STRING); |
| put(CarrierConfigManager.KEY_MMS_USER_AGENT_STRING, CcType.STRING); |
| put(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, CcType.STRING_ARRAY); |
| } |
| }; |
| |
| /** |
| * Map from a shorthand string to the feature tags required in registration required in order |
| * for the RCS feature to be considered "capable". |
| */ |
| private static final Map<String, Set<String>> TEST_FEATURE_TAG_MAP; |
| static { |
| ArrayMap<String, Set<String>> map = new ArrayMap<>(18); |
| map.put("chat_v1", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_IM)); |
| map.put("chat_v2", Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_SESSION)); |
| map.put("ft", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER)); |
| map.put("ft_sms", Collections.singleton(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS)); |
| map.put("mmtel", Collections.singleton(FeatureTags.FEATURE_TAG_MMTEL)); |
| map.put("mmtel_vt", new ArraySet<>(Arrays.asList(FeatureTags.FEATURE_TAG_MMTEL, |
| FeatureTags.FEATURE_TAG_VIDEO))); |
| map.put("geo_push", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH)); |
| map.put("geo_push_sms", Collections.singleton(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS)); |
| map.put("call_comp", |
| Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING)); |
| map.put("call_comp_mmtel", |
| Collections.singleton(FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY)); |
| map.put("call_post", Collections.singleton(FeatureTags.FEATURE_TAG_POST_CALL)); |
| map.put("map", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_MAP)); |
| map.put("sketch", Collections.singleton(FeatureTags.FEATURE_TAG_SHARED_SKETCH)); |
| // Feature tags defined twice for chatbot session because we want v1 and v2 based on bot |
| // version |
| map.put("chatbot", new ArraySet<>(Arrays.asList( |
| FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION, |
| FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED))); |
| map.put("chatbot_v2", new ArraySet<>(Arrays.asList( |
| FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION, |
| FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED))); |
| map.put("chatbot_sa", new ArraySet<>(Arrays.asList( |
| FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG, |
| FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED))); |
| map.put("chatbot_sa_v2", new ArraySet<>(Arrays.asList( |
| FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG, |
| FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED))); |
| map.put("chatbot_role", Collections.singleton(FeatureTags.FEATURE_TAG_CHATBOT_ROLE)); |
| TEST_FEATURE_TAG_MAP = Collections.unmodifiableMap(map); |
| } |
| |
| |
| public TelephonyShellCommand(ITelephony binder, Context context) { |
| mInterface = binder; |
| mCarrierConfigManager = |
| (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE); |
| mSubscriptionManager = (SubscriptionManager) |
| context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); |
| mTelephonyRegistryManager = (TelephonyRegistryManager) |
| context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); |
| mContext = context; |
| } |
| |
| @Override |
| public int onCommand(String cmd) { |
| if (cmd == null) { |
| return handleDefaultCommands(null); |
| } |
| |
| switch (cmd) { |
| case IMS_SUBCOMMAND: { |
| return handleImsCommand(); |
| } |
| case RCS_UCE_COMMAND: |
| return handleRcsUceCommand(); |
| case NUMBER_VERIFICATION_SUBCOMMAND: |
| return handleNumberVerificationCommand(); |
| case EMERGENCY_CALLBACK_MODE: |
| return handleEmergencyCallbackModeCommand(); |
| case EMERGENCY_NUMBER_TEST_MODE: |
| return handleEmergencyNumberTestModeCommand(); |
| case CARRIER_CONFIG_SUBCOMMAND: { |
| return handleCcCommand(); |
| } |
| case DATA_TEST_MODE: |
| return handleDataTestModeCommand(); |
| case END_BLOCK_SUPPRESSION: |
| return handleEndBlockSuppressionCommand(); |
| case GBA_SUBCOMMAND: |
| return handleGbaCommand(); |
| case D2D_SUBCOMMAND: |
| return handleD2dCommand(); |
| case BARRING_SUBCOMMAND: |
| return handleBarringCommand(); |
| case SINGLE_REGISTATION_CONFIG: |
| return handleSingleRegistrationConfigCommand(); |
| case RESTART_MODEM: |
| return handleRestartModemCommand(); |
| case CALL_COMPOSER_SUBCOMMAND: |
| return handleCallComposerCommand(); |
| case UNATTENDED_REBOOT: |
| return handleUnattendedReboot(); |
| case HAS_CARRIER_PRIVILEGES_COMMAND: |
| return handleHasCarrierPrivilegesCommand(); |
| case THERMAL_MITIGATION_COMMAND: |
| return handleThermalMitigationCommand(); |
| case DISABLE_PHYSICAL_SUBSCRIPTION: |
| return handleEnablePhysicalSubscription(false); |
| case ENABLE_PHYSICAL_SUBSCRIPTION: |
| return handleEnablePhysicalSubscription(true); |
| case GET_ALLOWED_NETWORK_TYPES_FOR_USER: |
| case SET_ALLOWED_NETWORK_TYPES_FOR_USER: |
| return handleAllowedNetworkTypesCommand(cmd); |
| case GET_DATA_MODE: |
| return handleGetDataMode(); |
| default: { |
| return handleDefaultCommands(cmd); |
| } |
| } |
| } |
| |
| @Override |
| public void onHelp() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Telephony Commands:"); |
| pw.println(" help"); |
| pw.println(" Print this help text."); |
| pw.println(" ims"); |
| pw.println(" IMS Commands."); |
| pw.println(" uce"); |
| pw.println(" RCS User Capability Exchange Commands."); |
| pw.println(" emergency-number-test-mode"); |
| pw.println(" Emergency Number Test Mode Commands."); |
| pw.println(" end-block-suppression"); |
| pw.println(" End Block Suppression command."); |
| pw.println(" data"); |
| pw.println(" Data Test Mode Commands."); |
| pw.println(" cc"); |
| pw.println(" Carrier Config Commands."); |
| pw.println(" gba"); |
| pw.println(" GBA Commands."); |
| pw.println(" src"); |
| pw.println(" RCS VoLTE Single Registration Config Commands."); |
| pw.println(" restart-modem"); |
| pw.println(" Restart modem command."); |
| pw.println(" unattended-reboot"); |
| pw.println(" Prepare for unattended reboot."); |
| pw.println(" has-carrier-privileges [package]"); |
| pw.println(" Query carrier privilege status for a package. Prints true or false."); |
| pw.println(" get-allowed-network-types-for-users"); |
| pw.println(" Get the Allowed Network Types."); |
| pw.println(" set-allowed-network-types-for-users"); |
| pw.println(" Set the Allowed Network Types."); |
| onHelpIms(); |
| onHelpUce(); |
| onHelpEmergencyNumber(); |
| onHelpEndBlockSupperssion(); |
| onHelpDataTestMode(); |
| onHelpCc(); |
| onHelpGba(); |
| onHelpSrc(); |
| onHelpD2D(); |
| onHelpDisableOrEnablePhysicalSubscription(); |
| onHelpAllowedNetworkTypes(); |
| } |
| |
| private void onHelpD2D() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("D2D Comms Commands:"); |
| pw.println(" d2d send TYPE VALUE"); |
| pw.println(" Sends a D2D message of specified type and value."); |
| pw.println(" Type: " + MESSAGE_CALL_RADIO_ACCESS_TYPE + " - " |
| + Communicator.messageToString(MESSAGE_CALL_RADIO_ACCESS_TYPE)); |
| pw.println(" Type: " + MESSAGE_CALL_AUDIO_CODEC + " - " + Communicator.messageToString( |
| MESSAGE_CALL_AUDIO_CODEC)); |
| pw.println(" Type: " + MESSAGE_DEVICE_BATTERY_STATE + " - " |
| + Communicator.messageToString( |
| MESSAGE_DEVICE_BATTERY_STATE)); |
| pw.println(" Type: " + MESSAGE_DEVICE_NETWORK_COVERAGE + " - " |
| + Communicator.messageToString(MESSAGE_DEVICE_NETWORK_COVERAGE)); |
| pw.println(" d2d transport TYPE"); |
| pw.println(" Forces the specified D2D transport TYPE to be active. Use the"); |
| pw.println(" short class name of the transport; i.e. DtmfTransport or RtpTransport."); |
| pw.println(" d2d set-device-support true/default"); |
| pw.println(" true - forces device support to be enabled for D2D."); |
| pw.println(" default - clear any previously set force-enable of D2D, reverting to "); |
| pw.println(" the current device's configuration."); |
| } |
| |
| private void onHelpBarring() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Barring Commands:"); |
| pw.println(" barring send -s SLOT_ID -b BARRING_TYPE -c IS_CONDITIONALLY_BARRED" |
| + " -t CONDITIONAL_BARRING_TIME_SECS"); |
| pw.println(" Notifies of a barring info change for the specified slot id."); |
| pw.println(" BARRING_TYPE: 0 for BARRING_TYPE_NONE"); |
| pw.println(" BARRING_TYPE: 1 for BARRING_TYPE_UNCONDITIONAL"); |
| pw.println(" BARRING_TYPE: 2 for BARRING_TYPE_CONDITIONAL"); |
| pw.println(" BARRING_TYPE: -1 for BARRING_TYPE_UNKNOWN"); |
| } |
| |
| private void onHelpIms() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("IMS Commands:"); |
| pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME"); |
| pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound"); |
| pw.println(" ImsService. Options are:"); |
| pw.println(" -s: the slot ID that the ImsService should be bound for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" -c: Override the ImsService defined in the carrier configuration."); |
| pw.println(" -d: Override the ImsService defined in the device overlay."); |
| pw.println(" -f: Set the feature that this override if for, if no option is"); |
| pw.println(" specified, the new package name will be used for all features."); |
| pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]"); |
| pw.println(" Gets the package name of the currently defined ImsService."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID for the registered ImsService. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" -c: The ImsService defined as the carrier configured ImsService."); |
| pw.println(" -d: The ImsService defined as the device default ImsService."); |
| pw.println(" -f: The feature type that the query will be requested for. If none is"); |
| pw.println(" specified, the returned package name will correspond to MMTEL."); |
| pw.println(" ims clear-ims-service-override [-s SLOT_ID]"); |
| pw.println(" Clear all carrier ImsService overrides. This does not work for device "); |
| pw.println(" configuration overrides. Options are:"); |
| pw.println(" -s: The SIM slot ID for the registered ImsService. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" ims enable [-s SLOT_ID]"); |
| pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot"); |
| pw.println(" if none is specified."); |
| pw.println(" ims disable [-s SLOT_ID]"); |
| pw.println(" disables IMS for the SIM slot specified, or for the default voice SIM"); |
| pw.println(" slot if none is specified."); |
| pw.println(" ims conference-event-package [enable/disable]"); |
| pw.println(" enables or disables handling or network conference event package data."); |
| } |
| |
| private void onHelpUce() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("User Capability Exchange Commands:"); |
| pw.println(" uce get-eab-contact [PHONE_NUMBER]"); |
| pw.println(" Get the EAB contacts from the EAB database."); |
| pw.println(" Options are:"); |
| pw.println(" PHONE_NUMBER: The phone numbers to be removed from the EAB databases"); |
| pw.println(" Expected output format :"); |
| pw.println(" [PHONE_NUMBER],[RAW_CONTACT_ID],[CONTACT_ID],[DATA_ID]"); |
| pw.println(" uce remove-eab-contact [-s SLOT_ID] [PHONE_NUMBER]"); |
| pw.println(" Remove the EAB contacts from the EAB database."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" PHONE_NUMBER: The phone numbers to be removed from the EAB databases"); |
| pw.println(" uce get-device-enabled"); |
| pw.println(" Get the config to check whether the device supports RCS UCE or not."); |
| pw.println(" uce set-device-enabled true|false"); |
| pw.println(" Set the device config for RCS User Capability Exchange to the value."); |
| pw.println(" The value could be true, false."); |
| pw.println(" uce override-published-caps [-s SLOT_ID] add|remove|clear [CAPABILITIES]"); |
| pw.println(" Override the existing SIP PUBLISH with different capabilities."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" add [CAPABILITY]: add a new capability"); |
| pw.println(" remove [CAPABILITY]: remove a capability"); |
| pw.println(" clear: clear all capability overrides"); |
| pw.println(" CAPABILITY: \":\" separated list of capabilities."); |
| pw.println(" Valid options are: [mmtel(_vt), chat_v1, chat_v2, ft, ft_sms,"); |
| pw.println(" geo_push, geo_push_sms, call_comp, call_post, map, sketch, chatbot,"); |
| pw.println(" chatbot_sa, chatbot_role] as well as full length"); |
| pw.println(" featureTag=\"featureValue\" feature tags that are not defined here."); |
| pw.println(" uce get-last-publish-pidf [-s SLOT_ID]"); |
| pw.println(" Get the PIDF XML included in the last SIP PUBLISH, or \"none\" if no "); |
| pw.println(" PUBLISH is active"); |
| pw.println(" uce remove-request-disallowed-status [-s SLOT_ID]"); |
| pw.println(" Remove the UCE is disallowed to execute UCE requests status"); |
| pw.println(" uce set-capabilities-request-timeout [-s SLOT_ID] [REQUEST_TIMEOUT_MS]"); |
| pw.println(" Set the timeout for contact capabilities request."); |
| } |
| |
| private void onHelpNumberVerification() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Number verification commands"); |
| pw.println(" numverify override-package PACKAGE_NAME;"); |
| pw.println(" Set the authorized package for number verification."); |
| pw.println(" Leave the package name blank to reset."); |
| pw.println(" numverify fake-call NUMBER;"); |
| pw.println(" Fake an incoming call from NUMBER. This is for testing. Output will be"); |
| pw.println(" 1 if the call would have been intercepted, 0 otherwise."); |
| } |
| |
| private void onHelpThermalMitigation() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Thermal mitigation commands"); |
| pw.println(" thermal-mitigation allow-package PACKAGE_NAME"); |
| pw.println(" Set the package as one of authorized packages for thermal mitigation."); |
| pw.println(" thermal-mitigation disallow-package PACKAGE_NAME"); |
| pw.println(" Remove the package from one of the authorized packages for thermal " |
| + "mitigation."); |
| } |
| |
| private void onHelpDisableOrEnablePhysicalSubscription() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Disable or enable a physical subscription"); |
| pw.println(" disable-physical-subscription SUB_ID"); |
| pw.println(" Disable the physical subscription with the provided subId, if allowed."); |
| pw.println(" enable-physical-subscription SUB_ID"); |
| pw.println(" Enable the physical subscription with the provided subId, if allowed."); |
| } |
| |
| private void onHelpDataTestMode() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Mobile Data Test Mode Commands:"); |
| pw.println(" data enable: enable mobile data connectivity"); |
| pw.println(" data disable: disable mobile data connectivity"); |
| } |
| |
| private void onHelpEmergencyNumber() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Emergency Number Test Mode Commands:"); |
| pw.println(" emergency-number-test-mode "); |
| pw.println(" Add(-a), Clear(-c), Print (-p) or Remove(-r) the emergency number list in" |
| + " the test mode"); |
| pw.println(" -a <emergency number address>: add an emergency number address for the" |
| + " test mode, only allows '0'-'9', '*', '#' or '+'."); |
| pw.println(" -c: clear the emergency number list in the test mode."); |
| pw.println(" -r <emergency number address>: remove an existing emergency number" |
| + " address added by the test mode, only allows '0'-'9', '*', '#' or '+'."); |
| pw.println(" -p: get the full emergency number list in the test mode."); |
| } |
| |
| private void onHelpEndBlockSupperssion() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("End Block Suppression command:"); |
| pw.println(" end-block-suppression: disable suppressing blocking by contact"); |
| pw.println(" with emergency services."); |
| } |
| |
| private void onHelpCc() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Carrier Config Commands:"); |
| pw.println(" cc get-value [-s SLOT_ID] [KEY]"); |
| pw.println(" Print carrier config values."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" KEY: The key to the carrier config value to print. All values are printed"); |
| pw.println(" if KEY is not specified."); |
| pw.println(" cc set-value [-s SLOT_ID] [-p] KEY [NEW_VALUE]"); |
| pw.println(" Set carrier config KEY to NEW_VALUE."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to set carrier config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" -p: Value will be stored persistent"); |
| pw.println(" NEW_VALUE specifies the new value for carrier config KEY. Null will be"); |
| pw.println(" used if NEW_VALUE is not set. Strings should be encapsulated with"); |
| pw.println(" quotation marks. Spaces needs to be escaped. Example: \"Hello\\ World\""); |
| pw.println(" Separate items in arrays with space . Example: \"item1\" \"item2\""); |
| pw.println(" cc clear-values [-s SLOT_ID]"); |
| pw.println(" Clear all carrier override values that has previously been set"); |
| pw.println(" with set-value"); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to clear carrier config values for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| } |
| |
| private void onHelpGba() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Gba Commands:"); |
| pw.println(" gba set-service [-s SLOT_ID] PACKAGE_NAME"); |
| pw.println(" Sets the GbaService defined in PACKAGE_NAME to to be the bound."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" gba get-service [-s SLOT_ID]"); |
| pw.println(" Gets the package name of the currently defined GbaService."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" gba set-release [-s SLOT_ID] n"); |
| pw.println(" Sets the time to release/unbind GbaService in n milli-second."); |
| pw.println(" Do not release/unbind if n is -1."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" gba get-release [-s SLOT_ID]"); |
| pw.println(" Gets the time to release/unbind GbaService in n milli-sencond."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read carrier config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| } |
| |
| private void onHelpSrc() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("RCS VoLTE Single Registration Config Commands:"); |
| pw.println(" src set-test-enabled true|false"); |
| pw.println(" Sets the test mode enabled for RCS VoLTE single registration."); |
| pw.println(" The value could be true, false, or null(undefined)."); |
| pw.println(" src get-test-enabled"); |
| pw.println(" Gets the test mode for RCS VoLTE single registration."); |
| pw.println(" src set-device-enabled true|false|null"); |
| pw.println(" Sets the device config for RCS VoLTE single registration to the value."); |
| pw.println(" The value could be true, false, or null(undefined)."); |
| pw.println(" src get-device-enabled"); |
| pw.println(" Gets the device config for RCS VoLTE single registration."); |
| pw.println(" src set-carrier-enabled [-s SLOT_ID] true|false|null"); |
| pw.println(" Sets the carrier config for RCS VoLTE single registration to the value."); |
| pw.println(" The value could be true, false, or null(undefined)."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to set the config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" src get-carrier-enabled [-s SLOT_ID]"); |
| pw.println(" Gets the carrier config for RCS VoLTE single registration."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read the config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" src set-feature-validation [-s SLOT_ID] true|false|null"); |
| pw.println(" Sets ims feature validation result."); |
| pw.println(" The value could be true, false, or null(undefined)."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to set the config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| pw.println(" src get-feature-validation [-s SLOT_ID]"); |
| pw.println(" Gets ims feature validation override value."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read the config value for. If no option"); |
| pw.println(" is specified, it will choose the default voice SIM slot."); |
| } |
| |
| private void onHelpAllowedNetworkTypes() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Allowed Network Types Commands:"); |
| pw.println(" get-allowed-network-types-for-users [-s SLOT_ID]"); |
| pw.println(" Print allowed network types value."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to read allowed network types value for. If no"); |
| pw.println(" option is specified, it will choose the default voice SIM slot."); |
| pw.println(" set-allowed-network-types-for-users [-s SLOT_ID] [NETWORK_TYPES_BITMASK]"); |
| pw.println(" Sets allowed network types to NETWORK_TYPES_BITMASK."); |
| pw.println(" Options are:"); |
| pw.println(" -s: The SIM slot ID to set allowed network types value for. If no"); |
| pw.println(" option is specified, it will choose the default voice SIM slot."); |
| pw.println(" NETWORK_TYPES_BITMASK specifies the new network types value and this type"); |
| pw.println(" is bitmask in binary format. Reference the NetworkTypeBitMask"); |
| pw.println(" at TelephonyManager.java"); |
| pw.println(" For example:"); |
| pw.println(" NR only : 10000000000000000000"); |
| pw.println(" NR|LTE : 11000001000000000000"); |
| pw.println(" NR|LTE|CDMA|EVDO|GSM|WCDMA : 11001111101111111111"); |
| pw.println(" LTE|CDMA|EVDO|GSM|WCDMA : 01001111101111111111"); |
| pw.println(" LTE only : 01000001000000000000"); |
| } |
| |
| private int handleImsCommand() { |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpIms(); |
| return 0; |
| } |
| |
| switch (arg) { |
| case IMS_SET_IMS_SERVICE: { |
| return handleImsSetServiceCommand(); |
| } |
| case IMS_GET_IMS_SERVICE: { |
| return handleImsGetServiceCommand(); |
| } |
| case IMS_CLEAR_SERVICE_OVERRIDE: { |
| return handleImsClearCarrierServiceCommand(); |
| } |
| case ENABLE: { |
| return handleEnableIms(); |
| } |
| case DISABLE: { |
| return handleDisableIms(); |
| } |
| case IMS_CEP: { |
| return handleCepChange(); |
| } |
| } |
| |
| return -1; |
| } |
| |
| private int handleDataTestModeCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| String arg = getNextArgRequired(); |
| if (arg == null) { |
| onHelpDataTestMode(); |
| return 0; |
| } |
| switch (arg) { |
| case ENABLE: { |
| try { |
| mInterface.enableDataConnectivity(); |
| } catch (RemoteException ex) { |
| Log.w(LOG_TAG, "data enable, error " + ex.getMessage()); |
| errPw.println("Exception: " + ex.getMessage()); |
| return -1; |
| } |
| break; |
| } |
| case DISABLE: { |
| try { |
| mInterface.disableDataConnectivity(); |
| } catch (RemoteException ex) { |
| Log.w(LOG_TAG, "data disable, error " + ex.getMessage()); |
| errPw.println("Exception: " + ex.getMessage()); |
| return -1; |
| } |
| break; |
| } |
| default: |
| onHelpDataTestMode(); |
| break; |
| } |
| return 0; |
| } |
| |
| private int handleEmergencyCallbackModeCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| try { |
| mInterface.startEmergencyCallbackMode(); |
| Log.d(LOG_TAG, "handleEmergencyCallbackModeCommand: triggered"); |
| } catch (RemoteException ex) { |
| Log.w(LOG_TAG, "emergency-callback-mode error: " + ex.getMessage()); |
| errPw.println("Exception: " + ex.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleEmergencyNumberTestModeCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| String opt = getNextOption(); |
| if (opt == null) { |
| onHelpEmergencyNumber(); |
| return 0; |
| } |
| |
| switch (opt) { |
| case "-a": { |
| String emergencyNumberCmd = getNextArgRequired(); |
| if (emergencyNumberCmd == null |
| || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) { |
| errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs" |
| + " to be specified after -a in the command "); |
| return -1; |
| } |
| try { |
| mInterface.updateEmergencyNumberListTestMode( |
| EmergencyNumberTracker.ADD_EMERGENCY_NUMBER_TEST_MODE, |
| new EmergencyNumber(emergencyNumberCmd, "", "", |
| EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, |
| new ArrayList<String>(), |
| EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST, |
| EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN)); |
| } catch (RemoteException ex) { |
| Log.w(LOG_TAG, "emergency-number-test-mode -a " + emergencyNumberCmd |
| + ", error " + ex.getMessage()); |
| errPw.println("Exception: " + ex.getMessage()); |
| return -1; |
| } |
| break; |
| } |
| case "-c": { |
| try { |
| mInterface.updateEmergencyNumberListTestMode( |
| EmergencyNumberTracker.RESET_EMERGENCY_NUMBER_TEST_MODE, null); |
| } catch (RemoteException ex) { |
| Log.w(LOG_TAG, "emergency-number-test-mode -c " + "error " + ex.getMessage()); |
| errPw.println("Exception: " + ex.getMessage()); |
| return -1; |
| } |
| break; |
| } |
| case "-r": { |
| String emergencyNumberCmd = getNextArgRequired(); |
| if (emergencyNumberCmd == null |
| || !EmergencyNumber.validateEmergencyNumberAddress(emergencyNumberCmd)) { |
| errPw.println("An emergency number (only allow '0'-'9', '*', '#' or '+') needs" |
| + " to be specified after -r in the command "); |
| return -1; |
| } |
| try { |
| mInterface.updateEmergencyNumberListTestMode( |
| EmergencyNumberTracker.REMOVE_EMERGENCY_NUMBER_TEST_MODE, |
| new EmergencyNumber(emergencyNumberCmd, "", "", |
| EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, |
| new ArrayList<String>(), |
| EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST, |
| EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN)); |
| } catch (RemoteException ex) { |
| Log.w(LOG_TAG, "emergency-number-test-mode -r " + emergencyNumberCmd |
| + ", error " + ex.getMessage()); |
| errPw.println("Exception: " + ex.getMessage()); |
| return -1; |
| } |
| break; |
| } |
| case "-p": { |
| try { |
| getOutPrintWriter().println(mInterface.getEmergencyNumberListTestMode()); |
| } catch (RemoteException ex) { |
| Log.w(LOG_TAG, "emergency-number-test-mode -p " + "error " + ex.getMessage()); |
| errPw.println("Exception: " + ex.getMessage()); |
| return -1; |
| } |
| break; |
| } |
| default: |
| onHelpEmergencyNumber(); |
| break; |
| } |
| return 0; |
| } |
| |
| private int handleNumberVerificationCommand() { |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpNumberVerification(); |
| return 0; |
| } |
| |
| if (!checkShellUid()) { |
| return -1; |
| } |
| |
| switch (arg) { |
| case NUMBER_VERIFICATION_OVERRIDE_PACKAGE: { |
| NumberVerificationManager.overrideAuthorizedPackage(getNextArg()); |
| return 0; |
| } |
| case NUMBER_VERIFICATION_FAKE_CALL: { |
| boolean val = NumberVerificationManager.getInstance() |
| .checkIncomingCall(getNextArg()); |
| getOutPrintWriter().println(val ? "1" : "0"); |
| return 0; |
| } |
| } |
| |
| return -1; |
| } |
| |
| private boolean subIsEsim(int subId) { |
| SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId); |
| if (info != null) { |
| return info.isEmbedded(); |
| } |
| return false; |
| } |
| |
| private int handleEnablePhysicalSubscription(boolean enable) { |
| PrintWriter errPw = getErrPrintWriter(); |
| int subId = 0; |
| try { |
| subId = Integer.parseInt(getNextArgRequired()); |
| } catch (NumberFormatException e) { |
| errPw.println((enable ? "enable" : "disable") |
| + "-physical-subscription requires an integer as a subId."); |
| return -1; |
| } |
| // Verify that the user is allowed to run the command. Only allowed in rooted device in a |
| // non user build. |
| if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { |
| errPw.println("cc: Permission denied."); |
| return -1; |
| } |
| // Verify that the subId represents a physical sub |
| if (subIsEsim(subId)) { |
| errPw.println("SubId " + subId + " is not for a physical subscription"); |
| return -1; |
| } |
| Log.d(LOG_TAG, (enable ? "Enabling" : "Disabling") |
| + " physical subscription with subId=" + subId); |
| mSubscriptionManager.setUiccApplicationsEnabled(subId, enable); |
| return 0; |
| } |
| |
| private int handleThermalMitigationCommand() { |
| String arg = getNextArg(); |
| String packageName = getNextArg(); |
| if (arg == null || packageName == null) { |
| onHelpThermalMitigation(); |
| return 0; |
| } |
| |
| if (!checkShellUid()) { |
| return -1; |
| } |
| |
| switch (arg) { |
| case ALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: { |
| PhoneInterfaceManager.addPackageToThermalMitigationAllowlist(packageName, mContext); |
| return 0; |
| } |
| case DISALLOW_THERMAL_MITIGATION_PACKAGE_SUBCOMMAND: { |
| PhoneInterfaceManager.removePackageFromThermalMitigationAllowlist(packageName, |
| mContext); |
| return 0; |
| } |
| default: |
| onHelpThermalMitigation(); |
| } |
| |
| return -1; |
| |
| } |
| |
| private int handleD2dCommand() { |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpD2D(); |
| return 0; |
| } |
| |
| switch (arg) { |
| case D2D_SEND: { |
| return handleD2dSendCommand(); |
| } |
| case D2D_TRANSPORT: { |
| return handleD2dTransportCommand(); |
| } |
| case D2D_SET_DEVICE_SUPPORT: { |
| return handleD2dDeviceSupportedCommand(); |
| } |
| } |
| |
| return -1; |
| } |
| |
| private int handleD2dSendCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| int messageType = -1; |
| int messageValue = -1; |
| |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpD2D(); |
| return 0; |
| } |
| try { |
| messageType = Integer.parseInt(arg); |
| } catch (NumberFormatException e) { |
| errPw.println("message type must be a valid integer"); |
| return -1; |
| } |
| |
| arg = getNextArg(); |
| if (arg == null) { |
| onHelpD2D(); |
| return 0; |
| } |
| try { |
| messageValue = Integer.parseInt(arg); |
| } catch (NumberFormatException e) { |
| errPw.println("message value must be a valid integer"); |
| return -1; |
| } |
| |
| try { |
| mInterface.sendDeviceToDeviceMessage(messageType, messageValue); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "d2d send error: " + e.getMessage()); |
| errPw.println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| private int handleD2dTransportCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpD2D(); |
| return 0; |
| } |
| |
| try { |
| mInterface.setActiveDeviceToDeviceTransport(arg); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "d2d transport error: " + e.getMessage()); |
| errPw.println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| private int handleBarringCommand() { |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpBarring(); |
| return 0; |
| } |
| |
| switch (arg) { |
| case BARRING_SEND_INFO: { |
| return handleBarringSendCommand(); |
| } |
| } |
| return -1; |
| } |
| |
| private int handleBarringSendCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| int slotId = getDefaultSlot(); |
| int subId = SubscriptionManager.getSubId(slotId)[0]; |
| @BarringInfo.BarringServiceInfo.BarringType int barringType = |
| BarringInfo.BarringServiceInfo.BARRING_TYPE_UNCONDITIONAL; |
| boolean isConditionallyBarred = false; |
| int conditionalBarringTimeSeconds = 0; |
| |
| String opt; |
| while ((opt = getNextOption()) != null) { |
| switch (opt) { |
| case "-s": { |
| try { |
| slotId = Integer.parseInt(getNextArgRequired()); |
| subId = SubscriptionManager.getSubId(slotId)[0]; |
| } catch (NumberFormatException e) { |
| errPw.println("barring send requires an integer as a SLOT_ID."); |
| return -1; |
| } |
| break; |
| } |
| case "-b": { |
| try { |
| barringType = Integer.parseInt(getNextArgRequired()); |
| if (barringType < -1 || barringType > 2) { |
| throw new NumberFormatException(); |
| } |
| |
| } catch (NumberFormatException e) { |
| errPw.println("barring send requires an integer in range [-1,2] as " |
| + "a BARRING_TYPE."); |
| return -1; |
| } |
| break; |
| } |
| case "-c": { |
| try { |
| isConditionallyBarred = Boolean.parseBoolean(getNextArgRequired()); |
| } catch (Exception e) { |
| errPw.println("barring send requires a boolean after -c indicating" |
| + " conditional barring"); |
| return -1; |
| } |
| break; |
| } |
| case "-t": { |
| try { |
| conditionalBarringTimeSeconds = Integer.parseInt(getNextArgRequired()); |
| } catch (NumberFormatException e) { |
| errPw.println("barring send requires an integer for time of barring" |
| + " in seconds after -t for conditional barring"); |
| return -1; |
| } |
| break; |
| } |
| } |
| } |
| SparseArray<BarringInfo.BarringServiceInfo> barringServiceInfos = new SparseArray<>(); |
| BarringInfo.BarringServiceInfo bsi = new BarringInfo.BarringServiceInfo( |
| barringType, isConditionallyBarred, 0, conditionalBarringTimeSeconds); |
| barringServiceInfos.append(0, bsi); |
| BarringInfo barringInfo = new BarringInfo(null, barringServiceInfos); |
| try { |
| mTelephonyRegistryManager.notifyBarringInfoChanged(slotId, subId, barringInfo); |
| } catch (Exception e) { |
| Log.w(LOG_TAG, "barring send error: " + e.getMessage()); |
| errPw.println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleD2dDeviceSupportedCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpD2D(); |
| return 0; |
| } |
| |
| boolean isEnabled = "true".equals(arg.toLowerCase()); |
| try { |
| mInterface.setDeviceToDeviceForceEnabled(isEnabled); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "Error forcing D2D enabled: " + e.getMessage()); |
| errPw.println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ims set-ims-service |
| private int handleImsSetServiceCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| int slotId = getDefaultSlot(); |
| Boolean isCarrierService = null; |
| List<Integer> featuresList = new ArrayList<>(); |
| |
| String opt; |
| while ((opt = getNextOption()) != null) { |
| switch (opt) { |
| case "-s": { |
| try { |
| slotId = Integer.parseInt(getNextArgRequired()); |
| } catch (NumberFormatException e) { |
| errPw.println("ims set-ims-service requires an integer as a SLOT_ID."); |
| return -1; |
| } |
| break; |
| } |
| case "-c": { |
| isCarrierService = true; |
| break; |
| } |
| case "-d": { |
| isCarrierService = false; |
| break; |
| } |
| case "-f": { |
| String featureString = getNextArgRequired(); |
| String[] features = featureString.split(","); |
| for (int i = 0; i < features.length; i++) { |
| try { |
| Integer result = Integer.parseInt(features[i]); |
| if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL |
| || result >= ImsFeature.FEATURE_MAX) { |
| errPw.println("ims set-ims-service -f " + result |
| + " is an invalid feature."); |
| return -1; |
| } |
| featuresList.add(result); |
| } catch (NumberFormatException e) { |
| errPw.println("ims set-ims-service -f tried to parse " + features[i] |
| + " as an integer."); |
| return -1; |
| } |
| } |
| } |
| } |
| } |
| // Mandatory param, either -c or -d |
| if (isCarrierService == null) { |
| errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set."); |
| return -1; |
| } |
| |
| String packageName = getNextArg(); |
| |
| try { |
| if (packageName == null) { |
| packageName = ""; |
| } |
| int[] featureArray = new int[featuresList.size()]; |
| for (int i = 0; i < featuresList.size(); i++) { |
| featureArray[i] = featuresList.get(i); |
| } |
| boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService, |
| featureArray, packageName); |
| if (VDBG) { |
| Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " " |
| + (isCarrierService ? "-c " : "-d ") |
| + "-f " + featuresList + " " |
| + packageName + ", result=" + result); |
| } |
| getOutPrintWriter().println(result); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " " |
| + (isCarrierService ? "-c " : "-d ") |
| + "-f " + featuresList + " " |
| + packageName + ", error" + e.getMessage()); |
| errPw.println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ims clear-ims-service-override |
| private int handleImsClearCarrierServiceCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| int slotId = getDefaultSlot(); |
| |
| String opt; |
| while ((opt = getNextOption()) != null) { |
| switch (opt) { |
| case "-s": { |
| try { |
| slotId = Integer.parseInt(getNextArgRequired()); |
| } catch (NumberFormatException e) { |
| errPw.println("ims set-ims-service requires an integer as a SLOT_ID."); |
| return -1; |
| } |
| break; |
| } |
| } |
| } |
| |
| try { |
| boolean result = mInterface.clearCarrierImsServiceOverride(slotId); |
| if (VDBG) { |
| Log.v(LOG_TAG, "ims clear-ims-service-override -s " + slotId |
| + ", result=" + result); |
| } |
| getOutPrintWriter().println(result); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "ims clear-ims-service-override -s " + slotId |
| + ", error" + e.getMessage()); |
| errPw.println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| // ims get-ims-service |
| private int handleImsGetServiceCommand() { |
| PrintWriter errPw = getErrPrintWriter(); |
| int slotId = getDefaultSlot(); |
| Boolean isCarrierService = null; |
| Integer featureType = ImsFeature.FEATURE_MMTEL; |
| |
| String opt; |
| while ((opt = getNextOption()) != null) { |
| switch (opt) { |
| case "-s": { |
| try { |
| slotId = Integer.parseInt(getNextArgRequired()); |
| } catch (NumberFormatException e) { |
| errPw.println("ims set-ims-service requires an integer as a SLOT_ID."); |
| return -1; |
| } |
| break; |
| } |
| case "-c": { |
| isCarrierService = true; |
| break; |
| } |
| case "-d": { |
| isCarrierService = false; |
| break; |
| } |
| case "-f": { |
| try { |
| featureType = Integer.parseInt(getNextArg()); |
| } catch (NumberFormatException e) { |
| errPw.println("ims get-ims-service -f requires valid integer as feature."); |
| return -1; |
| } |
| if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL |
| || featureType >= ImsFeature.FEATURE_MAX) { |
| errPw.println("ims get-ims-service -f invalid feature."); |
| return -1; |
| } |
| } |
| } |
| } |
| // Mandatory param, either -c or -d |
| if (isCarrierService == null) { |
| errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set."); |
| return -1; |
| } |
| |
| String result; |
| try { |
| result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " " |
| + (isCarrierService ? "-c " : "-d ") |
| + (featureType != null ? ("-f " + featureType) : "") + " , returned: " |
| + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleEnableIms() { |
| int slotId = getDefaultSlot(); |
| String opt; |
| while ((opt = getNextOption()) != null) { |
| switch (opt) { |
| case "-s": { |
| try { |
| slotId = Integer.parseInt(getNextArgRequired()); |
| } catch (NumberFormatException e) { |
| getErrPrintWriter().println("ims enable requires an integer as a SLOT_ID."); |
| return -1; |
| } |
| break; |
| } |
| } |
| } |
| try { |
| mInterface.enableIms(slotId); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "ims enable -s " + slotId); |
| } |
| return 0; |
| } |
| |
| private int handleDisableIms() { |
| int slotId = getDefaultSlot(); |
| String opt; |
| while ((opt = getNextOption()) != null) { |
| switch (opt) { |
| case "-s": { |
| try { |
| slotId = Integer.parseInt(getNextArgRequired()); |
| } catch (NumberFormatException e) { |
| getErrPrintWriter().println( |
| "ims disable requires an integer as a SLOT_ID."); |
| return -1; |
| } |
| break; |
| } |
| } |
| } |
| try { |
| mInterface.disableIms(slotId); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "ims disable -s " + slotId); |
| } |
| return 0; |
| } |
| |
| private int handleCepChange() { |
| Log.i(LOG_TAG, "handleCepChange"); |
| String opt = getNextArg(); |
| if (opt == null) { |
| return -1; |
| } |
| boolean isCepEnabled = opt.equals("enable"); |
| |
| try { |
| mInterface.setCepEnabled(isCepEnabled); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int getDefaultSlot() { |
| int slotId = SubscriptionManager.getDefaultVoicePhoneId(); |
| if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX |
| || slotId == SubscriptionManager.DEFAULT_PHONE_INDEX) { |
| // If there is no default, default to slot 0. |
| slotId = DEFAULT_PHONE_ID; |
| } |
| return slotId; |
| } |
| |
| // Parse options related to Carrier Config Commands. |
| private CcOptionParseResult parseCcOptions(String tag, boolean allowOptionPersistent) { |
| PrintWriter errPw = getErrPrintWriter(); |
| CcOptionParseResult result = new CcOptionParseResult(); |
| result.mSubId = SubscriptionManager.getDefaultSubscriptionId(); |
| result.mPersistent = false; |
| |
| String opt; |
| while ((opt = getNextOption()) != null) { |
| switch (opt) { |
| case "-s": { |
| try { |
| result.mSubId = slotStringToSubId(tag, getNextArgRequired()); |
| if (!SubscriptionManager.isValidSubscriptionId(result.mSubId)) { |
| errPw.println(tag + "No valid subscription found."); |
| return null; |
| } |
| |
| } catch (IllegalArgumentException e) { |
| // Missing slot id |
| errPw.println(tag + "SLOT_ID expected after -s."); |
| return null; |
| } |
| break; |
| } |
| case "-p": { |
| if (allowOptionPersistent) { |
| result.mPersistent = true; |
| } else { |
| errPw.println(tag + "Unexpected option " + opt); |
| return null; |
| } |
| break; |
| } |
| default: { |
| errPw.println(tag + "Unknown option " + opt); |
| return null; |
| } |
| } |
| } |
| return result; |
| } |
| |
| private int slotStringToSubId(String tag, String slotString) { |
| int slotId = -1; |
| try { |
| slotId = Integer.parseInt(slotString); |
| } catch (NumberFormatException e) { |
| getErrPrintWriter().println(tag + slotString + " is not a valid number for SLOT_ID."); |
| return SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| } |
| |
| if (!SubscriptionManager.isValidPhoneId(slotId)) { |
| getErrPrintWriter().println(tag + slotString + " is not a valid SLOT_ID."); |
| return SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| } |
| |
| Phone phone = PhoneFactory.getPhone(slotId); |
| if (phone == null) { |
| getErrPrintWriter().println(tag + "No subscription found in slot " + slotId + "."); |
| return SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| } |
| return phone.getSubId(); |
| } |
| |
| private boolean checkShellUid() { |
| // adb can run as root or as shell, depending on whether the device is rooted. |
| return Binder.getCallingUid() == Process.SHELL_UID |
| || Binder.getCallingUid() == Process.ROOT_UID; |
| } |
| |
| private int handleCcCommand() { |
| // Verify that the user is allowed to run the command. Only allowed in rooted device in a |
| // non user build. |
| if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { |
| getErrPrintWriter().println("cc: Permission denied."); |
| return -1; |
| } |
| |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpCc(); |
| return 0; |
| } |
| |
| switch (arg) { |
| case CC_GET_VALUE: { |
| return handleCcGetValue(); |
| } |
| case CC_SET_VALUE: { |
| return handleCcSetValue(); |
| } |
| case CC_CLEAR_VALUES: { |
| return handleCcClearValues(); |
| } |
| default: { |
| getErrPrintWriter().println("cc: Unknown argument: " + arg); |
| } |
| } |
| return -1; |
| } |
| |
| // cc get-value |
| private int handleCcGetValue() { |
| PrintWriter errPw = getErrPrintWriter(); |
| String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_GET_VALUE + ": "; |
| String key = null; |
| |
| // Parse all options |
| CcOptionParseResult options = parseCcOptions(tag, false); |
| if (options == null) { |
| return -1; |
| } |
| |
| // Get bundle containing all carrier configuration values. |
| PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(options.mSubId); |
| if (bundle == null) { |
| errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); |
| return -1; |
| } |
| |
| // Get the key. |
| key = getNextArg(); |
| if (key != null) { |
| // A key was provided. Verify if it is a valid key |
| if (!bundle.containsKey(key)) { |
| errPw.println(tag + key + " is not a valid key."); |
| return -1; |
| } |
| |
| // Print the carrier config value for key. |
| getOutPrintWriter().println(ccValueToString(key, getType(tag, key, bundle), bundle)); |
| } else { |
| // No key provided. Show all values. |
| // Iterate over a sorted list of all carrier config keys and print them. |
| TreeSet<String> sortedSet = new TreeSet<String>(bundle.keySet()); |
| for (String k : sortedSet) { |
| getOutPrintWriter().println(ccValueToString(k, getType(tag, k, bundle), bundle)); |
| } |
| } |
| return 0; |
| } |
| |
| // cc set-value |
| private int handleCcSetValue() { |
| PrintWriter errPw = getErrPrintWriter(); |
| String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_SET_VALUE + ": "; |
| |
| // Parse all options |
| CcOptionParseResult options = parseCcOptions(tag, true); |
| if (options == null) { |
| return -1; |
| } |
| |
| // Get bundle containing all current carrier configuration values. |
| PersistableBundle originalValues = mCarrierConfigManager.getConfigForSubId(options.mSubId); |
| if (originalValues == null) { |
| errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); |
| return -1; |
| } |
| |
| // Get the key. |
| String key = getNextArg(); |
| if (key == null || key.equals("")) { |
| errPw.println(tag + "KEY is missing"); |
| return -1; |
| } |
| |
| // Verify if the key is valid |
| if (!originalValues.containsKey(key)) { |
| errPw.println(tag + key + " is not a valid key."); |
| return -1; |
| } |
| |
| // Remaining arguments is a list of new values. Add them all into an ArrayList. |
| ArrayList<String> valueList = new ArrayList<String>(); |
| while (peekNextArg() != null) { |
| valueList.add(getNextArg()); |
| } |
| |
| // Find the type of the carrier config value |
| CcType type = getType(tag, key, originalValues); |
| if (type == CcType.UNKNOWN) { |
| errPw.println(tag + "ERROR: Not possible to override key with unknown type."); |
| return -1; |
| } |
| |
| // Create an override bundle containing the key and value that should be overriden. |
| PersistableBundle overrideBundle = getOverrideBundle(tag, type, key, valueList); |
| if (overrideBundle == null) { |
| return -1; |
| } |
| |
| // Override the value |
| mCarrierConfigManager.overrideConfig(options.mSubId, overrideBundle, options.mPersistent); |
| |
| // Find bundle containing all new carrier configuration values after the override. |
| PersistableBundle newValues = mCarrierConfigManager.getConfigForSubId(options.mSubId); |
| if (newValues == null) { |
| errPw.println(tag + "No carrier config values found for subId " + options.mSubId + "."); |
| return -1; |
| } |
| |
| // Print the original and new value. |
| String originalValueString = ccValueToString(key, type, originalValues); |
| String newValueString = ccValueToString(key, type, newValues); |
| getOutPrintWriter().println("Previous value: \n" + originalValueString); |
| getOutPrintWriter().println("New value: \n" + newValueString); |
| |
| return 0; |
| } |
| |
| // cc clear-values |
| private int handleCcClearValues() { |
| PrintWriter errPw = getErrPrintWriter(); |
| String tag = CARRIER_CONFIG_SUBCOMMAND + " " + CC_CLEAR_VALUES + ": "; |
| |
| // Parse all options |
| CcOptionParseResult options = parseCcOptions(tag, false); |
| if (options == null) { |
| return -1; |
| } |
| |
| // Clear all values that has previously been set. |
| mCarrierConfigManager.overrideConfig(options.mSubId, null, true); |
| getOutPrintWriter() |
| .println("All previously set carrier config override values has been cleared"); |
| return 0; |
| } |
| |
| private CcType getType(String tag, String key, PersistableBundle bundle) { |
| // Find the type by checking the type of the current value stored in the bundle. |
| Object value = bundle.get(key); |
| |
| if (CC_TYPE_MAP.containsKey(key)) { |
| return CC_TYPE_MAP.get(key); |
| } else if (value != null) { |
| if (value instanceof Boolean) { |
| return CcType.BOOLEAN; |
| } else if (value instanceof Double) { |
| return CcType.DOUBLE; |
| } else if (value instanceof double[]) { |
| return CcType.DOUBLE_ARRAY; |
| } else if (value instanceof Integer) { |
| return CcType.INT; |
| } else if (value instanceof int[]) { |
| return CcType.INT_ARRAY; |
| } else if (value instanceof Long) { |
| return CcType.LONG; |
| } else if (value instanceof long[]) { |
| return CcType.LONG_ARRAY; |
| } else if (value instanceof String) { |
| return CcType.STRING; |
| } else if (value instanceof String[]) { |
| return CcType.STRING_ARRAY; |
| } |
| } else { |
| // Current value was null and can therefore not be used in order to find the type. |
| // Check the name of the key to infer the type. This check is not needed for primitive |
| // data types (boolean, double, int and long), since they can not be null. |
| if (key.endsWith("double_array")) { |
| return CcType.DOUBLE_ARRAY; |
| } |
| if (key.endsWith("int_array")) { |
| return CcType.INT_ARRAY; |
| } |
| if (key.endsWith("long_array")) { |
| return CcType.LONG_ARRAY; |
| } |
| if (key.endsWith("string")) { |
| return CcType.STRING; |
| } |
| if (key.endsWith("string_array") || key.endsWith("strings")) { |
| return CcType.STRING_ARRAY; |
| } |
| } |
| |
| // Not possible to infer the type by looking at the current value or the key. |
| PrintWriter errPw = getErrPrintWriter(); |
| errPw.println(tag + "ERROR: " + key + " has unknown type."); |
| return CcType.UNKNOWN; |
| } |
| |
| private String ccValueToString(String key, CcType type, PersistableBundle bundle) { |
| String result; |
| StringBuilder valueString = new StringBuilder(); |
| String typeString = type.toString(); |
| Object value = bundle.get(key); |
| |
| if (value == null) { |
| valueString.append("null"); |
| } else { |
| switch (type) { |
| case DOUBLE_ARRAY: { |
| // Format the string representation of the int array as value1 value2...... |
| double[] valueArray = (double[]) value; |
| for (int i = 0; i < valueArray.length; i++) { |
| if (i != 0) { |
| valueString.append(" "); |
| } |
| valueString.append(valueArray[i]); |
| } |
| break; |
| } |
| case INT_ARRAY: { |
| // Format the string representation of the int array as value1 value2...... |
| int[] valueArray = (int[]) value; |
| for (int i = 0; i < valueArray.length; i++) { |
| if (i != 0) { |
| valueString.append(" "); |
| } |
| valueString.append(valueArray[i]); |
| } |
| break; |
| } |
| case LONG_ARRAY: { |
| // Format the string representation of the int array as value1 value2...... |
| long[] valueArray = (long[]) value; |
| for (int i = 0; i < valueArray.length; i++) { |
| if (i != 0) { |
| valueString.append(" "); |
| } |
| valueString.append(valueArray[i]); |
| } |
| break; |
| } |
| case STRING: { |
| valueString.append("\"" + value.toString() + "\""); |
| break; |
| } |
| case STRING_ARRAY: { |
| // Format the string representation of the string array as "value1" "value2".... |
| String[] valueArray = (String[]) value; |
| for (int i = 0; i < valueArray.length; i++) { |
| if (i != 0) { |
| valueString.append(" "); |
| } |
| if (valueArray[i] != null) { |
| valueString.append("\"" + valueArray[i] + "\""); |
| } else { |
| valueString.append("null"); |
| } |
| } |
| break; |
| } |
| default: { |
| valueString.append(value.toString()); |
| } |
| } |
| } |
| return String.format("%-70s %-15s %s", key, typeString, valueString); |
| } |
| |
| private PersistableBundle getOverrideBundle(String tag, CcType type, String key, |
| ArrayList<String> valueList) { |
| PrintWriter errPw = getErrPrintWriter(); |
| PersistableBundle bundle = new PersistableBundle(); |
| |
| // First verify that a valid number of values has been provided for the type. |
| switch (type) { |
| case BOOLEAN: |
| case DOUBLE: |
| case INT: |
| case LONG: { |
| if (valueList.size() != 1) { |
| errPw.println(tag + "Expected 1 value for type " + type |
| + ". Found: " + valueList.size()); |
| return null; |
| } |
| break; |
| } |
| case STRING: { |
| if (valueList.size() > 1) { |
| errPw.println(tag + "Expected 0 or 1 values for type " + type |
| + ". Found: " + valueList.size()); |
| return null; |
| } |
| break; |
| } |
| } |
| |
| // Parse the value according to type and add it to the Bundle. |
| switch (type) { |
| case BOOLEAN: { |
| if ("true".equalsIgnoreCase(valueList.get(0))) { |
| bundle.putBoolean(key, true); |
| } else if ("false".equalsIgnoreCase(valueList.get(0))) { |
| bundle.putBoolean(key, false); |
| } else { |
| errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); |
| return null; |
| } |
| break; |
| } |
| case DOUBLE: { |
| try { |
| bundle.putDouble(key, Double.parseDouble(valueList.get(0))); |
| } catch (NumberFormatException nfe) { |
| // Not a valid double |
| errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); |
| return null; |
| } |
| break; |
| } |
| case DOUBLE_ARRAY: { |
| double[] valueDoubleArray = null; |
| if (valueList.size() > 0) { |
| valueDoubleArray = new double[valueList.size()]; |
| for (int i = 0; i < valueList.size(); i++) { |
| try { |
| valueDoubleArray[i] = Double.parseDouble(valueList.get(i)); |
| } catch (NumberFormatException nfe) { |
| // Not a valid double |
| errPw.println( |
| tag + "Unable to parse " + valueList.get(i) + " as a double."); |
| return null; |
| } |
| } |
| } |
| bundle.putDoubleArray(key, valueDoubleArray); |
| break; |
| } |
| case INT: { |
| try { |
| bundle.putInt(key, Integer.parseInt(valueList.get(0))); |
| } catch (NumberFormatException nfe) { |
| // Not a valid integer |
| errPw.println(tag + "Unable to parse " + valueList.get(0) + " as an " + type); |
| return null; |
| } |
| break; |
| } |
| case INT_ARRAY: { |
| int[] valueIntArray = null; |
| if (valueList.size() > 0) { |
| valueIntArray = new int[valueList.size()]; |
| for (int i = 0; i < valueList.size(); i++) { |
| try { |
| valueIntArray[i] = Integer.parseInt(valueList.get(i)); |
| } catch (NumberFormatException nfe) { |
| // Not a valid integer |
| errPw.println(tag |
| + "Unable to parse " + valueList.get(i) + " as an integer."); |
| return null; |
| } |
| } |
| } |
| bundle.putIntArray(key, valueIntArray); |
| break; |
| } |
| case LONG: { |
| try { |
| bundle.putLong(key, Long.parseLong(valueList.get(0))); |
| } catch (NumberFormatException nfe) { |
| // Not a valid long |
| errPw.println(tag + "Unable to parse " + valueList.get(0) + " as a " + type); |
| return null; |
| } |
| break; |
| } |
| case LONG_ARRAY: { |
| long[] valueLongArray = null; |
| if (valueList.size() > 0) { |
| valueLongArray = new long[valueList.size()]; |
| for (int i = 0; i < valueList.size(); i++) { |
| try { |
| valueLongArray[i] = Long.parseLong(valueList.get(i)); |
| } catch (NumberFormatException nfe) { |
| // Not a valid long |
| errPw.println( |
| tag + "Unable to parse " + valueList.get(i) + " as a long"); |
| return null; |
| } |
| } |
| } |
| bundle.putLongArray(key, valueLongArray); |
| break; |
| } |
| case STRING: { |
| String value = null; |
| if (valueList.size() > 0) { |
| value = valueList.get(0); |
| } |
| bundle.putString(key, value); |
| break; |
| } |
| case STRING_ARRAY: { |
| String[] valueStringArray = null; |
| if (valueList.size() > 0) { |
| valueStringArray = new String[valueList.size()]; |
| valueList.toArray(valueStringArray); |
| } |
| bundle.putStringArray(key, valueStringArray); |
| break; |
| } |
| } |
| return bundle; |
| } |
| |
| private int handleEndBlockSuppressionCommand() { |
| if (!checkShellUid()) { |
| return -1; |
| } |
| |
| if (BlockedNumberContract.SystemContract.getBlockSuppressionStatus(mContext).isSuppressed) { |
| BlockedNumberContract.SystemContract.endBlockSuppression(mContext); |
| } |
| return 0; |
| } |
| |
| private int handleRestartModemCommand() { |
| // Verify that the user is allowed to run the command. Only allowed in rooted device in a |
| // non user build. |
| if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { |
| getErrPrintWriter().println("RestartModem: Permission denied."); |
| return -1; |
| } |
| |
| boolean result = TelephonyManager.getDefault().rebootRadio(); |
| getOutPrintWriter().println(result); |
| |
| return result ? 0 : -1; |
| } |
| |
| private int handleUnattendedReboot() { |
| // Verify that the user is allowed to run the command. Only allowed in rooted device in a |
| // non user build. |
| if (Binder.getCallingUid() != Process.ROOT_UID || TelephonyUtils.IS_USER) { |
| getErrPrintWriter().println("UnattendedReboot: Permission denied."); |
| return -1; |
| } |
| |
| int result = TelephonyManager.getDefault().prepareForUnattendedReboot(); |
| getOutPrintWriter().println("result: " + result); |
| |
| return result != TelephonyManager.PREPARE_UNATTENDED_REBOOT_ERROR ? 0 : -1; |
| } |
| |
| private int handleGbaCommand() { |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpGba(); |
| return 0; |
| } |
| |
| switch (arg) { |
| case GBA_SET_SERVICE: { |
| return handleGbaSetServiceCommand(); |
| } |
| case GBA_GET_SERVICE: { |
| return handleGbaGetServiceCommand(); |
| } |
| case GBA_SET_RELEASE_TIME: { |
| return handleGbaSetReleaseCommand(); |
| } |
| case GBA_GET_RELEASE_TIME: { |
| return handleGbaGetReleaseCommand(); |
| } |
| } |
| |
| return -1; |
| } |
| |
| private int getSubId(String cmd) { |
| int slotId = getDefaultSlot(); |
| String opt = getNextOption(); |
| if (opt != null && opt.equals("-s")) { |
| try { |
| slotId = Integer.parseInt(getNextArgRequired()); |
| } catch (NumberFormatException e) { |
| getErrPrintWriter().println(cmd + " requires an integer as a SLOT_ID."); |
| return SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| } |
| } |
| int[] subIds = SubscriptionManager.getSubId(slotId); |
| return subIds[0]; |
| } |
| |
| private int handleGbaSetServiceCommand() { |
| int subId = getSubId("gba set-service"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| String packageName = getNextArg(); |
| try { |
| if (packageName == null) { |
| packageName = ""; |
| } |
| boolean result = mInterface.setBoundGbaServiceOverride(subId, packageName); |
| if (VDBG) { |
| Log.v(LOG_TAG, "gba set-service -s " + subId + " " |
| + packageName + ", result=" + result); |
| } |
| getOutPrintWriter().println(result); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "gba set-service " + subId + " " |
| + packageName + ", error" + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleGbaGetServiceCommand() { |
| String result; |
| |
| int subId = getSubId("gba get-service"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| try { |
| result = mInterface.getBoundGbaService(subId); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "gba get-service -s " + subId + ", returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleGbaSetReleaseCommand() { |
| //the release time value could be -1 |
| int subId = getRemainingArgsCount() > 1 ? getSubId("gba set-release") |
| : SubscriptionManager.getDefaultSubscriptionId(); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| String intervalStr = getNextArg(); |
| if (intervalStr == null) { |
| return -1; |
| } |
| |
| try { |
| int interval = Integer.parseInt(intervalStr); |
| boolean result = mInterface.setGbaReleaseTimeOverride(subId, interval); |
| if (VDBG) { |
| Log.v(LOG_TAG, "gba set-release -s " + subId + " " |
| + intervalStr + ", result=" + result); |
| } |
| getOutPrintWriter().println(result); |
| } catch (NumberFormatException | RemoteException e) { |
| Log.w(LOG_TAG, "gba set-release -s " + subId + " " |
| + intervalStr + ", error" + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleGbaGetReleaseCommand() { |
| int subId = getSubId("gba get-release"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| int result = 0; |
| try { |
| result = mInterface.getGbaReleaseTime(subId); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "gba get-release -s " + subId + ", returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleSingleRegistrationConfigCommand() { |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpSrc(); |
| return 0; |
| } |
| |
| switch (arg) { |
| case SRC_SET_TEST_ENABLED: { |
| return handleSrcSetTestEnabledCommand(); |
| } |
| case SRC_GET_TEST_ENABLED: { |
| return handleSrcGetTestEnabledCommand(); |
| } |
| case SRC_SET_DEVICE_ENABLED: { |
| return handleSrcSetDeviceEnabledCommand(); |
| } |
| case SRC_GET_DEVICE_ENABLED: { |
| return handleSrcGetDeviceEnabledCommand(); |
| } |
| case SRC_SET_CARRIER_ENABLED: { |
| return handleSrcSetCarrierEnabledCommand(); |
| } |
| case SRC_GET_CARRIER_ENABLED: { |
| return handleSrcGetCarrierEnabledCommand(); |
| } |
| case SRC_SET_FEATURE_ENABLED: { |
| return handleSrcSetFeatureValidationCommand(); |
| } |
| case SRC_GET_FEATURE_ENABLED: { |
| return handleSrcGetFeatureValidationCommand(); |
| } |
| } |
| |
| return -1; |
| } |
| |
| private int handleRcsUceCommand() { |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpUce(); |
| return 0; |
| } |
| |
| switch (arg) { |
| case UCE_REMOVE_EAB_CONTACT: |
| return handleRemovingEabContactCommand(); |
| case UCE_GET_EAB_CONTACT: |
| return handleGettingEabContactCommand(); |
| case UCE_GET_EAB_CAPABILITY: |
| return handleGettingEabCapabilityCommand(); |
| case UCE_GET_DEVICE_ENABLED: |
| return handleUceGetDeviceEnabledCommand(); |
| case UCE_SET_DEVICE_ENABLED: |
| return handleUceSetDeviceEnabledCommand(); |
| case UCE_OVERRIDE_PUBLISH_CAPS: |
| return handleUceOverridePublishCaps(); |
| case UCE_GET_LAST_PIDF_XML: |
| return handleUceGetPidfXml(); |
| case UCE_REMOVE_REQUEST_DISALLOWED_STATUS: |
| return handleUceRemoveRequestDisallowedStatus(); |
| case UCE_SET_CAPABILITY_REQUEST_TIMEOUT: |
| return handleUceSetCapRequestTimeout(); |
| } |
| return -1; |
| } |
| |
| private int handleRemovingEabContactCommand() { |
| int subId = getSubId("uce remove-eab-contact"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| String phoneNumber = getNextArgRequired(); |
| if (TextUtils.isEmpty(phoneNumber)) { |
| return -1; |
| } |
| int result = 0; |
| try { |
| result = mInterface.removeContactFromEab(subId, phoneNumber); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "uce remove-eab-contact -s " + subId + ", error " + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| |
| if (VDBG) { |
| Log.v(LOG_TAG, "uce remove-eab-contact -s " + subId + ", result: " + result); |
| } |
| return 0; |
| } |
| |
| private int handleGettingEabContactCommand() { |
| String phoneNumber = getNextArgRequired(); |
| if (TextUtils.isEmpty(phoneNumber)) { |
| return -1; |
| } |
| String result = ""; |
| try { |
| result = mInterface.getContactFromEab(phoneNumber); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "uce get-eab-contact, error " + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| |
| if (VDBG) { |
| Log.v(LOG_TAG, "uce get-eab-contact, result: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleGettingEabCapabilityCommand() { |
| String phoneNumber = getNextArgRequired(); |
| if (TextUtils.isEmpty(phoneNumber)) { |
| return -1; |
| } |
| String result = ""; |
| try { |
| result = mInterface.getCapabilityFromEab(phoneNumber); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "uce get-eab-capability, error " + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| |
| if (VDBG) { |
| Log.v(LOG_TAG, "uce get-eab-capability, result: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleUceGetDeviceEnabledCommand() { |
| boolean result = false; |
| try { |
| result = mInterface.getDeviceUceEnabled(); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "uce get-device-enabled, error " + e.getMessage()); |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "uce get-device-enabled, returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleUceSetDeviceEnabledCommand() { |
| String enabledStr = getNextArg(); |
| if (TextUtils.isEmpty(enabledStr)) { |
| return -1; |
| } |
| |
| try { |
| boolean isEnabled = Boolean.parseBoolean(enabledStr); |
| mInterface.setDeviceUceEnabled(isEnabled); |
| if (VDBG) { |
| Log.v(LOG_TAG, "uce set-device-enabled " + enabledStr + ", done"); |
| } |
| } catch (NumberFormatException | RemoteException e) { |
| Log.w(LOG_TAG, "uce set-device-enabled " + enabledStr + ", error " + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleUceRemoveRequestDisallowedStatus() { |
| int subId = getSubId("uce remove-request-disallowed-status"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| Log.w(LOG_TAG, "uce remove-request-disallowed-status, Invalid subscription ID"); |
| return -1; |
| } |
| boolean result; |
| try { |
| result = mInterface.removeUceRequestDisallowedStatus(subId); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "uce remove-request-disallowed-status, error " + e.getMessage()); |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "uce remove-request-disallowed-status, returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleUceSetCapRequestTimeout() { |
| int subId = getSubId("uce set-capabilities-request-timeout"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| Log.w(LOG_TAG, "uce set-capabilities-request-timeout, Invalid subscription ID"); |
| return -1; |
| } |
| long timeoutAfterMs = Long.valueOf(getNextArg()); |
| boolean result; |
| try { |
| result = mInterface.setCapabilitiesRequestTimeout(subId, timeoutAfterMs); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "uce set-capabilities-request-timeout, error " + e.getMessage()); |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "uce set-capabilities-request-timeout, returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleSrcSetTestEnabledCommand() { |
| String enabledStr = getNextArg(); |
| if (enabledStr == null) { |
| return -1; |
| } |
| |
| try { |
| mInterface.setRcsSingleRegistrationTestModeEnabled(Boolean.parseBoolean(enabledStr)); |
| if (VDBG) { |
| Log.v(LOG_TAG, "src set-test-enabled " + enabledStr + ", done"); |
| } |
| getOutPrintWriter().println("Done"); |
| } catch (NumberFormatException | RemoteException e) { |
| Log.w(LOG_TAG, "src set-test-enabled " + enabledStr + ", error" + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleSrcGetTestEnabledCommand() { |
| boolean result = false; |
| try { |
| result = mInterface.getRcsSingleRegistrationTestModeEnabled(); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "src get-test-enabled, returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleUceOverridePublishCaps() { |
| int subId = getSubId("uce override-published-caps"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| //uce override-published-caps [-s SLOT_ID] add|remove|clear|list [CAPABILITIES] |
| String operation = getNextArgRequired(); |
| String caps = getNextArg(); |
| if (!"add".equals(operation) && !"remove".equals(operation) && !"clear".equals(operation) |
| && !"list".equals(operation)) { |
| getErrPrintWriter().println("Invalid operation: " + operation); |
| return -1; |
| } |
| |
| // add/remove requires capabilities to be specified. |
| if ((!"clear".equals(operation) && !"list".equals(operation)) && TextUtils.isEmpty(caps)) { |
| getErrPrintWriter().println("\"" + operation + "\" requires capabilities to be " |
| + "specified"); |
| return -1; |
| } |
| |
| ArraySet<String> capSet = new ArraySet<>(); |
| if (!TextUtils.isEmpty(caps)) { |
| String[] capArray = caps.split(":"); |
| for (String cap : capArray) { |
| // Allow unknown tags to be passed in as well. |
| capSet.addAll(TEST_FEATURE_TAG_MAP.getOrDefault(cap, Collections.singleton(cap))); |
| } |
| } |
| |
| RcsContactUceCapability result = null; |
| try { |
| switch (operation) { |
| case "add": |
| result = mInterface.addUceRegistrationOverrideShell(subId, |
| new ArrayList<>(capSet)); |
| break; |
| case "remove": |
| result = mInterface.removeUceRegistrationOverrideShell(subId, |
| new ArrayList<>(capSet)); |
| break; |
| case "clear": |
| result = mInterface.clearUceRegistrationOverrideShell(subId); |
| break; |
| case "list": |
| result = mInterface.getLatestRcsContactUceCapabilityShell(subId); |
| break; |
| } |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "uce override-published-caps, error " + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } catch (ServiceSpecificException sse) { |
| // Reconstruct ImsException |
| ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode); |
| Log.w(LOG_TAG, "uce override-published-caps, error " + imsException); |
| getErrPrintWriter().println("Exception: " + imsException); |
| return -1; |
| } |
| if (result == null) { |
| getErrPrintWriter().println("Service not available"); |
| return -1; |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleUceGetPidfXml() { |
| int subId = getSubId("uce get-last-publish-pidf"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| String result; |
| try { |
| result = mInterface.getLastUcePidfXmlShell(subId); |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, "uce get-last-publish-pidf, error " + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } catch (ServiceSpecificException sse) { |
| // Reconstruct ImsException |
| ImsException imsException = new ImsException(sse.getMessage(), sse.errorCode); |
| Log.w(LOG_TAG, "uce get-last-publish-pidf error " + imsException); |
| getErrPrintWriter().println("Exception: " + imsException); |
| return -1; |
| } |
| if (result == null) { |
| getErrPrintWriter().println("Service not available"); |
| return -1; |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleSrcSetDeviceEnabledCommand() { |
| String enabledStr = getNextArg(); |
| if (enabledStr == null) { |
| return -1; |
| } |
| |
| try { |
| mInterface.setDeviceSingleRegistrationEnabledOverride(enabledStr); |
| if (VDBG) { |
| Log.v(LOG_TAG, "src set-device-enabled " + enabledStr + ", done"); |
| } |
| getOutPrintWriter().println("Done"); |
| } catch (NumberFormatException | RemoteException e) { |
| Log.w(LOG_TAG, "src set-device-enabled " + enabledStr + ", error" + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleSrcGetDeviceEnabledCommand() { |
| boolean result = false; |
| try { |
| result = mInterface.getDeviceSingleRegistrationEnabled(); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "src get-device-enabled, returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleSrcSetCarrierEnabledCommand() { |
| //the release time value could be -1 |
| int subId = getRemainingArgsCount() > 1 ? getSubId("src set-carrier-enabled") |
| : SubscriptionManager.getDefaultSubscriptionId(); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| String enabledStr = getNextArg(); |
| if (enabledStr == null) { |
| return -1; |
| } |
| |
| try { |
| boolean result = |
| mInterface.setCarrierSingleRegistrationEnabledOverride(subId, enabledStr); |
| if (VDBG) { |
| Log.v(LOG_TAG, "src set-carrier-enabled -s " + subId + " " |
| + enabledStr + ", result=" + result); |
| } |
| getOutPrintWriter().println(result); |
| } catch (NumberFormatException | RemoteException e) { |
| Log.w(LOG_TAG, "src set-carrier-enabled -s " + subId + " " |
| + enabledStr + ", error" + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleSrcGetCarrierEnabledCommand() { |
| int subId = getSubId("src get-carrier-enabled"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| boolean result = false; |
| try { |
| result = mInterface.getCarrierSingleRegistrationEnabled(subId); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "src get-carrier-enabled -s " + subId + ", returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| private int handleSrcSetFeatureValidationCommand() { |
| //the release time value could be -1 |
| int subId = getRemainingArgsCount() > 1 ? getSubId("src set-feature-validation") |
| : SubscriptionManager.getDefaultSubscriptionId(); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| String enabledStr = getNextArg(); |
| if (enabledStr == null) { |
| return -1; |
| } |
| |
| try { |
| boolean result = |
| mInterface.setImsFeatureValidationOverride(subId, enabledStr); |
| if (VDBG) { |
| Log.v(LOG_TAG, "src set-feature-validation -s " + subId + " " |
| + enabledStr + ", result=" + result); |
| } |
| getOutPrintWriter().println(result); |
| } catch (NumberFormatException | RemoteException e) { |
| Log.w(LOG_TAG, "src set-feature-validation -s " + subId + " " |
| + enabledStr + ", error" + e.getMessage()); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } |
| return 0; |
| } |
| |
| private int handleSrcGetFeatureValidationCommand() { |
| int subId = getSubId("src get-feature-validation"); |
| if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| return -1; |
| } |
| |
| Boolean result = false; |
| try { |
| result = mInterface.getImsFeatureValidationOverride(subId); |
| } catch (RemoteException e) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "src get-feature-validation -s " + subId + ", returned: " + result); |
| } |
| getOutPrintWriter().println(result); |
| return 0; |
| } |
| |
| |
| private void onHelpCallComposer() { |
| PrintWriter pw = getOutPrintWriter(); |
| pw.println("Call composer commands"); |
| pw.println(" callcomposer test-mode enable|disable|query"); |
| pw.println(" Enables or disables test mode for call composer. In test mode, picture"); |
| pw.println(" upload/download from carrier servers is disabled, and operations are"); |
| pw.println(" performed using emulated local files instead."); |
| pw.println(" callcomposer simulate-outgoing-call [subId] [UUID]"); |
| pw.println(" Simulates an outgoing call being placed with the picture ID as"); |
| pw.println(" the provided UUID. This triggers storage to the call log."); |
| pw.println(" callcomposer user-setting [subId] enable|disable|query"); |
| pw.println(" Enables or disables the user setting for call composer, as set by"); |
| pw.println(" TelephonyManager#setCallComposerStatus."); |
| } |
| |
| private int handleCallComposerCommand() { |
| String arg = getNextArg(); |
| if (arg == null) { |
| onHelpCallComposer(); |
| return 0; |
| } |
| |
| mContext.enforceCallingPermission(Manifest.permission.MODIFY_PHONE_STATE, |
| "MODIFY_PHONE_STATE required for call composer shell cmds"); |
| switch (arg) { |
| case CALL_COMPOSER_TEST_MODE: { |
| String enabledStr = getNextArg(); |
| if (ENABLE.equals(enabledStr)) { |
| CallComposerPictureManager.sTestMode = true; |
| } else if (DISABLE.equals(enabledStr)) { |
| CallComposerPictureManager.sTestMode = false; |
| } else if (QUERY.equals(enabledStr)) { |
| getOutPrintWriter().println(CallComposerPictureManager.sTestMode); |
| } else { |
| onHelpCallComposer(); |
| return 1; |
| } |
| break; |
| } |
| case CALL_COMPOSER_SIMULATE_CALL: { |
| int subscriptionId = Integer.valueOf(getNextArg()); |
| String uuidString = getNextArg(); |
| UUID uuid = UUID.fromString(uuidString); |
| CompletableFuture<Uri> storageUriFuture = new CompletableFuture<>(); |
| Binder.withCleanCallingIdentity(() -> { |
| CallComposerPictureManager.getInstance(mContext, subscriptionId) |
| .storeUploadedPictureToCallLog(uuid, storageUriFuture::complete); |
| }); |
| try { |
| Uri uri = storageUriFuture.get(); |
| getOutPrintWriter().println(String.valueOf(uri)); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| break; |
| } |
| case CALL_COMPOSER_USER_SETTING: { |
| try { |
| int subscriptionId = Integer.valueOf(getNextArg()); |
| String enabledStr = getNextArg(); |
| if (ENABLE.equals(enabledStr)) { |
| mInterface.setCallComposerStatus(subscriptionId, |
| TelephonyManager.CALL_COMPOSER_STATUS_ON); |
| } else if (DISABLE.equals(enabledStr)) { |
| mInterface.setCallComposerStatus(subscriptionId, |
| TelephonyManager.CALL_COMPOSER_STATUS_OFF); |
| } else if (QUERY.equals(enabledStr)) { |
| getOutPrintWriter().println(mInterface.getCallComposerStatus(subscriptionId) |
| == TelephonyManager.CALL_COMPOSER_STATUS_ON); |
| } else { |
| onHelpCallComposer(); |
| return 1; |
| } |
| } catch (RemoteException e) { |
| e.printStackTrace(getOutPrintWriter()); |
| return 1; |
| } |
| break; |
| } |
| } |
| return 0; |
| } |
| |
| private int handleHasCarrierPrivilegesCommand() { |
| String packageName = getNextArgRequired(); |
| |
| boolean hasCarrierPrivileges; |
| final long token = Binder.clearCallingIdentity(); |
| try { |
| hasCarrierPrivileges = |
| mInterface.checkCarrierPrivilegesForPackageAnyPhone(packageName) |
| == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; |
| } catch (RemoteException e) { |
| Log.w(LOG_TAG, HAS_CARRIER_PRIVILEGES_COMMAND + " exception", e); |
| getErrPrintWriter().println("Exception: " + e.getMessage()); |
| return -1; |
| } finally { |
| Binder.restoreCallingIdentity(token); |
| } |
| |
| getOutPrintWriter().println(hasCarrierPrivileges); |
| return 0; |
| } |
| |
| private int handleAllowedNetworkTypesCommand(String command) { |
| if (!checkShellUid()) { |
| return -1; |
| } |
| |
| PrintWriter errPw = getErrPrintWriter(); |
| String tag = command + ": "; |
| String opt; |
| int subId = -1; |
| Log.v(LOG_TAG, command + " start"); |
| |
| while ((opt = getNextOption()) != null) { |
| if (opt.equals("-s")) { |
| try { |
| subId = slotStringToSubId(tag, getNextArgRequired()); |
| if (!SubscriptionManager.isValidSubscriptionId(subId)) { |
| errPw.println(tag + "No valid subscription found."); |
| return -1; |
| } |
| } catch (IllegalArgumentException e) { |
| // Missing slot id |
| errPw.println(tag + "SLOT_ID expected after -s."); |
| return -1; |
| } |
| } else { |
| errPw.println(tag + "Unknown option " + opt); |
| return -1; |
| } |
| } |
| |
| if (GET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) { |
| return handleGetAllowedNetworkTypesCommand(subId); |
| } |
| if (SET_ALLOWED_NETWORK_TYPES_FOR_USER.equals(command)) { |
| return handleSetAllowedNetworkTypesCommand(subId); |
| } |
| return -1; |
| } |
| |
| private int handleGetAllowedNetworkTypesCommand(int subId) { |
| PrintWriter errPw = getErrPrintWriter(); |
| |
| long result = -1; |
| try { |
| if (mInterface != null) { |
| result = mInterface.getAllowedNetworkTypesForReason(subId, |
| TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER); |
| } else { |
| throw new IllegalStateException("telephony service is null."); |
| } |
| } catch (RemoteException e) { |
| Log.e(TAG, "getAllowedNetworkTypesForReason RemoteException" + e); |
| errPw.println(GET_ALLOWED_NETWORK_TYPES_FOR_USER + "RemoteException " + e); |
| return -1; |
| } |
| |
| getOutPrintWriter().println(TelephonyManager.convertNetworkTypeBitmaskToString(result)); |
| return 0; |
| } |
| |
| private int handleSetAllowedNetworkTypesCommand(int subId) { |
| PrintWriter errPw = getErrPrintWriter(); |
| |
| String bitmaskString = getNextArg(); |
| if (TextUtils.isEmpty(bitmaskString)) { |
| errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No NETWORK_TYPES_BITMASK"); |
| return -1; |
| } |
| long allowedNetworkTypes = convertNetworkTypeBitmaskFromStringToLong(bitmaskString); |
| if (allowedNetworkTypes < 0) { |
| errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " No valid NETWORK_TYPES_BITMASK"); |
| return -1; |
| } |
| boolean result = false; |
| try { |
| if (mInterface != null) { |
| result = mInterface.setAllowedNetworkTypesForReason(subId, |
| TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, allowedNetworkTypes); |
| } else { |
| throw new IllegalStateException("telephony service is null."); |
| } |
| } catch (RemoteException e) { |
| Log.e(TAG, "setAllowedNetworkTypesForReason RemoteException" + e); |
| errPw.println(SET_ALLOWED_NETWORK_TYPES_FOR_USER + " RemoteException " + e); |
| return -1; |
| } |
| |
| String resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " failed"; |
| if (result) { |
| resultMessage = SET_ALLOWED_NETWORK_TYPES_FOR_USER + " completed"; |
| } |
| getOutPrintWriter().println(resultMessage); |
| return 0; |
| } |
| |
| private long convertNetworkTypeBitmaskFromStringToLong(String bitmaskString) { |
| if (TextUtils.isEmpty(bitmaskString)) { |
| return -1; |
| } |
| if (VDBG) { |
| Log.v(LOG_TAG, "AllowedNetworkTypes:" + bitmaskString |
| + ", length: " + bitmaskString.length()); |
| } |
| try { |
| return Long.parseLong(bitmaskString, 2); |
| } catch (NumberFormatException e) { |
| Log.e(LOG_TAG, "AllowedNetworkTypes: " + e); |
| return -1; |
| } |
| } |
| |
| private int handleGetDataMode() { |
| if (!checkShellUid()) { |
| return -1; |
| } |
| |
| boolean newDataStackEnabled = false; |
| try { |
| newDataStackEnabled = mInterface.isUsingNewDataStack(); |
| } catch (RemoteException e) { |
| getOutPrintWriter().println("Something went wrong. " + e); |
| return -1; |
| } |
| |
| getOutPrintWriter().println("Telephony new data stack is " |
| + (newDataStackEnabled ? "enabled." : "disabled.")); |
| |
| boolean configEnabled = Boolean.parseBoolean(DeviceConfig.getProperty( |
| DeviceConfig.NAMESPACE_TELEPHONY, "new_telephony_data_enabled")); |
| if (configEnabled != newDataStackEnabled) { |
| getOutPrintWriter().println("The config has been " |
| + (configEnabled ? "enabled" : "disabled") + ". Need to reboot the device."); |
| } else { |
| getOutPrintWriter().println("Run the following command to " |
| + (configEnabled ? "disable" : "enable") + " the new telephony data stack."); |
| getOutPrintWriter().println("adb root && adb shell device_config put telephony " |
| + "new_telephony_data_enabled " + (configEnabled ? "false" : "true") |
| + " && adb reboot"); |
| } |
| return 0; |
| } |
| } |