| /* | 
 |  * Copyright (C) 2008 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 android.telephony; | 
 |  | 
 | import android.Manifest; | 
 | import android.annotation.CallbackExecutor; | 
 | import android.annotation.IntDef; | 
 | import android.annotation.IntRange; | 
 | import android.annotation.NonNull; | 
 | import android.annotation.Nullable; | 
 | import android.annotation.RequiresFeature; | 
 | import android.annotation.RequiresPermission; | 
 | import android.annotation.SuppressAutoDoc; | 
 | import android.annotation.SystemApi; | 
 | import android.annotation.TestApi; | 
 | import android.app.PendingIntent; | 
 | import android.compat.Compatibility; | 
 | import android.compat.annotation.ChangeId; | 
 | import android.compat.annotation.EnabledAfter; | 
 | import android.compat.annotation.UnsupportedAppUsage; | 
 | import android.content.Context; | 
 | import android.content.pm.PackageManager; | 
 | import android.database.CursorWindow; | 
 | import android.net.Uri; | 
 | import android.os.Build; | 
 | import android.os.Bundle; | 
 | import android.os.RemoteException; | 
 | import android.text.TextUtils; | 
 | import android.util.ArrayMap; | 
 | import android.util.Log; | 
 | import android.util.Pair; | 
 |  | 
 | import com.android.internal.annotations.GuardedBy; | 
 | import com.android.internal.telephony.IIntegerConsumer; | 
 | import com.android.internal.telephony.IPhoneSubInfo; | 
 | import com.android.internal.telephony.ISms; | 
 | import com.android.internal.telephony.ITelephony; | 
 | import com.android.internal.telephony.SmsRawData; | 
 | import com.android.telephony.Rlog; | 
 |  | 
 | import java.lang.annotation.Retention; | 
 | import java.lang.annotation.RetentionPolicy; | 
 | import java.util.ArrayList; | 
 | import java.util.List; | 
 | import java.util.Map; | 
 | import java.util.concurrent.Executor; | 
 |  | 
 | /* | 
 |  * TODO(code review): Curious question... Why are a lot of these | 
 |  * methods not declared as static, since they do not seem to require | 
 |  * any local object state?  Presumably this cannot be changed without | 
 |  * interfering with the API... | 
 |  */ | 
 |  | 
 | /** | 
 |  * Manages SMS operations such as sending data, text, and pdu SMS messages. | 
 |  * Get this object by calling the static method {@link #getDefault()}. To create an instance of | 
 |  * {@link SmsManager} associated with a specific subscription ID, call | 
 |  * {@link #getSmsManagerForSubscriptionId(int)}. This is typically used for devices that support | 
 |  * multiple active subscriptions at once. | 
 |  * | 
 |  * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19) | 
 |  * and higher, see {@link android.provider.Telephony}. | 
 |  * | 
 |  * @see SubscriptionManager#getActiveSubscriptionInfoList() | 
 |  */ | 
 | @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING) | 
 | public final class SmsManager { | 
 |     private static final String TAG = "SmsManager"; | 
 |  | 
 |     private static final Object sLockObject = new Object(); | 
 |  | 
 |     @GuardedBy("sLockObject") | 
 |     private static final Map<Pair<Context, Integer>, SmsManager> sSubInstances = | 
 |             new ArrayMap<>(); | 
 |  | 
 |     /** Singleton object constructed during class initialization. */ | 
 |     private static final SmsManager DEFAULT_INSTANCE = getSmsManagerForContextAndSubscriptionId( | 
 |             null, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); | 
 |  | 
 |     /** SMS record length from TS 51.011 10.5.3 | 
 |      * @hide | 
 |      */ | 
 |     public static final int SMS_RECORD_LENGTH = 176; | 
 |  | 
 |     /** SMS record length from C.S0023 3.4.27 | 
 |      * @hide | 
 |      */ | 
 |     public static final int CDMA_SMS_RECORD_LENGTH = 255; | 
 |  | 
 |     /** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */ | 
 |     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) | 
 |     private int mSubId; | 
 |  | 
 |     /** | 
 |      * Context this SmsManager is for. Can be {@code null} in the case the manager was created via | 
 |      * legacy APIs | 
 |      */ | 
 |     private final @Nullable Context mContext; | 
 |  | 
 |     /* | 
 |      * Key for the various carrier-dependent configuration values. | 
 |      * Some of the values are used by the system in processing SMS or MMS messages. Others | 
 |      * are provided for the convenience of SMS applications. | 
 |      */ | 
 |  | 
 |     /** | 
 |      * Whether to append transaction id to MMS WAP Push M-Notification.ind's content location URI | 
 |      * when constructing the download URL of a new MMS (boolean type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_APPEND_TRANSACTION_ID = | 
 |             CarrierConfigManager.KEY_MMS_APPEND_TRANSACTION_ID_BOOL; | 
 |     /** | 
 |      * Whether MMS is enabled for the current carrier (boolean type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_MMS_ENABLED = CarrierConfigManager.KEY_MMS_MMS_ENABLED_BOOL; | 
 |     /** | 
 |      * Whether group MMS is enabled for the current carrier (boolean type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_GROUP_MMS_ENABLED = CarrierConfigManager.KEY_MMS_GROUP_MMS_ENABLED_BOOL; | 
 |     /** | 
 |      * If this is enabled, M-NotifyResp.ind should be sent to the WAP Push content location instead | 
 |      * of the default MMSC (boolean type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED = | 
 |             CarrierConfigManager.KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL; | 
 |     /** | 
 |      * Whether alias is enabled (boolean type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_ALIAS_ENABLED = CarrierConfigManager.KEY_MMS_ALIAS_ENABLED_BOOL; | 
 |     /** | 
 |      * Whether audio is allowed to be attached for MMS messages (boolean type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_ALLOW_ATTACH_AUDIO = CarrierConfigManager.KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL; | 
 |     /** | 
 |      * Whether multipart SMS is enabled (boolean type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED = | 
 |             CarrierConfigManager.KEY_MMS_MULTIPART_SMS_ENABLED_BOOL; | 
 |     /** | 
 |      * Whether SMS delivery report is enabled (boolean type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED = | 
 |             CarrierConfigManager.KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL; | 
 |     /** | 
 |      * Whether content-disposition field should be expected in an MMS PDU (boolean type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION = | 
 |             CarrierConfigManager.KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL; | 
 |     /** | 
 |      * Whether multipart SMS should be sent as separate messages | 
 |      */ | 
 |     public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES = | 
 |             CarrierConfigManager.KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL; | 
 |     /** | 
 |      * Whether MMS read report is enabled (boolean type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED = | 
 |             CarrierConfigManager.KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL; | 
 |     /** | 
 |      * Whether MMS delivery report is enabled (boolean type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED = | 
 |             CarrierConfigManager.KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL; | 
 |     /** | 
 |      * Max MMS message size in bytes (int type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_MAX_MESSAGE_SIZE = CarrierConfigManager.KEY_MMS_MAX_MESSAGE_SIZE_INT; | 
 |     /** | 
 |      * Max MMS image width (int type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_MAX_IMAGE_WIDTH = CarrierConfigManager.KEY_MMS_MAX_IMAGE_WIDTH_INT; | 
 |     /** | 
 |      * Max MMS image height (int type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_MAX_IMAGE_HEIGHT = CarrierConfigManager.KEY_MMS_MAX_IMAGE_HEIGHT_INT; | 
 |     /** | 
 |      * Limit of recipients of MMS messages (int type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_RECIPIENT_LIMIT = CarrierConfigManager.KEY_MMS_RECIPIENT_LIMIT_INT; | 
 |     /** | 
 |      * Min alias character count (int type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_ALIAS_MIN_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MIN_CHARS_INT; | 
 |     /** | 
 |      * Max alias character count (int type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_ALIAS_MAX_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MAX_CHARS_INT; | 
 |     /** | 
 |      * When the number of parts of a multipart SMS reaches this threshold, it should be converted | 
 |      * into an MMS (int type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD = | 
 |             CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT; | 
 |     /** | 
 |      * Some carriers require SMS to be converted into MMS when text length reaches this threshold | 
 |      * (int type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD = | 
 |             CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT; | 
 |     /** | 
 |      * Max message text size (int type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE = | 
 |             CarrierConfigManager.KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT; | 
 |     /** | 
 |      * Max message subject length (int type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_SUBJECT_MAX_LENGTH = CarrierConfigManager.KEY_MMS_SUBJECT_MAX_LENGTH_INT; | 
 |     /** | 
 |      * MMS HTTP socket timeout in milliseconds (int type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_HTTP_SOCKET_TIMEOUT = CarrierConfigManager.KEY_MMS_HTTP_SOCKET_TIMEOUT_INT; | 
 |     /** | 
 |      * The name of the UA Prof URL HTTP header for MMS HTTP request (String type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_UA_PROF_TAG_NAME = CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING; | 
 |     /** | 
 |      * The User-Agent header value for MMS HTTP request (String type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_USER_AGENT = CarrierConfigManager.KEY_MMS_USER_AGENT_STRING; | 
 |     /** | 
 |      * The UA Profile URL header value for MMS HTTP request (String type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_UA_PROF_URL = CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING; | 
 |     /** | 
 |      * A list of HTTP headers to add to MMS HTTP request, separated by "|" (String type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_HTTP_PARAMS = CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING; | 
 |     /** | 
 |      * Email gateway number (String type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER = | 
 |             CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING; | 
 |     /** | 
 |      * The suffix to append to the NAI header value for MMS HTTP request (String type) | 
 |      */ | 
 |     public static final String | 
 |             MMS_CONFIG_NAI_SUFFIX = CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING; | 
 |     /** | 
 |      * If true, show the cell broadcast (amber alert) in the SMS settings. Some carriers don't want | 
 |      * this shown. (Boolean type) | 
 |      */ | 
 |     public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS = | 
 |             CarrierConfigManager.KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL; | 
 |     /** | 
 |      * Whether the carrier MMSC supports charset field in Content-Type header. If this is false, | 
 |      * then we don't add "charset" to "Content-Type" | 
 |      */ | 
 |     public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER = | 
 |             CarrierConfigManager.KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL; | 
 |     /** | 
 |      * If true, add "Connection: close" header to MMS HTTP requests so the connection | 
 |      * is immediately closed (disabling keep-alive). (Boolean type) | 
 |      * @hide | 
 |      */ | 
 |     public static final String MMS_CONFIG_CLOSE_CONNECTION = | 
 |             CarrierConfigManager.KEY_MMS_CLOSE_CONNECTION_BOOL; | 
 |  | 
 |     /** | 
 |      * 3gpp2 SMS priority is not specified | 
 |      * @hide | 
 |      */ | 
 |     public static final int SMS_MESSAGE_PRIORITY_NOT_SPECIFIED = -1; | 
 |     /** | 
 |      * 3gpp SMS period is not specified | 
 |      * @hide | 
 |      */ | 
 |     public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1; | 
 |  | 
 |     // RP-Cause Values For MO SMS as per TS 124 011, table 8.4. | 
 |  | 
 |     /** @hide */ | 
 |     @IntDef(prefix = { "SMS_RP_CAUSE" }, value = { | 
 |         SmsManager.SMS_RP_CAUSE_UNALLOCATED_NUMBER, | 
 |         SmsManager.SMS_RP_CAUSE_OPERATOR_DETERMINED_BARRING, | 
 |         SmsManager.SMS_RP_CAUSE_CALL_BARRING, | 
 |         SmsManager.SMS_RP_CAUSE_RESERVED, | 
 |         SmsManager.SMS_RP_CAUSE_SHORT_MESSAGE_TRANSFER_REJECTED, | 
 |         SmsManager.SMS_RP_CAUSE_DESTINATION_OUT_OF_ORDER, | 
 |         SmsManager.SMS_RP_CAUSE_UNIDENTIFIED_SUBSCRIBER, | 
 |         SmsManager.SMS_RP_CAUSE_FACILITY_REJECTED, | 
 |         SmsManager.SMS_RP_CAUSE_UNKNOWN_SUBSCRIBER, | 
 |         SmsManager.SMS_RP_CAUSE_NETWORK_OUT_OF_ORDER, | 
 |         SmsManager.SMS_RP_CAUSE_TEMPORARY_FAILURE, | 
 |         SmsManager.SMS_RP_CAUSE_CONGESTION, | 
 |         SmsManager.SMS_RP_CAUSE_RESOURCES_UNAVAILABLE, | 
 |         SmsManager.SMS_RP_CAUSE_FACILITY_NOT_SUBSCRIBED, | 
 |         SmsManager.SMS_RP_CAUSE_FACILITY_NOT_IMPLEMENTED, | 
 |         SmsManager.SMS_RP_CAUSE_INVALID_MESSAGE_REFERENCE_VALUE, | 
 |         SmsManager.SMS_RP_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE, | 
 |         SmsManager.SMS_RP_CAUSE_INVALID_MANDATORY_INFORMATION, | 
 |         SmsManager.SMS_RP_CAUSE_MESSAGE_TYPE_NON_EXISTENT, | 
 |         SmsManager.SMS_RP_CAUSE_MESSAGE_INCOMPATIBLE_WITH_PROTOCOL_STATE, | 
 |         SmsManager.SMS_RP_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT, | 
 |         SmsManager.SMS_RP_CAUSE_PROTOCOL_ERROR, | 
 |         SmsManager.SMS_RP_CAUSE_INTERWORKING_UNSPECIFIED | 
 |     }) | 
 |     @Retention(RetentionPolicy.SOURCE) | 
 |     public @interface SMS_RP_CAUSE {} | 
 |  | 
 |     /** Unallocated Number Cause */ | 
 |     public static final int SMS_RP_CAUSE_UNALLOCATED_NUMBER = 1; | 
 |  | 
 |     /** RP-Cause for Operator Barring */ | 
 |     public static final int SMS_RP_CAUSE_OPERATOR_DETERMINED_BARRING = 8; | 
 |  | 
 |     /** RP-Cause Value for Call Barring */ | 
 |     public static final int SMS_RP_CAUSE_CALL_BARRING = 10; | 
 |  | 
 |     /** RP-Cause value for Reserved Number */ | 
 |     public static final int SMS_RP_CAUSE_RESERVED = 11; | 
 |  | 
 |     /** RP-Cause Value for Message Transfer Rejected by Network */ | 
 |     public static final int SMS_RP_CAUSE_SHORT_MESSAGE_TRANSFER_REJECTED = 21; | 
 |  | 
 |     /** RP-Cause Value for Destination is Out of Order */ | 
 |     public static final int SMS_RP_CAUSE_DESTINATION_OUT_OF_ORDER = 27; | 
 |  | 
 |     /** RP-Cause Value when Subscriber is not Identified */ | 
 |     public static final int SMS_RP_CAUSE_UNIDENTIFIED_SUBSCRIBER = 28; | 
 |  | 
 |     /** RP-Cause Value when SMS Facility if Rejected by Operator */ | 
 |     public static final int SMS_RP_CAUSE_FACILITY_REJECTED = 29; | 
 |  | 
 |     /** RP-Cause Value when Subscriber is not Identified */ | 
 |     public static final int SMS_RP_CAUSE_UNKNOWN_SUBSCRIBER = 30; | 
 |  | 
 |     /** RP-Cause Value when network is out of order*/ | 
 |     public static final int SMS_RP_CAUSE_NETWORK_OUT_OF_ORDER = 38; | 
 |  | 
 |     /** RP-Cause Value For Temporary failure*/ | 
 |     public static final int SMS_RP_CAUSE_TEMPORARY_FAILURE = 41; | 
 |  | 
 |     /** RP-Cause Value for SMS Failure due to Congestion in network*/ | 
 |     public static final int SMS_RP_CAUSE_CONGESTION = 42; | 
 |  | 
 |     /** RP-Cause Value when Network Resources are unavailable */ | 
 |     public static final int SMS_RP_CAUSE_RESOURCES_UNAVAILABLE = 47; | 
 |  | 
 |     /** RP-Cause Value when SMS Facilty is not subscribed by Reote device */ | 
 |     public static final int SMS_RP_CAUSE_FACILITY_NOT_SUBSCRIBED = 50; | 
 |  | 
 |     /** RP-Cause Value when network does not provide the received service */ | 
 |     public static final int SMS_RP_CAUSE_FACILITY_NOT_IMPLEMENTED = 69; | 
 |  | 
 |     /** RP-Cause Value when RP-MessageRefere */ | 
 |     public static final int SMS_RP_CAUSE_INVALID_MESSAGE_REFERENCE_VALUE = 81; | 
 |  | 
 |     /** RP-Cause Value when network does not provide the received service */ | 
 |     public static final int SMS_RP_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE = 95; | 
 |  | 
 |     /** RP-Cause Value when network does not provide the received service */ | 
 |     public static final int SMS_RP_CAUSE_INVALID_MANDATORY_INFORMATION = 96; | 
 |  | 
 |     /** RP-Cause Value when network does not provide the received service */ | 
 |     public static final int SMS_RP_CAUSE_MESSAGE_TYPE_NON_EXISTENT = 97; | 
 |  | 
 |     /** RP-Cause Value when network does not provide the received service */ | 
 |     public static final int SMS_RP_CAUSE_MESSAGE_INCOMPATIBLE_WITH_PROTOCOL_STATE = 98; | 
 |  | 
 |     /** RP-Cause Value when network does not provide the received service */ | 
 |     public static final int SMS_RP_CAUSE_INFORMATION_ELEMENT_NON_EXISTENT  = 99; | 
 |  | 
 |     /** RP-Cause Value when network does not provide the received service */ | 
 |     public static final int SMS_RP_CAUSE_PROTOCOL_ERROR = 111; | 
 |  | 
 |     /** RP-Cause Value when network does not provide the received service */ | 
 |     public static final int SMS_RP_CAUSE_INTERWORKING_UNSPECIFIED = 127; | 
 |  | 
 |     /** @hide */ | 
 |     @IntDef(prefix = { "PREMIUM_SMS_CONSENT" }, value = { | 
 |         SmsManager.PREMIUM_SMS_CONSENT_UNKNOWN, | 
 |         SmsManager.PREMIUM_SMS_CONSENT_ASK_USER, | 
 |         SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW, | 
 |         SmsManager.PREMIUM_SMS_CONSENT_ALWAYS_ALLOW | 
 |     }) | 
 |     @Retention(RetentionPolicy.SOURCE) | 
 |     public @interface PremiumSmsConsent {} | 
 |  | 
 |     /** Premium SMS Consent for the package is unknown. This indicates that the user | 
 |      *  has not set a permission for this package, because this package has never tried | 
 |      *  to send a premium SMS. | 
 |      * @hide | 
 |      */ | 
 |     @SystemApi | 
 |     public static final int PREMIUM_SMS_CONSENT_UNKNOWN = 0; | 
 |  | 
 |     /** Default premium SMS Consent (ask user for each premium SMS sent). | 
 |      * @hide | 
 |      */ | 
 |     @SystemApi | 
 |     public static final int PREMIUM_SMS_CONSENT_ASK_USER = 1; | 
 |  | 
 |     /** Premium SMS Consent when the owner has denied the app from sending premium SMS. | 
 |      * @hide | 
 |      */ | 
 |     @SystemApi | 
 |     public static final int PREMIUM_SMS_CONSENT_NEVER_ALLOW = 2; | 
 |  | 
 |     /** Premium SMS Consent when the owner has allowed the app to send premium SMS. | 
 |      * @hide | 
 |      */ | 
 |     @SystemApi | 
 |     public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; | 
 |  | 
 |     // result of asking the user for a subscription to perform an operation. | 
 |     private interface SubscriptionResolverResult { | 
 |         void onSuccess(int subId); | 
 |         void onFailure(); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get {@link Context#getOpPackageName()} if this manager has a context, otherwise a dummy | 
 |      * value. | 
 |      * | 
 |      * @return The package name to be used for app-ops checks | 
 |      */ | 
 |     private @Nullable String getOpPackageName() { | 
 |         if (mContext == null) { | 
 |             return null; | 
 |         } else { | 
 |             return mContext.getOpPackageName(); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get {@link Context#getAttributionTag()} ()} if this manager has a context, otherwise get the | 
 |      * default attribution tag. | 
 |      * | 
 |      * @return The attribution tag to be used for app-ops checks | 
 |      */ | 
 |     private @Nullable String getAttributionTag() { | 
 |         if (mContext == null) { | 
 |             return null; | 
 |         } else { | 
 |             return mContext.getAttributionTag(); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send a text based SMS. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the | 
 |      * {@link android.Manifest.permission#SEND_SMS} permission.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if | 
 |      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically | 
 |      * writes messages sent using this method to the SMS Provider (the default SMS app is always | 
 |      * responsible for writing its sent messages to the SMS Provider). For information about | 
 |      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail sending the SMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code sentIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the | 
 |      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions | 
 |      * where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param destinationAddress the address to send the message to | 
 |      * @param scAddress is the service center address or null to use | 
 |      *  the current default SMSC | 
 |      * @param text the body of the message to send | 
 |      * @param sentIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is successfully sent, or failed. | 
 |      *  The result code will be <code>Activity.RESULT_OK</code> for success, | 
 |      *  or one of these errors:<br> | 
 |      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_RADIO_OFF</code><br> | 
 |      *  <code>RESULT_ERROR_NULL_PDU</code><br> | 
 |      *  <code>RESULT_ERROR_NO_SERVICE</code><br> | 
 |      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> | 
 |      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> | 
 |      *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_SYSTEM_ERROR</code><br> | 
 |      *  <code>RESULT_MODEM_ERROR</code><br> | 
 |      *  <code>RESULT_NETWORK_ERROR</code><br> | 
 |      *  <code>RESULT_ENCODING_ERROR</code><br> | 
 |      *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_INTERNAL_ERROR</code><br> | 
 |      *  <code>RESULT_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_CANCELLED</code><br> | 
 |      *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br> | 
 |      *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> | 
 |      *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br> | 
 |      *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> | 
 |      *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> | 
 |      *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br> | 
 |      *  <code>RESULT_REMOTE_EXCEPTION</code><br> | 
 |      *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br> | 
 |      *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_RIL_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_RIL_SYSTEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_ENCODING_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_RIL_MODEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INTERNAL_ERR</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br> | 
 |      *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_RIL_CANCELLED</code><br> | 
 |      *  <code>RESULT_RIL_SIM_ABSENT</code><br> | 
 |      *  <code>RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_ACCESS_BARRED</code><br> | 
 |      *  <code>RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> | 
 |      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, | 
 |      *  the sentIntent may include the extra "errorCode" containing a radio technology specific | 
 |      *  value, generally only useful for troubleshooting.<br> | 
 |      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is delivered to the recipient.  The | 
 |      *  raw pdu of the status report is in the extended data ("pdu"). | 
 |      * | 
 |      * @throws IllegalArgumentException if destinationAddress or text are empty | 
 |      */ | 
 |     public void sendTextMessage( | 
 |             String destinationAddress, String scAddress, String text, | 
 |             PendingIntent sentIntent, PendingIntent deliveryIntent) { | 
 |         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, | 
 |                 true /* persistMessage*/, getOpPackageName(), getAttributionTag(), | 
 |                 0L /* messageId */); | 
 |     } | 
 |  | 
 |  | 
 |     /** | 
 |      * Send a text based SMS. Same as {@link #sendTextMessage( String destinationAddress, | 
 |      * String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)}, but | 
 |      * adds an optional messageId. | 
 |      * @param messageId An id that uniquely identifies the message requested to be sent. | 
 |      * Used for logging and diagnostics purposes. The id may be 0. | 
 |      * | 
 |      * @throws IllegalArgumentException if destinationAddress or text are empty | 
 |      * | 
 |      */ | 
 |     public void sendTextMessage( | 
 |             @NonNull String destinationAddress, @Nullable String scAddress, @NonNull String text, | 
 |             @Nullable PendingIntent sentIntent, @Nullable PendingIntent deliveryIntent, | 
 |             long messageId) { | 
 |         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, | 
 |                 true /* persistMessage*/, getOpPackageName(), getAttributionTag(), | 
 |                 messageId); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send a text based SMS with messaging options. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail sending the SMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code sentIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the | 
 |      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions | 
 |      * where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param destinationAddress the address to send the message to | 
 |      * @param scAddress is the service center address or null to use | 
 |      *  the current default SMSC | 
 |      * @param text the body of the message to send | 
 |      * @param sentIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is successfully sent, or failed. | 
 |      *  The result code will be <code>Activity.RESULT_OK</code> for success, | 
 |      *  or one of these errors:<br> | 
 |      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_RADIO_OFF</code><br> | 
 |      *  <code>RESULT_ERROR_NULL_PDU</code><br> | 
 |      *  <code>RESULT_ERROR_NO_SERVICE</code><br> | 
 |      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> | 
 |      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> | 
 |      *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_SYSTEM_ERROR</code><br> | 
 |      *  <code>RESULT_MODEM_ERROR</code><br> | 
 |      *  <code>RESULT_NETWORK_ERROR</code><br> | 
 |      *  <code>RESULT_ENCODING_ERROR</code><br> | 
 |      *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_INTERNAL_ERROR</code><br> | 
 |      *  <code>RESULT_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_CANCELLED</code><br> | 
 |      *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br> | 
 |      *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> | 
 |      *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br> | 
 |      *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> | 
 |      *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> | 
 |      *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br> | 
 |      *  <code>RESULT_REMOTE_EXCEPTION</code><br> | 
 |      *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br> | 
 |      *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_RIL_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_RIL_SYSTEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_ENCODING_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_RIL_MODEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INTERNAL_ERR</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br> | 
 |      *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_RIL_CANCELLED</code><br> | 
 |      *  <code>RESULT_RIL_SIM_ABSENT</code><br> | 
 |      *  <code>RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_ACCESS_BARRED</code><br> | 
 |      *  <code>RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> | 
 |      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, | 
 |      *  the sentIntent may include the extra "errorCode" containing a radio technology specific | 
 |      *  value, generally only useful for troubleshooting.<br> | 
 |      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is delivered to the recipient.  The | 
 |      *  raw pdu of the status report is in the extended data ("pdu"). | 
 |      * @param priority Priority level of the message | 
 |      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 | 
 |      *  --------------------------------- | 
 |      *  PRIORITY      | Level of Priority | 
 |      *  --------------------------------- | 
 |      *      '00'      |     Normal | 
 |      *      '01'      |     Interactive | 
 |      *      '10'      |     Urgent | 
 |      *      '11'      |     Emergency | 
 |      *  ---------------------------------- | 
 |      *  Any Other values included Negative considered as Invalid Priority Indicator of the message. | 
 |      * @param expectMore is a boolean to indicate the sending messages through same link or not. | 
 |      * @param validityPeriod Validity Period of the message in mins. | 
 |      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. | 
 |      *  Validity Period(Minimum) -> 5 mins | 
 |      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). | 
 |      *  Any Other values included Negative considered as Invalid Validity Period of the message. | 
 |      * | 
 |      * @throws IllegalArgumentException if destinationAddress or text are empty | 
 |      * {@hide} | 
 |      */ | 
 |     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) | 
 |     public void sendTextMessage( | 
 |             String destinationAddress, String scAddress, String text, | 
 |             PendingIntent sentIntent, PendingIntent deliveryIntent, | 
 |             int priority, boolean expectMore, int validityPeriod) { | 
 |         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, | 
 |                 true /* persistMessage*/, priority, expectMore, validityPeriod); | 
 |     } | 
 |  | 
 |     private void sendTextMessageInternal(String destinationAddress, String scAddress, | 
 |             String text, PendingIntent sentIntent, PendingIntent deliveryIntent, | 
 |             boolean persistMessage, String packageName, String attributionTag, long messageId) { | 
 |         if (TextUtils.isEmpty(destinationAddress)) { | 
 |             throw new IllegalArgumentException("Invalid destinationAddress"); | 
 |         } | 
 |  | 
 |         if (TextUtils.isEmpty(text)) { | 
 |             throw new IllegalArgumentException("Invalid message body"); | 
 |         } | 
 |  | 
 |         // We will only show the SMS disambiguation dialog in the case that the message is being | 
 |         // persisted. This is for two reasons: | 
 |         // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific | 
 |         //    subscription and require special permissions. These messages are usually not sent by | 
 |         //    the device user and should not have an SMS disambiguation dialog associated with them | 
 |         //    because the device user did not trigger them. | 
 |         // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the SEND_SMS | 
 |         //    permission. If we call resolveSubscriptionForOperation from a carrier/OEM app that has | 
 |         //    the correct MODIFY_PHONE_STATE or carrier permissions, but no SEND_SMS, it will throw | 
 |         //    an incorrect SecurityException. | 
 |         if (persistMessage) { | 
 |             resolveSubscriptionForOperation(new SubscriptionResolverResult() { | 
 |                 @Override | 
 |                 public void onSuccess(int subId) { | 
 |                     ISms iSms = getISmsServiceOrThrow(); | 
 |                     try { | 
 |                         iSms.sendTextForSubscriber(subId, packageName, attributionTag, | 
 |                                 destinationAddress, scAddress, text, sentIntent, deliveryIntent, | 
 |                                 persistMessage, messageId); | 
 |                     } catch (RemoteException e) { | 
 |                         Log.e(TAG, "sendTextMessageInternal: Couldn't send SMS, exception - " | 
 |                                 + e.getMessage() + " " + formatCrossStackMessageId(messageId)); | 
 |                         notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION); | 
 |                     } | 
 |                 } | 
 |  | 
 |                 @Override | 
 |                 public void onFailure() { | 
 |                     notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP); | 
 |                 } | 
 |             }); | 
 |         } else { | 
 |             // Not persisting the message, used by sendTextMessageWithoutPersisting() and is not | 
 |             // visible to the user. | 
 |             ISms iSms = getISmsServiceOrThrow(); | 
 |             try { | 
 |                 iSms.sendTextForSubscriber(getSubscriptionId(), packageName, attributionTag, | 
 |                         destinationAddress, scAddress, text, sentIntent, deliveryIntent, | 
 |                         persistMessage, messageId); | 
 |             } catch (RemoteException e) { | 
 |                 Log.e(TAG, "sendTextMessageInternal (no persist): Couldn't send SMS, exception - " | 
 |                         + e.getMessage() + " " + formatCrossStackMessageId(messageId)); | 
 |                 notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION); | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send a text based SMS without writing it into the SMS Provider. | 
 |      * | 
 |      * <p> | 
 |      * The message will be sent directly over the network and will not be visible in SMS | 
 |      * applications. Intended for internal carrier use only. | 
 |      * </p> | 
 |      * | 
 |      * <p>Requires Permission: Both {@link android.Manifest.permission#SEND_SMS} and | 
 |      * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or that the calling app has carrier | 
 |      * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), or that the calling app is | 
 |      * the default IMS app (see | 
 |      * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}). | 
 |      * </p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the SMS being sent on the subscription associated with logical | 
 |      * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the | 
 |      * correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent) | 
 |      */ | 
 |     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges | 
 |     @RequiresPermission(allOf = { | 
 |             android.Manifest.permission.MODIFY_PHONE_STATE, | 
 |             android.Manifest.permission.SEND_SMS | 
 |     }) | 
 |     public void sendTextMessageWithoutPersisting( | 
 |             String destinationAddress, String scAddress, String text, | 
 |             PendingIntent sentIntent, PendingIntent deliveryIntent) { | 
 |         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, | 
 |                 false /* persistMessage */, getOpPackageName(), | 
 |                 getAttributionTag(), 0L /* messageId */); | 
 |     } | 
 |  | 
 |     private void sendTextMessageInternal( | 
 |             String destinationAddress, String scAddress, String text, | 
 |             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, | 
 |             int priority, boolean expectMore, int validityPeriod) { | 
 |         if (TextUtils.isEmpty(destinationAddress)) { | 
 |             throw new IllegalArgumentException("Invalid destinationAddress"); | 
 |         } | 
 |  | 
 |         if (TextUtils.isEmpty(text)) { | 
 |             throw new IllegalArgumentException("Invalid message body"); | 
 |         } | 
 |  | 
 |         if (priority < 0x00 || priority > 0x03) { | 
 |             Log.e(TAG, "Invalid Priority " + priority); | 
 |             priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; | 
 |         } | 
 |  | 
 |         if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { | 
 |             Log.e(TAG, "Invalid Validity Period " + validityPeriod); | 
 |             validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED; | 
 |         } | 
 |  | 
 |         final int finalPriority = priority; | 
 |         final int finalValidity = validityPeriod; | 
 |         // We will only show the SMS disambiguation dialog in the case that the message is being | 
 |         // persisted. This is for two reasons: | 
 |         // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific | 
 |         //    subscription and require special permissions. These messages are usually not sent by | 
 |         //    the device user and should not have an SMS disambiguation dialog associated with them | 
 |         //    because the device user did not trigger them. | 
 |         // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the SEND_SMS | 
 |         //    permission. If we call resolveSubscriptionForOperation from a carrier/OEM app that has | 
 |         //    the correct MODIFY_PHONE_STATE or carrier permissions, but no SEND_SMS, it will throw | 
 |         //    an incorrect SecurityException. | 
 |         if (persistMessage) { | 
 |             resolveSubscriptionForOperation(new SubscriptionResolverResult() { | 
 |                 @Override | 
 |                 public void onSuccess(int subId) { | 
 |                     try { | 
 |                         ISms iSms = getISmsServiceOrThrow(); | 
 |                         if (iSms != null) { | 
 |                             iSms.sendTextForSubscriberWithOptions(subId, | 
 |                                     null, null, destinationAddress, | 
 |                                     scAddress, | 
 |                                     text, sentIntent, deliveryIntent, persistMessage, finalPriority, | 
 |                                     expectMore, finalValidity); | 
 |                         } | 
 |                     } catch (RemoteException e) { | 
 |                         Log.e(TAG, "sendTextMessageInternal: Couldn't send SMS, exception - " | 
 |                                 + e.getMessage()); | 
 |                         notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION); | 
 |                     } | 
 |                 } | 
 |  | 
 |                 @Override | 
 |                 public void onFailure() { | 
 |                     notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP); | 
 |                 } | 
 |             }); | 
 |         } else { | 
 |             try { | 
 |                 ISms iSms = getISmsServiceOrThrow(); | 
 |                 if (iSms != null) { | 
 |                     iSms.sendTextForSubscriberWithOptions(getSubscriptionId(), | 
 |                             null, null, destinationAddress, | 
 |                             scAddress, | 
 |                             text, sentIntent, deliveryIntent, persistMessage, finalPriority, | 
 |                             expectMore, finalValidity); | 
 |                 } | 
 |             } catch (RemoteException e) { | 
 |                 Log.e(TAG, "sendTextMessageInternal(no persist): Couldn't send SMS, exception - " | 
 |                         + e.getMessage()); | 
 |                 notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION); | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * | 
 |      * Inject an SMS PDU into the android application framework. | 
 |      * | 
 |      * <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier | 
 |      * privileges per {@link android.telephony.TelephonyManager#hasCarrierPrivileges}. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the SMS being injected on the subscription associated with | 
 |      * logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is | 
 |      * delivered to the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param pdu is the byte array of pdu to be injected into android application framework | 
 |      * @param format is the format of SMS pdu ({@link SmsMessage#FORMAT_3GPP} or | 
 |      *  {@link SmsMessage#FORMAT_3GPP2}) | 
 |      * @param receivedIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is successfully received by the | 
 |      *  android application framework, or failed. This intent is broadcasted at | 
 |      *  the same time an SMS received from radio is acknowledged back. | 
 |      *  The result code will be {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_HANDLED} | 
 |      *  for success, or {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_GENERIC_ERROR} or | 
 |      *  {@link #RESULT_REMOTE_EXCEPTION} for error. | 
 |      * | 
 |      * @throws IllegalArgumentException if the format is invalid. | 
 |      */ | 
 |     public void injectSmsPdu( | 
 |             byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent) { | 
 |         if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) { | 
 |             // Format must be either 3gpp or 3gpp2. | 
 |             throw new IllegalArgumentException( | 
 |                     "Invalid pdu format. format must be either 3gpp or 3gpp2"); | 
 |         } | 
 |         try { | 
 |             ISms iSms = TelephonyManager.getSmsService(); | 
 |             if (iSms != null) { | 
 |                 iSms.injectSmsPduForSubscriber( | 
 |                         getSubscriptionId(), pdu, format, receivedIntent); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             try { | 
 |                 if (receivedIntent != null) { | 
 |                     receivedIntent.send(RESULT_REMOTE_EXCEPTION); | 
 |                 } | 
 |             } catch (PendingIntent.CanceledException cx) { | 
 |                 // Don't worry about it, we do not need to notify the caller if this is the case. | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Divide a message text into several fragments, none bigger than the maximum SMS message size. | 
 |      * | 
 |      * @param text the original message. Must not be null. | 
 |      * @return an <code>ArrayList</code> of strings that, in order, comprise the original message. | 
 |      * @throws IllegalArgumentException if text is null. | 
 |      */ | 
 |     public ArrayList<String> divideMessage(String text) { | 
 |         if (null == text) { | 
 |             throw new IllegalArgumentException("text is null"); | 
 |         } | 
 |         return SmsMessage.fragmentText(text, getSubscriptionId()); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send a multi-part text based SMS.  The callee should have already | 
 |      * divided the message into correctly sized parts by calling | 
 |      * <code>divideMessage</code>. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the | 
 |      * {@link android.Manifest.permission#SEND_SMS} permission.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if | 
 |      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically | 
 |      * writes messages sent using this method to the SMS Provider (the default SMS app is always | 
 |      * responsible for writing its sent messages to the SMS Provider). For information about | 
 |      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail sending the SMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code sentIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the | 
 |      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions | 
 |      * where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param destinationAddress the address to send the message to | 
 |      * @param scAddress is the service center address or null to use | 
 |      *  the current default SMSC | 
 |      * @param parts an <code>ArrayList</code> of strings that, in order, | 
 |      *  comprise the original message | 
 |      * @param sentIntents if not null, an <code>ArrayList</code> of | 
 |      *  <code>PendingIntent</code>s (one for each message part) that is | 
 |      *  broadcast when the corresponding message part has been sent. | 
 |      *  The result code will be <code>Activity.RESULT_OK</code> for success, | 
 |      *  or one of these errors:<br> | 
 |      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_RADIO_OFF</code><br> | 
 |      *  <code>RESULT_ERROR_NULL_PDU</code><br> | 
 |      *  <code>RESULT_ERROR_NO_SERVICE</code><br> | 
 |      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> | 
 |      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> | 
 |      *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_SYSTEM_ERROR</code><br> | 
 |      *  <code>RESULT_MODEM_ERROR</code><br> | 
 |      *  <code>RESULT_NETWORK_ERROR</code><br> | 
 |      *  <code>RESULT_ENCODING_ERROR</code><br> | 
 |      *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_INTERNAL_ERROR</code><br> | 
 |      *  <code>RESULT_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_CANCELLED</code><br> | 
 |      *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br> | 
 |      *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> | 
 |      *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br> | 
 |      *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> | 
 |      *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> | 
 |      *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br> | 
 |      *  <code>RESULT_REMOTE_EXCEPTION</code><br> | 
 |      *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br> | 
 |      *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_RIL_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_RIL_SYSTEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_ENCODING_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_RIL_MODEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INTERNAL_ERR</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br> | 
 |      *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_RIL_CANCELLED</code><br> | 
 |      *  <code>RESULT_RIL_SIM_ABSENT</code><br> | 
 |      *  <code>RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_ACCESS_BARRED</code><br> | 
 |      *  <code>RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> | 
 |      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, | 
 |      *  the sentIntent may include the extra "errorCode" containing a radio technology specific | 
 |      *  value, generally only useful for troubleshooting.<br> | 
 |      * @param deliveryIntents if not null, an <code>ArrayList</code> of | 
 |      *  <code>PendingIntent</code>s (one for each message part) that is | 
 |      *  broadcast when the corresponding message part has been delivered | 
 |      *  to the recipient.  The raw pdu of the status report is in the | 
 |      *  extended data ("pdu"). | 
 |      * | 
 |      * @throws IllegalArgumentException if destinationAddress or data are empty | 
 |      */ | 
 |     public void sendMultipartTextMessage( | 
 |             String destinationAddress, String scAddress, ArrayList<String> parts, | 
 |             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { | 
 |         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, | 
 |                 deliveryIntents, true /* persistMessage*/, getOpPackageName(), | 
 |                 getAttributionTag(), 0L /* messageId */); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send a multi-part text based SMS. Same as #sendMultipartTextMessage(String, String, | 
 |      * ArrayList, ArrayList, ArrayList), but adds an optional messageId. | 
 |      * @param messageId An id that uniquely identifies the message requested to be sent. | 
 |      * Used for logging and diagnostics purposes. The id may be 0. | 
 |      * | 
 |      * @throws IllegalArgumentException if destinationAddress or data are empty | 
 |      * | 
 |      */ | 
 |     public void sendMultipartTextMessage( | 
 |             @NonNull String destinationAddress, @Nullable String scAddress, | 
 |             @NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents, | 
 |             @Nullable List<PendingIntent> deliveryIntents, long messageId) { | 
 |         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, | 
 |                 deliveryIntents, true /* persistMessage*/, getOpPackageName(), | 
 |                 getAttributionTag(), messageId); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Similar method as #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList) | 
 |      * With an additional argument. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use the Telephony | 
 |      * framework and will never trigger an SMS disambiguation dialog. If this method is called on a | 
 |      * device that has multiple active subscriptions, this {@link SmsManager} instance has been | 
 |      * created with {@link #getDefault()}, and no user-defined default subscription is defined, the | 
 |      * subscription ID associated with this message will be INVALID, which will result in the SMS | 
 |      * being sent on the subscription associated with logical slot 0. Use | 
 |      * {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the correct | 
 |      * subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param packageName serves as the default package name if the package name that is | 
 |      *        associated with the user id is null. | 
 |      */ | 
 |     public void sendMultipartTextMessage( | 
 |             @NonNull String destinationAddress, @Nullable String scAddress, | 
 |             @NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents, | 
 |             @Nullable List<PendingIntent> deliveryIntents, @NonNull String packageName, | 
 |             @Nullable String attributionTag) { | 
 |         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, | 
 |                 deliveryIntents, true /* persistMessage*/, packageName, attributionTag, | 
 |                 0L /* messageId */); | 
 |     } | 
 |  | 
 |     private void sendMultipartTextMessageInternal( | 
 |             String destinationAddress, String scAddress, List<String> parts, | 
 |             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, | 
 |             boolean persistMessage, String packageName, @Nullable String attributionTag, | 
 |             long messageId) { | 
 |         if (TextUtils.isEmpty(destinationAddress)) { | 
 |             throw new IllegalArgumentException("Invalid destinationAddress"); | 
 |         } | 
 |         if (parts == null || parts.size() < 1) { | 
 |             throw new IllegalArgumentException("Invalid message body"); | 
 |         } | 
 |  | 
 |         if (parts.size() > 1) { | 
 |             // We will only show the SMS disambiguation dialog in the case that the message is being | 
 |             // persisted. This is for two reasons: | 
 |             // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific | 
 |             //    subscription and require special permissions. These messages are usually not sent | 
 |             //    by the device user and should not have an SMS disambiguation dialog associated | 
 |             //    with them because the device user did not trigger them. | 
 |             // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the | 
 |             //    SEND_SMS permission. If we call resolveSubscriptionForOperation from a carrier/OEM | 
 |             //    app that has the correct MODIFY_PHONE_STATE or carrier permissions, but no | 
 |             //    SEND_SMS, it will throw an incorrect SecurityException. | 
 |             if (persistMessage) { | 
 |                 resolveSubscriptionForOperation(new SubscriptionResolverResult() { | 
 |                     @Override | 
 |                     public void onSuccess(int subId) { | 
 |                         try { | 
 |                             ISms iSms = getISmsServiceOrThrow(); | 
 |                             iSms.sendMultipartTextForSubscriber(subId, packageName, attributionTag, | 
 |                                     destinationAddress, scAddress, parts, sentIntents, | 
 |                                     deliveryIntents, persistMessage, messageId); | 
 |                         } catch (RemoteException e) { | 
 |                             Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - " | 
 |                                     + e.getMessage() + " " + formatCrossStackMessageId(messageId)); | 
 |                             notifySmsError(sentIntents, RESULT_REMOTE_EXCEPTION); | 
 |                         } | 
 |                     } | 
 |  | 
 |                     @Override | 
 |                     public void onFailure() { | 
 |                         notifySmsError(sentIntents, RESULT_NO_DEFAULT_SMS_APP); | 
 |                     } | 
 |                 }); | 
 |             } else { | 
 |                 // Called by apps that are not user facing, don't show disambiguation dialog. | 
 |                 try { | 
 |                     ISms iSms = getISmsServiceOrThrow(); | 
 |                     if (iSms != null) { | 
 |                         iSms.sendMultipartTextForSubscriber(getSubscriptionId(), packageName, | 
 |                                 attributionTag, destinationAddress, scAddress, parts, sentIntents, | 
 |                                 deliveryIntents, persistMessage, messageId); | 
 |                     } | 
 |                 } catch (RemoteException e) { | 
 |                     Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - " | 
 |                             + e.getMessage() + " " + formatCrossStackMessageId(messageId)); | 
 |                     notifySmsError(sentIntents, RESULT_REMOTE_EXCEPTION); | 
 |                 } | 
 |             } | 
 |         } else { | 
 |             PendingIntent sentIntent = null; | 
 |             PendingIntent deliveryIntent = null; | 
 |             if (sentIntents != null && sentIntents.size() > 0) { | 
 |                 sentIntent = sentIntents.get(0); | 
 |             } | 
 |             if (deliveryIntents != null && deliveryIntents.size() > 0) { | 
 |                 deliveryIntent = deliveryIntents.get(0); | 
 |             } | 
 |             sendTextMessageInternal(destinationAddress, scAddress, parts.get(0), | 
 |                     sentIntent, deliveryIntent, true, packageName, attributionTag, messageId); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send a multi-part text based SMS without writing it into the SMS Provider. | 
 |      * | 
 |      * <p> | 
 |      * If this method is called on a device with multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the SMS sent on the subscription associated with slot | 
 |      * 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent using the | 
 |      * correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * <p>Requires Permission: | 
 |      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier | 
 |      * privileges. | 
 |      * </p> | 
 |      * | 
 |      * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList) | 
 |      * @hide | 
 |      **/ | 
 |     @SystemApi | 
 |     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) | 
 |     public void sendMultipartTextMessageWithoutPersisting( | 
 |             String destinationAddress, String scAddress, List<String> parts, | 
 |             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { | 
 |         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, | 
 |                 deliveryIntents, false /* persistMessage*/, getOpPackageName(), | 
 |                 getAttributionTag(), 0L /* messageId */); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send a multi-part text based SMS with messaging options. The callee should have already | 
 |      * divided the message into correctly sized parts by calling | 
 |      * <code>divideMessage</code>. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the | 
 |      * {@link android.Manifest.permission#SEND_SMS} permission.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if | 
 |      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically | 
 |      * writes messages sent using this method to the SMS Provider (the default SMS app is always | 
 |      * responsible for writing its sent messages to the SMS Provider). For information about | 
 |      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail sending the SMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code sentIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the | 
 |      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions | 
 |      * where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param destinationAddress the address to send the message to | 
 |      * @param scAddress is the service center address or null to use | 
 |      *  the current default SMSC | 
 |      * @param parts an <code>ArrayList</code> of strings that, in order, | 
 |      *  comprise the original message | 
 |      * @param sentIntents if not null, an <code>ArrayList</code> of | 
 |      *  <code>PendingIntent</code>s (one for each message part) that is | 
 |      *  broadcast when the corresponding message part has been sent. | 
 |      *  The result code will be <code>Activity.RESULT_OK</code> for success, | 
 |      *  or one of these errors:<br> | 
 |      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_RADIO_OFF</code><br> | 
 |      *  <code>RESULT_ERROR_NULL_PDU</code><br> | 
 |      *  <code>RESULT_ERROR_NO_SERVICE</code><br> | 
 |      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> | 
 |      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> | 
 |      *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_SYSTEM_ERROR</code><br> | 
 |      *  <code>RESULT_MODEM_ERROR</code><br> | 
 |      *  <code>RESULT_NETWORK_ERROR</code><br> | 
 |      *  <code>RESULT_ENCODING_ERROR</code><br> | 
 |      *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_INTERNAL_ERROR</code><br> | 
 |      *  <code>RESULT_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_CANCELLED</code><br> | 
 |      *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br> | 
 |      *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> | 
 |      *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br> | 
 |      *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> | 
 |      *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> | 
 |      *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br> | 
 |      *  <code>RESULT_REMOTE_EXCEPTION</code><br> | 
 |      *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br> | 
 |      *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_RIL_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_RIL_SYSTEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_ENCODING_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_RIL_MODEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INTERNAL_ERR</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br> | 
 |      *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_RIL_CANCELLED</code><br> | 
 |      *  <code>RESULT_RIL_SIM_ABSENT</code><br> | 
 |      *  <code>RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_ACCESS_BARRED</code><br> | 
 |      *  <code>RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> | 
 |      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, | 
 |      *  the sentIntent may include the extra "errorCode" containing a radio technology specific | 
 |      *  value, generally only useful for troubleshooting.<br> | 
 |      * @param deliveryIntents if not null, an <code>ArrayList</code> of | 
 |      *  <code>PendingIntent</code>s (one for each message part) that is | 
 |      *  broadcast when the corresponding message part has been delivered | 
 |      *  to the recipient.  The raw pdu of the status report is in the | 
 |      *  extended data ("pdu"). | 
 |      * @param priority Priority level of the message | 
 |      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 | 
 |      *  --------------------------------- | 
 |      *  PRIORITY      | Level of Priority | 
 |      *  --------------------------------- | 
 |      *      '00'      |     Normal | 
 |      *      '01'      |     Interactive | 
 |      *      '10'      |     Urgent | 
 |      *      '11'      |     Emergency | 
 |      *  ---------------------------------- | 
 |      *  Any Other values included Negative considered as Invalid Priority Indicator of the message. | 
 |      * @param expectMore is a boolean to indicate the sending messages through same link or not. | 
 |      * @param validityPeriod Validity Period of the message in mins. | 
 |      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. | 
 |      *  Validity Period(Minimum) -> 5 mins | 
 |      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). | 
 |      *  Any Other values included Negative considered as Invalid Validity Period of the message. | 
 |      * | 
 |      * @throws IllegalArgumentException if destinationAddress or data are empty | 
 |      * {@hide} | 
 |      */ | 
 |     @UnsupportedAppUsage | 
 |     public void sendMultipartTextMessage( | 
 |             String destinationAddress, String scAddress, ArrayList<String> parts, | 
 |             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, | 
 |             int priority, boolean expectMore, int validityPeriod) { | 
 |         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, | 
 |                 deliveryIntents, true /* persistMessage*/, priority, expectMore, | 
 |                 validityPeriod); | 
 |     } | 
 |  | 
 |     private void sendMultipartTextMessageInternal( | 
 |             String destinationAddress, String scAddress, List<String> parts, | 
 |             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, | 
 |             boolean persistMessage, int priority, boolean expectMore, int validityPeriod) { | 
 |         if (TextUtils.isEmpty(destinationAddress)) { | 
 |             throw new IllegalArgumentException("Invalid destinationAddress"); | 
 |         } | 
 |         if (parts == null || parts.size() < 1) { | 
 |             throw new IllegalArgumentException("Invalid message body"); | 
 |         } | 
 |  | 
 |         if (priority < 0x00 || priority > 0x03) { | 
 |             Log.e(TAG, "Invalid Priority " + priority); | 
 |             priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED; | 
 |         } | 
 |  | 
 |         if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) { | 
 |             Log.e(TAG, "Invalid Validity Period " + validityPeriod); | 
 |             validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED; | 
 |         } | 
 |  | 
 |         if (parts.size() > 1) { | 
 |             final int finalPriority = priority; | 
 |             final int finalValidity = validityPeriod; | 
 |             if (persistMessage) { | 
 |                 resolveSubscriptionForOperation(new SubscriptionResolverResult() { | 
 |                     @Override | 
 |                     public void onSuccess(int subId) { | 
 |                         try { | 
 |                             ISms iSms = getISmsServiceOrThrow(); | 
 |                             if (iSms != null) { | 
 |                                 iSms.sendMultipartTextForSubscriberWithOptions(subId, | 
 |                                         null, null, destinationAddress, | 
 |                                         scAddress, parts, sentIntents, deliveryIntents, | 
 |                                         persistMessage, finalPriority, expectMore, finalValidity); | 
 |                             } | 
 |                         } catch (RemoteException e) { | 
 |                             Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - " | 
 |                                     + e.getMessage()); | 
 |                             notifySmsError(sentIntents, RESULT_REMOTE_EXCEPTION); | 
 |                         } | 
 |                     } | 
 |  | 
 |                     @Override | 
 |                     public void onFailure() { | 
 |                         notifySmsError(sentIntents, RESULT_NO_DEFAULT_SMS_APP); | 
 |                     } | 
 |                 }); | 
 |             } else { | 
 |                 // Sent by apps that are not user visible, so don't show SIM disambiguation dialog. | 
 |                 try { | 
 |                     ISms iSms = getISmsServiceOrThrow(); | 
 |                     if (iSms != null) { | 
 |                         iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(), | 
 |                                 null, null, destinationAddress, | 
 |                                 scAddress, parts, sentIntents, deliveryIntents, | 
 |                                 persistMessage, finalPriority, expectMore, finalValidity); | 
 |                     } | 
 |                 } catch (RemoteException e) { | 
 |                     Log.e(TAG, "sendMultipartTextMessageInternal (no persist): Couldn't send SMS - " | 
 |                             + e.getMessage()); | 
 |                     notifySmsError(sentIntents, RESULT_REMOTE_EXCEPTION); | 
 |                 } | 
 |             } | 
 |         } else { | 
 |             PendingIntent sentIntent = null; | 
 |             PendingIntent deliveryIntent = null; | 
 |             if (sentIntents != null && sentIntents.size() > 0) { | 
 |                 sentIntent = sentIntents.get(0); | 
 |             } | 
 |             if (deliveryIntents != null && deliveryIntents.size() > 0) { | 
 |                 deliveryIntent = deliveryIntents.get(0); | 
 |             } | 
 |             sendTextMessageInternal(destinationAddress, scAddress, parts.get(0), | 
 |                     sentIntent, deliveryIntent, persistMessage, priority, expectMore, | 
 |                     validityPeriod); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send a data based SMS to a specific application port. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the | 
 |      * {@link android.Manifest.permission#SEND_SMS} permission.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail sending the SMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code sentIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the | 
 |      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions | 
 |      * where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param destinationAddress the address to send the message to | 
 |      * @param scAddress is the service center address or null to use | 
 |      *  the current default SMSC | 
 |      * @param destinationPort the port to deliver the message to | 
 |      * @param data the body of the message to send | 
 |      * @param sentIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is successfully sent, or failed. | 
 |      *  The result code will be <code>Activity.RESULT_OK</code> for success, | 
 |      *  or one of these errors:<br> | 
 |      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_RADIO_OFF</code><br> | 
 |      *  <code>RESULT_ERROR_NULL_PDU</code><br> | 
 |      *  <code>RESULT_ERROR_NO_SERVICE</code><br> | 
 |      *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> | 
 |      *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> | 
 |      *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_SYSTEM_ERROR</code><br> | 
 |      *  <code>RESULT_MODEM_ERROR</code><br> | 
 |      *  <code>RESULT_NETWORK_ERROR</code><br> | 
 |      *  <code>RESULT_ENCODING_ERROR</code><br> | 
 |      *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_INTERNAL_ERROR</code><br> | 
 |      *  <code>RESULT_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_CANCELLED</code><br> | 
 |      *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br> | 
 |      *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> | 
 |      *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br> | 
 |      *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> | 
 |      *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> | 
 |      *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br> | 
 |      *  <code>RESULT_REMOTE_EXCEPTION</code><br> | 
 |      *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br> | 
 |      *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> | 
 |      *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_REJECT</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_STATE</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br> | 
 |      *  <code>RESULT_RIL_NO_MEMORY</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br> | 
 |      *  <code>RESULT_RIL_SYSTEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_ENCODING_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> | 
 |      *  <code>RESULT_RIL_MODEM_ERR</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_ERR</code><br> | 
 |      *  <code>RESULT_RIL_INTERNAL_ERR</code><br> | 
 |      *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> | 
 |      *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br> | 
 |      *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br> | 
 |      *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_NO_RESOURCES</code><br> | 
 |      *  <code>RESULT_RIL_CANCELLED</code><br> | 
 |      *  <code>RESULT_RIL_SIM_ABSENT</code><br> | 
 |      *  <code>RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> | 
 |      *  <code>RESULT_RIL_ACCESS_BARRED</code><br> | 
 |      *  <code>RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> | 
 |      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, | 
 |      *  the sentIntent may include the extra "errorCode" containing a radio technology specific | 
 |      *  value, generally only useful for troubleshooting.<br> | 
 |      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is delivered to the recipient.  The | 
 |      *  raw pdu of the status report is in the extended data ("pdu"). | 
 |      * | 
 |      * @throws IllegalArgumentException if destinationAddress or data are empty | 
 |      */ | 
 |     public void sendDataMessage( | 
 |             String destinationAddress, String scAddress, short destinationPort, | 
 |             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { | 
 |         if (TextUtils.isEmpty(destinationAddress)) { | 
 |             throw new IllegalArgumentException("Invalid destinationAddress"); | 
 |         } | 
 |  | 
 |         if (data == null || data.length == 0) { | 
 |             throw new IllegalArgumentException("Invalid message data"); | 
 |         } | 
 |  | 
 |         resolveSubscriptionForOperation(new SubscriptionResolverResult() { | 
 |             @Override | 
 |             public void onSuccess(int subId) { | 
 |                 try { | 
 |                     ISms iSms = getISmsServiceOrThrow(); | 
 |                     iSms.sendDataForSubscriber(subId, null, null, destinationAddress, scAddress, | 
 |                             destinationPort & 0xFFFF, data, sentIntent, deliveryIntent); | 
 |                 } catch (RemoteException e) { | 
 |                     Log.e(TAG, "sendDataMessage: Couldn't send SMS - Exception: " + e.getMessage()); | 
 |                     notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION); | 
 |                 } | 
 |             } | 
 |             @Override | 
 |             public void onFailure() { | 
 |                 notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP); | 
 |             } | 
 |         }); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the SmsManager associated with the default subscription id. The instance will always be | 
 |      * associated with the default subscription id, even if the default subscription id changes. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> For devices that support multiple active subscriptions | 
 |      * at a time, SmsManager will track the subscription set by the user as the default SMS | 
 |      * subscription. If the user has not set a default, {@link SmsManager} may | 
 |      * start an activity to kick off a subscription disambiguation dialog. Most operations will not | 
 |      * complete until the user has chosen the subscription that will be associated with the | 
 |      * operation. If the user cancels the dialog without choosing a subscription, one of the | 
 |      * following will happen, depending on the target SDK version of the application. For | 
 |      * compatibility purposes, if the target SDK level is <= 28, telephony will still send the SMS | 
 |      * over the first available subscription. If the target SDK level is > 28, the operation will | 
 |      * fail to complete. | 
 |      * </p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> If this method is used to perform an operation on a | 
 |      * device that has multiple active subscriptions, the user has not set a default SMS | 
 |      * subscription, and the operation is being performed while the application is not in the | 
 |      * foreground, the SMS disambiguation dialog will not be shown. The result of the operation will | 
 |      * conclude as if the user cancelled the disambiguation dialog and the operation will finish as | 
 |      * outlined above, depending on the target SDK version of the calling application. It is safer | 
 |      * to use {@link #getSmsManagerForSubscriptionId(int)} if the application will perform the | 
 |      * operation while in the background because this can cause unpredictable results, such as the | 
 |      * operation being sent over the wrong subscription or failing completely, depending on the | 
 |      * user's default SMS subscription setting. | 
 |      * </p> | 
 |      * | 
 |      * @return the {@link SmsManager} associated with the default subscription id. | 
 |      * | 
 |      * @see SubscriptionManager#getDefaultSmsSubscriptionId() | 
 |      * | 
 |      * @deprecated Use {@link Context#getSystemService Context.getSystemService(SmsManager.class)} | 
 |      * instead | 
 |      */ | 
 |     @Deprecated | 
 |     public static SmsManager getDefault() { | 
 |         return DEFAULT_INSTANCE; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the instance of the SmsManager associated with a particular context and subscription ID. | 
 |      * | 
 |      * @param context The context the manager belongs to | 
 |      * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager} | 
 |      * | 
 |      * @return the instance of the SmsManager associated with subscription | 
 |      * | 
 |      * @hide | 
 |      */ | 
 |     public static @NonNull SmsManager getSmsManagerForContextAndSubscriptionId( | 
 |             @Nullable Context context, int subId) { | 
 |         synchronized(sLockObject) { | 
 |             Pair<Context, Integer> key = new Pair<>(context, subId); | 
 |  | 
 |             SmsManager smsManager = sSubInstances.get(key); | 
 |             if (smsManager == null) { | 
 |                 smsManager = new SmsManager(context, subId); | 
 |                 sSubInstances.put(key, smsManager); | 
 |             } | 
 |             return smsManager; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the instance of the SmsManager associated with a particular subscription ID. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Constructing an {@link SmsManager} in this manner will | 
 |      * never cause an SMS disambiguation dialog to appear, unlike {@link #getDefault()}. | 
 |      * </p> | 
 |      * | 
 |      * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager} | 
 |      * @return the instance of the SmsManager associated with subscription | 
 |      * | 
 |      * @see SubscriptionManager#getActiveSubscriptionInfoList() | 
 |      * @see SubscriptionManager#getDefaultSmsSubscriptionId() | 
 |      * @deprecated Use {@link Context#getSystemService Context.getSystemService(SmsManager.class)} | 
 |      * .{@link #createForSubscriptionId createForSubscriptionId(subId)} instead | 
 |      */ | 
 |     @Deprecated | 
 |     public static SmsManager getSmsManagerForSubscriptionId(int subId) { | 
 |         return getSmsManagerForContextAndSubscriptionId(null, subId); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the instance of the SmsManager associated with a particular subscription ID. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Constructing an {@link SmsManager} in this manner will | 
 |      * never cause an SMS disambiguation dialog to appear, unlike {@link #getDefault()}. | 
 |      * </p> | 
 |      * | 
 |      * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager} | 
 |      * @return the instance of the SmsManager associated with subscription | 
 |      * | 
 |      * @see SubscriptionManager#getActiveSubscriptionInfoList() | 
 |      * @see SubscriptionManager#getDefaultSmsSubscriptionId() | 
 |      */ | 
 |     public @NonNull SmsManager createForSubscriptionId(int subId) { | 
 |         return getSmsManagerForContextAndSubscriptionId(mContext, subId); | 
 |     } | 
 |  | 
 |     private SmsManager(@Nullable Context context, int subId) { | 
 |         mContext = context; | 
 |         mSubId = subId; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get the associated subscription id. If the instance was returned by {@link #getDefault()}, | 
 |      * then this method may return different values at different points in time (if the user | 
 |      * changes the default subscription id). | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method used to display a disambiguation dialog to | 
 |      * the user asking them to choose a default subscription to send SMS messages over if they | 
 |      * haven't chosen yet. Starting in API level 29, we allow the user to not have a default set as | 
 |      * a valid option for the default SMS subscription on multi-SIM devices. We no longer show the | 
 |      * disambiguation dialog and return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if the | 
 |      * device has multiple active subscriptions and no default is set. | 
 |      * </p> | 
 |      * | 
 |      * @return associated subscription ID or {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if | 
 |      * the default subscription id cannot be determined or the device has multiple active | 
 |      * subscriptions and and no default is set ("ask every time") by the user. | 
 |      */ | 
 |     public int getSubscriptionId() { | 
 |         try { | 
 |             return (mSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) | 
 |                     ? getISmsServiceOrThrow().getPreferredSmsSubscription() : mSubId; | 
 |         } catch (RemoteException e) { | 
 |             return SubscriptionManager.INVALID_SUBSCRIPTION_ID; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Resolves the subscription id to use for the associated operation if | 
 |      * {@link #getSubscriptionId()} returns {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. | 
 |      * | 
 |      * If app targets API level 28 or below and they are either sending the SMS from the background | 
 |      * or the device has more than one active subscription available and no default is set, we will | 
 |      * use the first logical slot to send the SMS and possibly fail later in the SMS sending | 
 |      * process. | 
 |      * | 
 |      * Regardless of the API level, if the app is the foreground app, then we will show the SMS | 
 |      * disambiguation dialog. If the app is in the background and tries to perform an operation, we | 
 |      * will not show the disambiguation dialog. | 
 |      * | 
 |      * See {@link #getDefault()} for a detailed explanation of how this method operates. | 
 |      * | 
 |      * @param resolverResult The callback that will be called when the subscription is resolved or | 
 |      *                       fails to be resolved. | 
 |      */ | 
 |     private void resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult) { | 
 |         int subId = getSubscriptionId(); | 
 |         boolean isSmsSimPickActivityNeeded = false; | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 // Determines if the SMS SIM pick activity should be shown. This is only shown if: | 
 |                 // 1) The device has multiple active subscriptions and an SMS default subscription | 
 |                 //    hasn't been set, and | 
 |                 // 2) SmsManager is being called from the foreground app. | 
 |                 // Android does not allow background activity starts, so we need to block this. | 
 |                 // if Q+, do not perform requested operation if these two operations are not set. If | 
 |                 // <P, perform these operations on phone 0 (for compatibility purposes, since we | 
 |                 // used to not wait for the result of this activity). | 
 |                 isSmsSimPickActivityNeeded = iSms.isSmsSimPickActivityNeeded(subId); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             Log.e(TAG, "resolveSubscriptionForOperation", ex); | 
 |         } | 
 |         if (!isSmsSimPickActivityNeeded) { | 
 |             sendResolverResult(resolverResult, subId, false /*pickActivityShown*/); | 
 |             return; | 
 |         } | 
 |         // We need to ask the user pick an appropriate subid for the operation. | 
 |         Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for calling" | 
 |                 + " package. "); | 
 |         try { | 
 |             // Create the SMS pick activity and call back once the activity is complete. Can't do | 
 |             // it here because we do not have access to the activity context that is performing this | 
 |             // operation. | 
 |             // Requires that the calling process has the SEND_SMS permission. | 
 |             getITelephony().enqueueSmsPickResult(null, null, | 
 |                     new IIntegerConsumer.Stub() { | 
 |                         @Override | 
 |                         public void accept(int subId) { | 
 |                             // Runs on binder thread attached to this app's process. | 
 |                             sendResolverResult(resolverResult, subId, true /*pickActivityShown*/); | 
 |                         } | 
 |                     }); | 
 |         } catch (RemoteException ex) { | 
 |             Log.e(TAG, "Unable to launch activity", ex); | 
 |             // pickActivityShown is true here because we want to call sendResolverResult and always | 
 |             // have this operation fail. This is because we received a RemoteException here, which | 
 |             // means that telephony is not available and the next operation to Telephony will fail | 
 |             // as well anyways, so we might as well shortcut fail here first. | 
 |             sendResolverResult(resolverResult, subId, true /*pickActivityShown*/); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * To check the SDK version for SmsManager.sendResolverResult method. | 
 |      */ | 
 |     @ChangeId | 
 |     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P) | 
 |     private static final long GET_TARGET_SDK_VERSION_CODE_CHANGE = 145147528L; | 
 |  | 
 |     private void sendResolverResult(SubscriptionResolverResult resolverResult, int subId, | 
 |             boolean pickActivityShown) { | 
 |         if (SubscriptionManager.isValidSubscriptionId(subId)) { | 
 |             resolverResult.onSuccess(subId); | 
 |             return; | 
 |         } | 
 |  | 
 |         if (!Compatibility.isChangeEnabled(GET_TARGET_SDK_VERSION_CODE_CHANGE) | 
 |                 && !pickActivityShown) { | 
 |             // Do not fail, return a success with an INVALID subid for apps targeting P or below | 
 |             // that tried to perform an operation and the SMS disambiguation dialog was never shown, | 
 |             // as these applications may not have been written to handle the failure case properly. | 
 |             // This will resolve to performing the operation on phone 0 in telephony. | 
 |             resolverResult.onSuccess(subId); | 
 |         } else { | 
 |             // Fail if the app targets Q or above or it targets P and below and the disambiguation | 
 |             // dialog was shown and the user clicked out of it. | 
 |             resolverResult.onFailure(); | 
 |         } | 
 |     } | 
 |  | 
 |     private static ITelephony getITelephony() { | 
 |         ITelephony binder = ITelephony.Stub.asInterface( | 
 |                 TelephonyFrameworkInitializer | 
 |                         .getTelephonyServiceManager() | 
 |                         .getTelephonyServiceRegisterer() | 
 |                         .get()); | 
 |         if (binder == null) { | 
 |             throw new RuntimeException("Could not find Telephony Service."); | 
 |         } | 
 |         return binder; | 
 |     } | 
 |  | 
 |     private static void notifySmsError(PendingIntent pendingIntent, int error) { | 
 |         if (pendingIntent != null) { | 
 |             try { | 
 |                 pendingIntent.send(error); | 
 |             } catch (PendingIntent.CanceledException e) { | 
 |                 // Don't worry about it, we do not need to notify the caller if this is the case. | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     private static void notifySmsError(List<PendingIntent> pendingIntents, int error) { | 
 |         if (pendingIntents != null) { | 
 |             for (PendingIntent pendingIntent : pendingIntents) { | 
 |                 notifySmsError(pendingIntent, error); | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Returns the ISms service, or throws an UnsupportedOperationException if | 
 |      * the service does not exist. | 
 |      */ | 
 |     private static ISms getISmsServiceOrThrow() { | 
 |         ISms iSms = TelephonyManager.getSmsService(); | 
 |         if (iSms == null) { | 
 |             throw new UnsupportedOperationException("Sms is not supported"); | 
 |         } | 
 |         return iSms; | 
 |     } | 
 |  | 
 |     private static ISms getISmsService() { | 
 |         return TelephonyManager.getSmsService(); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Copies a raw SMS PDU to the ICC. | 
 |      * ICC (Integrated Circuit Card) is the card of the device. | 
 |      * For example, this can be the SIM or USIM for GSM. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param smsc the SMSC for this messag or null for the default SMSC. | 
 |      * @param pdu the raw PDU to store. | 
 |      * @param status message status. One of these status: | 
 |      *               <code>STATUS_ON_ICC_READ</code> | 
 |      *               <code>STATUS_ON_ICC_UNREAD</code> | 
 |      *               <code>STATUS_ON_ICC_SENT</code> | 
 |      *               <code>STATUS_ON_ICC_UNSENT</code> | 
 |      * @return true for success. Otherwise false. | 
 |      * | 
 |      * @throws IllegalArgumentException if pdu is null. | 
 |      * @hide | 
 |      */ | 
 |     @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC) | 
 |     public boolean copyMessageToIcc( | 
 |             @Nullable byte[] smsc, @NonNull byte[] pdu, @StatusOnIcc int status) { | 
 |         boolean success = false; | 
 |  | 
 |         if (pdu == null) { | 
 |             throw new IllegalArgumentException("pdu is null"); | 
 |         } | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(), | 
 |                         null, | 
 |                         status, pdu, smsc); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             // ignore it | 
 |         } | 
 |  | 
 |         return success; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Deletes the specified message from the ICC. | 
 |      * ICC (Integrated Circuit Card) is the card of the device. | 
 |      * For example, this can be the SIM or USIM for GSM. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param messageIndex the message index of the message in the ICC (1-based index). | 
 |      * @return true for success, false if the operation fails. Failure can be due to IPC failure, | 
 |      * RIL/modem error which results in SMS failed to be deleted on SIM | 
 |      * | 
 |      * {@hide} | 
 |      */ | 
 |     @UnsupportedAppUsage | 
 |     @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC) | 
 |     public boolean deleteMessageFromIcc(int messageIndex) { | 
 |         boolean success = false; | 
 |  | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(), | 
 |                         null, | 
 |                         messageIndex, STATUS_ON_ICC_FREE, null /* pdu */); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             // ignore it | 
 |         } | 
 |  | 
 |         return success; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Update the specified message on the ICC. | 
 |      * ICC (Integrated Circuit Card) is the card of the device. | 
 |      * For example, this can be the SIM or USIM for GSM. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param messageIndex record index of message to update | 
 |      * @param newStatus new message status (STATUS_ON_ICC_READ, | 
 |      *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, | 
 |      *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) | 
 |      * @param pdu the raw PDU to store | 
 |      * @return true for success | 
 |      * | 
 |      * {@hide} | 
 |      */ | 
 |     @UnsupportedAppUsage | 
 |     @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC) | 
 |     public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { | 
 |         boolean success = false; | 
 |  | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(), | 
 |                         null, | 
 |                         messageIndex, newStatus, pdu); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             // ignore it | 
 |         } | 
 |  | 
 |         return success; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Retrieves all messages currently stored on the ICC. | 
 |      * ICC (Integrated Circuit Card) is the card of the device. | 
 |      * For example, this can be the SIM or USIM for GSM. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @return <code>List</code> of <code>SmsMessage</code> objects for valid records only. | 
 |      * | 
 |      * {@hide} | 
 |      */ | 
 |     @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC) | 
 |     public @NonNull List<SmsMessage> getMessagesFromIcc() { | 
 |         return getAllMessagesFromIcc(); | 
 |     } | 
 |  | 
 |     /** | 
 |      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects | 
 |      * | 
 |      * This is similar to {@link #getMessagesFromIcc} except that it will return ArrayList. | 
 |      * Suggested to use {@link #getMessagesFromIcc} instead. | 
 |      * | 
 |      * {@hide} | 
 |      */ | 
 |     @UnsupportedAppUsage | 
 |     public ArrayList<SmsMessage> getAllMessagesFromIcc() { | 
 |         List<SmsRawData> records = null; | 
 |  | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 records = iSms.getAllMessagesFromIccEfForSubscriber( | 
 |                         getSubscriptionId(), | 
 |                         null); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             // ignore it | 
 |         } | 
 |  | 
 |         return createMessageListFromRawRecords(records); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Enable reception of cell broadcast (SMS-CB) messages with the given | 
 |      * message identifier range and RAN type. The RAN type specifies if this message ID | 
 |      * belongs to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable | 
 |      * the same message identifier, they must both disable it for the device to stop | 
 |      * receiving those messages. All received messages will be broadcast in an | 
 |      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED". | 
 |      * Note: This call is blocking, callers may want to avoid calling it from | 
 |      * the main thread of an application. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}, which will result in the operation | 
 |      * being completed on the subscription associated with logical slot 0. Use | 
 |      * {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation is performed on the | 
 |      * correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * <p>Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST}</p> | 
 |      * | 
 |      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) | 
 |      * or C.R1001-G (3GPP2) | 
 |      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) | 
 |      * or C.R1001-G (3GPP2) | 
 |      * @param ranType the message format as defined in {@link SmsCbMessage} | 
 |      * @return true if successful, false if the modem reports a failure (e.g. the given range or | 
 |      * RAN type is invalid). | 
 |      * @see #disableCellBroadcastRange(int, int, int) | 
 |      * | 
 |      * @throws IllegalArgumentException if endMessageId < startMessageId | 
 |      * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} instead. | 
 |      * {@hide} | 
 |      */ | 
 |     @Deprecated | 
 |     @SystemApi | 
 |     public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, | 
 |             @android.telephony.SmsCbMessage.MessageFormat int ranType) { | 
 |         boolean success = false; | 
 |         if (endMessageId < startMessageId) { | 
 |             throw new IllegalArgumentException("endMessageId < startMessageId"); | 
 |         } | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use | 
 |                 // the default phone internally. | 
 |                 int subId = getSubscriptionId(); | 
 |                 success = iSms.enableCellBroadcastRangeForSubscriber(subId, | 
 |                         startMessageId, endMessageId, ranType); | 
 |                 Rlog.d(TAG, "enableCellBroadcastRange: " + (success ? "succeeded" : "failed") | 
 |                         + " at calling enableCellBroadcastRangeForSubscriber. subId = " + subId); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             Rlog.d(TAG, "enableCellBroadcastRange: ", ex); | 
 |             // ignore it | 
 |         } | 
 |  | 
 |         return success; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Disable reception of cell broadcast (SMS-CB) messages with the given | 
 |      * message identifier range and RAN type. The RAN type specify this message | 
 |      * ID range belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different | 
 |      * clients enable the same message identifier, they must both disable it for | 
 |      * the device to stop receiving those messages. | 
 |      * Note: This call is blocking, callers may want to avoid calling it from | 
 |      * the main thread of an application. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * <p>Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST}</p> | 
 |      * | 
 |      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) | 
 |      * or C.R1001-G (3GPP2) | 
 |      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) | 
 |      * or C.R1001-G (3GPP2) | 
 |      * @param ranType the message format as defined in {@link SmsCbMessage} | 
 |      * @return true if successful, false if the modem reports a failure (e.g. the given range or | 
 |      * RAN type is invalid). | 
 |      * | 
 |      * @see #enableCellBroadcastRange(int, int, int) | 
 |      * | 
 |      * @throws IllegalArgumentException if endMessageId < startMessageId | 
 |      * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} instead. | 
 |      * {@hide} | 
 |      */ | 
 |     @Deprecated | 
 |     @SystemApi | 
 |     public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, | 
 |             @android.telephony.SmsCbMessage.MessageFormat int ranType) { | 
 |         boolean success = false; | 
 |  | 
 |         if (endMessageId < startMessageId) { | 
 |             throw new IllegalArgumentException("endMessageId < startMessageId"); | 
 |         } | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use | 
 |                 // the default phone internally. | 
 |                 int subId = getSubscriptionId(); | 
 |                 success = iSms.disableCellBroadcastRangeForSubscriber(subId, | 
 |                         startMessageId, endMessageId, ranType); | 
 |                 Rlog.d(TAG, "disableCellBroadcastRange: " + (success ? "succeeded" : "failed") | 
 |                         + " at calling disableCellBroadcastRangeForSubscriber. subId = " + subId); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             Rlog.d(TAG, "disableCellBroadcastRange: ", ex); | 
 |             // ignore it | 
 |         } | 
 |  | 
 |         return success; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Creates a list of <code>SmsMessage</code>s from a list of SmsRawData records. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param records SMS EF records. | 
 |      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. | 
 |      */ | 
 |     private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { | 
 |         ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); | 
 |         if (records != null) { | 
 |             int count = records.size(); | 
 |             for (int i = 0; i < count; i++) { | 
 |                 SmsRawData data = records.get(i); | 
 |                 // List contains all records, including "free" records (null) | 
 |                 if (data != null) { | 
 |                     SmsMessage sms = SmsMessage.createFromEfRecord(i + 1, data.getBytes(), | 
 |                             getSubscriptionId()); | 
 |                     if (sms != null) { | 
 |                         messages.add(sms); | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         return messages; | 
 |     } | 
 |  | 
 |     /** | 
 |      * SMS over IMS is supported if IMS is registered and SMS is supported | 
 |      * on IMS. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @return true if SMS over IMS is supported, false otherwise | 
 |      * | 
 |      * @see #getImsSmsFormat() | 
 |      * | 
 |      * @hide | 
 |      */ | 
 |     public boolean isImsSmsSupported() { | 
 |         boolean boSupported = false; | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 boSupported = iSms.isImsSmsSupportedForSubscriber(getSubscriptionId()); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             // ignore it | 
 |         } | 
 |         return boSupported; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Gets SMS format supported on IMS.  SMS over IMS format is either 3GPP or 3GPP2. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @return SmsMessage.FORMAT_3GPP, | 
 |      *         SmsMessage.FORMAT_3GPP2 | 
 |      *      or SmsMessage.FORMAT_UNKNOWN | 
 |      * | 
 |      * @see #isImsSmsSupported() | 
 |      * | 
 |      * @hide | 
 |      */ | 
 |     public String getImsSmsFormat() { | 
 |         String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN; | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 format = iSms.getImsSmsFormatForSubscriber(getSubscriptionId()); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             // ignore it | 
 |         } | 
 |         return format; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get default sms subscription id. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong>This returns a value different from | 
 |      * {@link SubscriptionManager#getDefaultSmsSubscriptionId} if the user has not chosen a default. | 
 |      * In this case it returns the active subscription id if there's only one active subscription | 
 |      * available. | 
 |      * | 
 |      * @return the user-defined default SMS subscription id, or the active subscription id if | 
 |      * there's only one active subscription available, otherwise | 
 |      * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. | 
 |      */ | 
 |     public static int getDefaultSmsSubscriptionId() { | 
 |         try { | 
 |             return getISmsService().getPreferredSmsSubscription(); | 
 |         } catch (RemoteException e) { | 
 |             return SubscriptionManager.INVALID_SUBSCRIPTION_ID; | 
 |         } catch (NullPointerException e) { | 
 |             return SubscriptionManager.INVALID_SUBSCRIPTION_ID; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Get SMS prompt property,  enabled or not | 
 |      * | 
 |      * @return true if enabled, false otherwise | 
 |      * @hide | 
 |      */ | 
 |     @UnsupportedAppUsage | 
 |     public boolean isSMSPromptEnabled() { | 
 |         ISms iSms = null; | 
 |         try { | 
 |             iSms = TelephonyManager.getSmsService(); | 
 |             return iSms.isSMSPromptEnabled(); | 
 |         } catch (RemoteException ex) { | 
 |             return false; | 
 |         } catch (NullPointerException ex) { | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Gets the total capacity of SMS storage on the SIM card. | 
 |      * | 
 |      * <p> | 
 |      * This is the number of 176 byte EF-SMS records which can be stored on the SIM card. | 
 |      * See 3GPP TS 31.102 - 4.2.25 - EF-SMS for more information. | 
 |      * </p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this method will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation | 
 |      * is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @return the total number of SMS records which can be stored on the SIM card. | 
 |      */ | 
 |     @RequiresPermission(anyOf = {android.Manifest.permission.READ_PHONE_STATE, | 
 |             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}) | 
 |     @IntRange(from = 0) | 
 |     public int getSmsCapacityOnIcc() { | 
 |         int ret = 0; | 
 |         try { | 
 |             ISms iccISms = getISmsService(); | 
 |             if (iccISms != null) { | 
 |                 ret = iccISms.getSmsCapacityOnIccForSubscriber(getSubscriptionId()); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             Log.e(TAG, "getSmsCapacityOnIcc() RemoteException", ex); | 
 |         } | 
 |         return ret; | 
 |     } | 
 |  | 
 |     /** @hide */ | 
 |     @IntDef(prefix = { "STATUS_ON_ICC_" }, value = { | 
 |             STATUS_ON_ICC_FREE, | 
 |             STATUS_ON_ICC_READ, | 
 |             STATUS_ON_ICC_UNREAD, | 
 |             STATUS_ON_ICC_SENT, | 
 |             STATUS_ON_ICC_UNSENT | 
 |     }) | 
 |     @Retention(RetentionPolicy.SOURCE) | 
 |     public @interface StatusOnIcc {} | 
 |  | 
 |     // see SmsMessage.getStatusOnIcc | 
 |  | 
 |     /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ | 
 |     public static final int STATUS_ON_ICC_FREE      = 0; | 
 |  | 
 |     /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ | 
 |     public static final int STATUS_ON_ICC_READ      = 1; | 
 |  | 
 |     /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ | 
 |     public static final int STATUS_ON_ICC_UNREAD    = 3; | 
 |  | 
 |     /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ | 
 |     public static final int STATUS_ON_ICC_SENT      = 5; | 
 |  | 
 |     /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ | 
 |     public static final int STATUS_ON_ICC_UNSENT    = 7; | 
 |  | 
 |     // SMS send failure result codes | 
 |  | 
 |     /** @hide */ | 
 |     @IntDef(prefix = { "RESULT" }, value = { | 
 |             RESULT_ERROR_NONE, | 
 |             RESULT_ERROR_GENERIC_FAILURE, | 
 |             RESULT_ERROR_RADIO_OFF, | 
 |             RESULT_ERROR_NULL_PDU, | 
 |             RESULT_ERROR_NO_SERVICE, | 
 |             RESULT_ERROR_LIMIT_EXCEEDED, | 
 |             RESULT_ERROR_FDN_CHECK_FAILURE, | 
 |             RESULT_ERROR_SHORT_CODE_NOT_ALLOWED, | 
 |             RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, | 
 |             RESULT_RADIO_NOT_AVAILABLE, | 
 |             RESULT_NETWORK_REJECT, | 
 |             RESULT_INVALID_ARGUMENTS, | 
 |             RESULT_INVALID_STATE, | 
 |             RESULT_NO_MEMORY, | 
 |             RESULT_INVALID_SMS_FORMAT, | 
 |             RESULT_SYSTEM_ERROR, | 
 |             RESULT_MODEM_ERROR, | 
 |             RESULT_NETWORK_ERROR, | 
 |             RESULT_INVALID_SMSC_ADDRESS, | 
 |             RESULT_OPERATION_NOT_ALLOWED, | 
 |             RESULT_INTERNAL_ERROR, | 
 |             RESULT_NO_RESOURCES, | 
 |             RESULT_CANCELLED, | 
 |             RESULT_REQUEST_NOT_SUPPORTED, | 
 |             RESULT_NO_BLUETOOTH_SERVICE, | 
 |             RESULT_INVALID_BLUETOOTH_ADDRESS, | 
 |             RESULT_BLUETOOTH_DISCONNECTED, | 
 |             RESULT_UNEXPECTED_EVENT_STOP_SENDING, | 
 |             RESULT_SMS_BLOCKED_DURING_EMERGENCY, | 
 |             RESULT_SMS_SEND_RETRY_FAILED, | 
 |             RESULT_REMOTE_EXCEPTION, | 
 |             RESULT_NO_DEFAULT_SMS_APP, | 
 |             RESULT_USER_NOT_ALLOWED, | 
 |             RESULT_RIL_RADIO_NOT_AVAILABLE, | 
 |             RESULT_RIL_SMS_SEND_FAIL_RETRY, | 
 |             RESULT_RIL_NETWORK_REJECT, | 
 |             RESULT_RIL_INVALID_STATE, | 
 |             RESULT_RIL_INVALID_ARGUMENTS, | 
 |             RESULT_RIL_NO_MEMORY, | 
 |             RESULT_RIL_REQUEST_RATE_LIMITED, | 
 |             RESULT_RIL_INVALID_SMS_FORMAT, | 
 |             RESULT_RIL_SYSTEM_ERR, | 
 |             RESULT_RIL_ENCODING_ERR, | 
 |             RESULT_RIL_INVALID_SMSC_ADDRESS, | 
 |             RESULT_RIL_MODEM_ERR, | 
 |             RESULT_RIL_NETWORK_ERR, | 
 |             RESULT_RIL_INTERNAL_ERR, | 
 |             RESULT_RIL_REQUEST_NOT_SUPPORTED, | 
 |             RESULT_RIL_INVALID_MODEM_STATE, | 
 |             RESULT_RIL_NETWORK_NOT_READY, | 
 |             RESULT_RIL_OPERATION_NOT_ALLOWED, | 
 |             RESULT_RIL_NO_RESOURCES, | 
 |             RESULT_RIL_CANCELLED, | 
 |             RESULT_RIL_SIM_ABSENT, | 
 |             RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED, | 
 |             RESULT_RIL_ACCESS_BARRED, | 
 |             RESULT_RIL_BLOCKED_DUE_TO_CALL, | 
 |             RESULT_RIL_GENERIC_ERROR, | 
 |             RESULT_RIL_INVALID_RESPONSE, | 
 |             RESULT_RIL_SIM_PIN2, | 
 |             RESULT_RIL_SIM_PUK2, | 
 |             RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE, | 
 |             RESULT_RIL_SIM_ERROR, | 
 |             RESULT_RIL_INVALID_SIM_STATE, | 
 |             RESULT_RIL_NO_SMS_TO_ACK, | 
 |             RESULT_RIL_SIM_BUSY, | 
 |             RESULT_RIL_SIM_FULL, | 
 |             RESULT_RIL_NO_SUBSCRIPTION, | 
 |             RESULT_RIL_NO_NETWORK_FOUND, | 
 |             RESULT_RIL_DEVICE_IN_USE, | 
 |             RESULT_RIL_ABORTED | 
 |     }) | 
 |     @Retention(RetentionPolicy.SOURCE) | 
 |     public @interface Result {} | 
 |  | 
 |     /** | 
 |      * No error. | 
 |      */ | 
 |     public static final int RESULT_ERROR_NONE    = 0; | 
 |  | 
 |     /** Generic failure cause */ | 
 |     public static final int RESULT_ERROR_GENERIC_FAILURE    = 1; | 
 |  | 
 |     /** Failed because radio was explicitly turned off */ | 
 |     public static final int RESULT_ERROR_RADIO_OFF          = 2; | 
 |  | 
 |     /** Failed because no pdu provided */ | 
 |     public static final int RESULT_ERROR_NULL_PDU           = 3; | 
 |  | 
 |     /** Failed because service is currently unavailable */ | 
 |     public static final int RESULT_ERROR_NO_SERVICE         = 4; | 
 |  | 
 |     /** Failed because we reached the sending queue limit. */ | 
 |     public static final int RESULT_ERROR_LIMIT_EXCEEDED     = 5; | 
 |  | 
 |     /** | 
 |      * Failed because FDN is enabled. | 
 |      */ | 
 |     public static final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6; | 
 |  | 
 |     /** Failed because user denied the sending of this short code. */ | 
 |     public static final int RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7; | 
 |  | 
 |     /** Failed because the user has denied this app ever send premium short codes. */ | 
 |     public static final int RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8; | 
 |  | 
 |     /** | 
 |      * Failed because the radio was not available | 
 |      */ | 
 |     public static final int RESULT_RADIO_NOT_AVAILABLE = 9; | 
 |  | 
 |     /** | 
 |      * Failed because of network rejection | 
 |      */ | 
 |     public static final int RESULT_NETWORK_REJECT = 10; | 
 |  | 
 |     /** | 
 |      * Failed because of invalid arguments | 
 |      */ | 
 |     public static final int RESULT_INVALID_ARGUMENTS = 11; | 
 |  | 
 |     /** | 
 |      * Failed because of an invalid state | 
 |      */ | 
 |     public static final int RESULT_INVALID_STATE = 12; | 
 |  | 
 |     /** | 
 |      * Failed because there is no memory | 
 |      */ | 
 |     public static final int RESULT_NO_MEMORY = 13; | 
 |  | 
 |     /** | 
 |      * Failed because the sms format is not valid | 
 |      */ | 
 |     public static final int RESULT_INVALID_SMS_FORMAT = 14; | 
 |  | 
 |     /** | 
 |      * Failed because of a system error | 
 |      */ | 
 |     public static final int RESULT_SYSTEM_ERROR = 15; | 
 |  | 
 |     /** | 
 |      * Failed because of a modem error | 
 |      */ | 
 |     public static final int RESULT_MODEM_ERROR = 16; | 
 |  | 
 |     /** | 
 |      * Failed because of a network error | 
 |      */ | 
 |     public static final int RESULT_NETWORK_ERROR = 17; | 
 |  | 
 |     /** | 
 |      * Failed because of an encoding error | 
 |      */ | 
 |     public static final int RESULT_ENCODING_ERROR = 18; | 
 |  | 
 |     /** | 
 |      * Failed because of an invalid smsc address | 
 |      */ | 
 |     public static final int RESULT_INVALID_SMSC_ADDRESS = 19; | 
 |  | 
 |     /** | 
 |      * Failed because the operation is not allowed | 
 |      */ | 
 |     public static final int RESULT_OPERATION_NOT_ALLOWED = 20; | 
 |  | 
 |     /** | 
 |      * Failed because of an internal error | 
 |      */ | 
 |     public static final int RESULT_INTERNAL_ERROR = 21; | 
 |  | 
 |     /** | 
 |      * Failed because there are no resources | 
 |      */ | 
 |     public static final int RESULT_NO_RESOURCES = 22; | 
 |  | 
 |     /** | 
 |      * Failed because the operation was cancelled | 
 |      */ | 
 |     public static final int RESULT_CANCELLED = 23; | 
 |  | 
 |     /** | 
 |      * Failed because the request is not supported | 
 |      */ | 
 |     public static final int RESULT_REQUEST_NOT_SUPPORTED = 24; | 
 |  | 
 |     /** | 
 |      * Failed sending via bluetooth because the bluetooth service is not available | 
 |      */ | 
 |     public static final int RESULT_NO_BLUETOOTH_SERVICE = 25; | 
 |  | 
 |     /** | 
 |      * Failed sending via bluetooth because the bluetooth device address is invalid | 
 |      */ | 
 |     public static final int RESULT_INVALID_BLUETOOTH_ADDRESS = 26; | 
 |  | 
 |     /** | 
 |      * Failed sending via bluetooth because bluetooth disconnected | 
 |      */ | 
 |     public static final int RESULT_BLUETOOTH_DISCONNECTED = 27; | 
 |  | 
 |     /** | 
 |      * Failed sending because the user denied or canceled the dialog displayed for a premium | 
 |      * shortcode sms or rate-limited sms. | 
 |      */ | 
 |     public static final int RESULT_UNEXPECTED_EVENT_STOP_SENDING = 28; | 
 |  | 
 |     /** | 
 |      * Failed sending during an emergency call | 
 |      */ | 
 |     public static final int RESULT_SMS_BLOCKED_DURING_EMERGENCY = 29; | 
 |  | 
 |     /** | 
 |      * Failed to send an sms retry | 
 |      */ | 
 |     public static final int RESULT_SMS_SEND_RETRY_FAILED = 30; | 
 |  | 
 |     /** | 
 |      * Set by BroadcastReceiver to indicate a remote exception while handling a message. | 
 |      */ | 
 |     public static final int RESULT_REMOTE_EXCEPTION = 31; | 
 |  | 
 |     /** | 
 |      * Set by BroadcastReceiver to indicate there's no default sms app. | 
 |      */ | 
 |     public static final int RESULT_NO_DEFAULT_SMS_APP = 32; | 
 |  | 
 |     /** | 
 |      * User is not associated with the subscription. | 
 |      * TODO(b/263279115): Make this error code public. | 
 |      * @hide | 
 |      */ | 
 |     public static final int RESULT_USER_NOT_ALLOWED = 33; | 
 |  | 
 |     // Radio Error results | 
 |  | 
 |     /** | 
 |      * The radio did not start or is resetting. | 
 |      */ | 
 |     public static final int RESULT_RIL_RADIO_NOT_AVAILABLE = 100; | 
 |  | 
 |     /** | 
 |      * The radio failed to send the sms and needs to retry. | 
 |      */ | 
 |     public static final int RESULT_RIL_SMS_SEND_FAIL_RETRY = 101; | 
 |  | 
 |     /** | 
 |      * The sms request was rejected by the network. | 
 |      */ | 
 |     public static final int RESULT_RIL_NETWORK_REJECT = 102; | 
 |  | 
 |     /** | 
 |      * The radio returned an unexpected request for the current state. | 
 |      */ | 
 |     public static final int RESULT_RIL_INVALID_STATE = 103; | 
 |  | 
 |     /** | 
 |      * The radio received invalid arguments in the request. | 
 |      */ | 
 |     public static final int RESULT_RIL_INVALID_ARGUMENTS = 104; | 
 |  | 
 |     /** | 
 |      * The radio didn't have sufficient memory to process the request. | 
 |      */ | 
 |     public static final int RESULT_RIL_NO_MEMORY = 105; | 
 |  | 
 |     /** | 
 |      * The radio denied the operation due to overly-frequent requests. | 
 |      */ | 
 |     public static final int RESULT_RIL_REQUEST_RATE_LIMITED = 106; | 
 |  | 
 |     /** | 
 |      * The radio returned an error indicating invalid sms format. | 
 |      */ | 
 |     public static final int RESULT_RIL_INVALID_SMS_FORMAT = 107; | 
 |  | 
 |     /** | 
 |      * The radio encountered a platform or system error. | 
 |      */ | 
 |     public static final int RESULT_RIL_SYSTEM_ERR = 108; | 
 |  | 
 |     /** | 
 |      * The SMS message was not encoded properly. | 
 |      */ | 
 |     public static final int RESULT_RIL_ENCODING_ERR = 109; | 
 |  | 
 |     /** | 
 |      * The specified SMSC address was invalid. | 
 |      */ | 
 |     public static final int RESULT_RIL_INVALID_SMSC_ADDRESS = 110; | 
 |  | 
 |     /** | 
 |      * The vendor RIL received an unexpected or incorrect response. | 
 |      */ | 
 |     public static final int RESULT_RIL_MODEM_ERR = 111; | 
 |  | 
 |     /** | 
 |      * The radio received an error from the network. | 
 |      */ | 
 |     public static final int RESULT_RIL_NETWORK_ERR = 112; | 
 |  | 
 |     /** | 
 |      * The modem encountered an unexpected error scenario while handling the request. | 
 |      */ | 
 |     public static final int RESULT_RIL_INTERNAL_ERR = 113; | 
 |  | 
 |     /** | 
 |      * The request was not supported by the radio. | 
 |      */ | 
 |     public static final int RESULT_RIL_REQUEST_NOT_SUPPORTED = 114; | 
 |  | 
 |     /** | 
 |      * The radio cannot process the request in the current modem state. | 
 |      */ | 
 |     public static final int RESULT_RIL_INVALID_MODEM_STATE = 115; | 
 |  | 
 |     /** | 
 |      * The network is not ready to perform the request. | 
 |      */ | 
 |     public static final int RESULT_RIL_NETWORK_NOT_READY = 116; | 
 |  | 
 |     /** | 
 |      * The radio reports the request is not allowed. | 
 |      */ | 
 |     public static final int RESULT_RIL_OPERATION_NOT_ALLOWED = 117; | 
 |  | 
 |     /** | 
 |      * There are insufficient resources to process the request. | 
 |      */ | 
 |     public static final int RESULT_RIL_NO_RESOURCES = 118; | 
 |  | 
 |     /** | 
 |      * The request has been cancelled. | 
 |      */ | 
 |     public static final int RESULT_RIL_CANCELLED = 119; | 
 |  | 
 |     /** | 
 |      * The radio failed to set the location where the CDMA subscription | 
 |      * can be retrieved because the SIM or RUIM is absent. | 
 |      */ | 
 |     public static final int RESULT_RIL_SIM_ABSENT = 120; | 
 |  | 
 |     /** | 
 |      * 1X voice and SMS are not allowed simultaneously. | 
 |      */ | 
 |     public static final int RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED = 121; | 
 |  | 
 |     /** | 
 |      * Access is barred. | 
 |      */ | 
 |     public static final int RESULT_RIL_ACCESS_BARRED = 122; | 
 |  | 
 |     /** | 
 |      * SMS is blocked due to call control, e.g., resource unavailable in the SMR entity. | 
 |      */ | 
 |     public static final int RESULT_RIL_BLOCKED_DUE_TO_CALL = 123; | 
 |  | 
 |     /** | 
 |      * A RIL error occurred during the SMS send. | 
 |      */ | 
 |     public static final int RESULT_RIL_GENERIC_ERROR = 124; | 
 |  | 
 |     /** | 
 |      * A RIL internal error when one of the RIL layers receives an unrecognized response from a | 
 |      * lower layer. | 
 |      */ | 
 |     public static final int RESULT_RIL_INVALID_RESPONSE = 125; | 
 |  | 
 |     /** | 
 |      * Operation requires SIM PIN2 to be entered | 
 |      */ | 
 |     public static final int RESULT_RIL_SIM_PIN2 = 126; | 
 |  | 
 |     /** | 
 |      * Operation requires SIM PUK2 to be entered | 
 |      */ | 
 |     public static final int RESULT_RIL_SIM_PUK2 = 127; | 
 |  | 
 |     /** | 
 |      * Fail to find CDMA subscription from specified location | 
 |      */ | 
 |     public static final int RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE = 128; | 
 |  | 
 |     /** | 
 |      * Received error from SIM card | 
 |      */ | 
 |     public static final int RESULT_RIL_SIM_ERROR = 129; | 
 |  | 
 |     /** | 
 |      * Cannot process the request in current SIM state | 
 |      */ | 
 |     public static final int RESULT_RIL_INVALID_SIM_STATE = 130; | 
 |  | 
 |     /** | 
 |      * ACK received when there is no SMS to ack | 
 |      */ | 
 |     public static final int RESULT_RIL_NO_SMS_TO_ACK = 131; | 
 |  | 
 |     /** | 
 |      * SIM is busy | 
 |      */ | 
 |     public static final int RESULT_RIL_SIM_BUSY = 132; | 
 |  | 
 |     /** | 
 |      * The target EF is full | 
 |      */ | 
 |     public static final int RESULT_RIL_SIM_FULL = 133; | 
 |  | 
 |     /** | 
 |      * Device does not have subscription | 
 |      */ | 
 |     public static final int RESULT_RIL_NO_SUBSCRIPTION = 134; | 
 |  | 
 |     /** | 
 |      * Network cannot be found | 
 |      */ | 
 |     public static final int RESULT_RIL_NO_NETWORK_FOUND = 135; | 
 |  | 
 |     /** | 
 |      * Operation cannot be performed because the device is currently in use | 
 |      */ | 
 |     public static final int RESULT_RIL_DEVICE_IN_USE = 136; | 
 |  | 
 |     /** | 
 |      * Operation aborted | 
 |      */ | 
 |     public static final int RESULT_RIL_ABORTED = 137; | 
 |  | 
 |  | 
 |     // SMS receiving results sent as a "result" extra in {@link Intents.SMS_REJECTED_ACTION} | 
 |  | 
 |     /** | 
 |      * SMS receive dispatch failure. | 
 |      */ | 
 |     public static final int RESULT_RECEIVE_DISPATCH_FAILURE = 500; | 
 |  | 
 |     /** | 
 |      * SMS receive injected null PDU. | 
 |      */ | 
 |     public static final int RESULT_RECEIVE_INJECTED_NULL_PDU = 501; | 
 |  | 
 |     /** | 
 |      * SMS receive encountered runtime exception. | 
 |      */ | 
 |     public static final int RESULT_RECEIVE_RUNTIME_EXCEPTION = 502; | 
 |  | 
 |     /** | 
 |      * SMS received null message from the radio interface layer. | 
 |      */ | 
 |     public static final int RESULT_RECEIVE_NULL_MESSAGE_FROM_RIL = 503; | 
 |  | 
 |     /** | 
 |      * SMS short code received while the phone is in encrypted state. | 
 |      */ | 
 |     public static final int RESULT_RECEIVE_WHILE_ENCRYPTED = 504; | 
 |  | 
 |     /** | 
 |      * SMS receive encountered an SQL exception. | 
 |      */ | 
 |     public static final int RESULT_RECEIVE_SQL_EXCEPTION = 505; | 
 |  | 
 |     /** | 
 |      * SMS receive an exception parsing a uri. | 
 |      */ | 
 |     public static final int RESULT_RECEIVE_URI_EXCEPTION = 506; | 
 |  | 
 |  | 
 |  | 
 |     /** | 
 |      * Send an MMS message | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail sending the MMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code sentIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the | 
 |      * conditions where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param context application context | 
 |      * @param contentUri the content Uri from which the message pdu will be read | 
 |      * @param locationUrl the optional location url where message should be sent to | 
 |      * @param configOverrides the carrier-specific messaging configuration values to override for | 
 |      *  sending the message. | 
 |      * @param sentIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is successfully sent, or failed | 
 |      * The result code will be <code>Activity.RESULT_OK</code> for success | 
 |      * or one of these errors:<br> | 
 |      * <code>MMS_ERROR_UNSPECIFIED</code><br> | 
 |      * <code>MMS_ERROR_INVALID_APN</code><br> | 
 |      * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br> | 
 |      * <code>MMS_ERROR_HTTP_FAILURE</code><br> | 
 |      * <code>MMS_ERROR_IO_ERROR</code><br> | 
 |      * <code>MMS_ERROR_RETRY</code><br> | 
 |      * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br> | 
 |      * <code>MMS_ERROR_NO_DATA_NETWORK</code><br> | 
 |      * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br> | 
 |      * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br> | 
 |      * <code>MMS_ERROR_DATA_DISABLED</code><br> | 
 |      * @throws IllegalArgumentException if contentUri is empty | 
 |      */ | 
 |     public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, | 
 |             Bundle configOverrides, PendingIntent sentIntent) { | 
 |         sendMultimediaMessage(context, contentUri, locationUrl, configOverrides, sentIntent, | 
 |                 0L /* messageId */); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Send an MMS message | 
 |      * | 
 |      * Same as {@link #sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, | 
 |      *           Bundle configOverrides, PendingIntent sentIntent)}, but adds an optional messageId. | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail sending the MMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code sentIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the | 
 |      * conditions where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param context application context | 
 |      * @param contentUri the content Uri from which the message pdu will be read | 
 |      * @param locationUrl the optional location url where message should be sent to | 
 |      * @param configOverrides the carrier-specific messaging configuration values to override for | 
 |      *  sending the message. | 
 |      * @param sentIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is successfully sent, or failed | 
 |      * The result code will be <code>Activity.RESULT_OK</code> for success | 
 |      * or one of these errors:<br> | 
 |      * <code>MMS_ERROR_UNSPECIFIED</code><br> | 
 |      * <code>MMS_ERROR_INVALID_APN</code><br> | 
 |      * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br> | 
 |      * <code>MMS_ERROR_HTTP_FAILURE</code><br> | 
 |      * <code>MMS_ERROR_IO_ERROR</code><br> | 
 |      * <code>MMS_ERROR_RETRY</code><br> | 
 |      * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br> | 
 |      * <code>MMS_ERROR_NO_DATA_NETWORK</code><br> | 
 |      * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br> | 
 |      * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br> | 
 |      * <code>MMS_ERROR_DATA_DISABLED</code><br> | 
 |      * @param messageId an id that uniquely identifies the message requested to be sent. | 
 |      * Used for logging and diagnostics purposes. The id may be 0. | 
 |      * @throws IllegalArgumentException if contentUri is empty | 
 |      */ | 
 |     public void sendMultimediaMessage(@NonNull Context context, @NonNull Uri contentUri, | 
 |             @Nullable String locationUrl, | 
 |             @SuppressWarnings("NullableCollection") @Nullable Bundle configOverrides, | 
 |             @Nullable PendingIntent sentIntent, long messageId) { | 
 |         if (contentUri == null) { | 
 |             throw new IllegalArgumentException("Uri contentUri null"); | 
 |         } | 
 |         MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE); | 
 |         if (m != null) { | 
 |             resolveSubscriptionForOperation(new SubscriptionResolverResult() { | 
 |                 @Override | 
 |                 public void onSuccess(int subId) { | 
 |                     m.sendMultimediaMessage(subId, contentUri, locationUrl, configOverrides, | 
 |                             sentIntent, messageId); | 
 |                 } | 
 |  | 
 |                 @Override | 
 |                 public void onFailure() { | 
 |                     notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP); | 
 |                 } | 
 |             }); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Download an MMS message from carrier by a given location URL | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail downloading the MMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code downloadedIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the | 
 |      * conditions where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param context application context | 
 |      * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained | 
 |      *  from the MMS WAP push notification | 
 |      * @param contentUri the content uri to which the downloaded pdu will be written | 
 |      * @param configOverrides the carrier-specific messaging configuration values to override for | 
 |      *  downloading the message. | 
 |      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is downloaded, or the download is failed | 
 |      * The result code will be <code>Activity.RESULT_OK</code> for success | 
 |      * or one of these errors:<br> | 
 |      * <code>MMS_ERROR_UNSPECIFIED</code><br> | 
 |      * <code>MMS_ERROR_INVALID_APN</code><br> | 
 |      * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br> | 
 |      * <code>MMS_ERROR_HTTP_FAILURE</code><br> | 
 |      * <code>MMS_ERROR_IO_ERROR</code><br> | 
 |      * <code>MMS_ERROR_RETRY</code><br> | 
 |      * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br> | 
 |      * <code>MMS_ERROR_NO_DATA_NETWORK</code><br> | 
 |      * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br> | 
 |      * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br> | 
 |      * <code>MMS_ERROR_DATA_DISABLED</code><br> | 
 |      * @throws IllegalArgumentException if locationUrl or contentUri is empty | 
 |      */ | 
 |     public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, | 
 |             Bundle configOverrides, PendingIntent downloadedIntent) { | 
 |         downloadMultimediaMessage(context, locationUrl, contentUri, configOverrides, | 
 |                 downloadedIntent, 0L /* messageId */); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Download an MMS message from carrier by a given location URL | 
 |      * | 
 |      * Same as {@link #downloadMultimediaMessage(Context context, String locationUrl, | 
 |      *      Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent)}, | 
 |      *      but adds an optional messageId. | 
 |      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this | 
 |      * manager on a multi-SIM device, this operation may fail downloading the MMS message because no | 
 |      * suitable default subscription could be found. In this case, if {@code downloadedIntent} is | 
 |      * non-null, then the {@link PendingIntent} will be sent with an error code | 
 |      * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the | 
 |      * conditions where this operation may fail. | 
 |      * </p> | 
 |      * | 
 |      * @param context application context | 
 |      * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained | 
 |      *  from the MMS WAP push notification | 
 |      * @param contentUri the content uri to which the downloaded pdu will be written | 
 |      * @param configOverrides the carrier-specific messaging configuration values to override for | 
 |      *  downloading the message. | 
 |      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is | 
 |      *  broadcast when the message is downloaded, or the download is failed | 
 |      * The result code will be <code>Activity.RESULT_OK</code> for success | 
 |      * or one of these errors:<br> | 
 |      * <code>MMS_ERROR_UNSPECIFIED</code><br> | 
 |      * <code>MMS_ERROR_INVALID_APN</code><br> | 
 |      * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br> | 
 |      * <code>MMS_ERROR_HTTP_FAILURE</code><br> | 
 |      * <code>MMS_ERROR_IO_ERROR</code><br> | 
 |      * <code>MMS_ERROR_RETRY</code><br> | 
 |      * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br> | 
 |      * <code>MMS_ERROR_NO_DATA_NETWORK</code><br> | 
 |      * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br> | 
 |      * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br> | 
 |      * <code>MMS_ERROR_DATA_DISABLED</code><br> | 
 |      * @param messageId an id that uniquely identifies the message requested to be downloaded. | 
 |      * Used for logging and diagnostics purposes. The id may be 0. | 
 |      * @throws IllegalArgumentException if locationUrl or contentUri is empty | 
 |      */ | 
 |     public void downloadMultimediaMessage(@NonNull Context context, @NonNull String locationUrl, | 
 |             @NonNull Uri contentUri, | 
 |             @SuppressWarnings("NullableCollection") @Nullable Bundle configOverrides, | 
 |             @Nullable PendingIntent downloadedIntent, long messageId) { | 
 |         if (TextUtils.isEmpty(locationUrl)) { | 
 |             throw new IllegalArgumentException("Empty MMS location URL"); | 
 |         } | 
 |         if (contentUri == null) { | 
 |             throw new IllegalArgumentException("Uri contentUri null"); | 
 |         } | 
 |         MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE); | 
 |         if (m != null) { | 
 |             resolveSubscriptionForOperation(new SubscriptionResolverResult() { | 
 |                 @Override | 
 |                 public void onSuccess(int subId) { | 
 |                     m.downloadMultimediaMessage(subId, locationUrl, contentUri, configOverrides, | 
 |                             downloadedIntent, messageId); | 
 |                 } | 
 |  | 
 |                 @Override | 
 |                 public void onFailure() { | 
 |                     notifySmsError(downloadedIntent, RESULT_NO_DEFAULT_SMS_APP); | 
 |                 } | 
 |             }); | 
 |         } | 
 |     } | 
 |  | 
 |     // MMS send/download failure result codes | 
 |  | 
 |     /** | 
 |      * Unspecific MMS error occurred during send/download. | 
 |      */ | 
 |     public static final int MMS_ERROR_UNSPECIFIED = 1; | 
 |  | 
 |     /** | 
 |      * ApnException occurred during MMS network setup. | 
 |      */ | 
 |     public static final int MMS_ERROR_INVALID_APN = 2; | 
 |  | 
 |     /** | 
 |      * An error occurred during the MMS connection setup. | 
 |      */ | 
 |     public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; | 
 |  | 
 |     /** | 
 |      * An error occurred during the HTTP client setup. | 
 |      */ | 
 |     public static final int MMS_ERROR_HTTP_FAILURE = 4; | 
 |  | 
 |     /** | 
 |      * An I/O error occurred reading the PDU. | 
 |      */ | 
 |     public static final int MMS_ERROR_IO_ERROR = 5; | 
 |  | 
 |     /** | 
 |      * An error occurred while retrying sending/downloading the MMS. | 
 |      */ | 
 |     public static final int MMS_ERROR_RETRY = 6; | 
 |  | 
 |     /** | 
 |      * The carrier-dependent configuration values could not be loaded. | 
 |      */ | 
 |     public static final int MMS_ERROR_CONFIGURATION_ERROR = 7; | 
 |  | 
 |     /** | 
 |      * There is no data network. | 
 |      */ | 
 |     public static final int MMS_ERROR_NO_DATA_NETWORK = 8; | 
 |  | 
 |     /** | 
 |      * The subscription id for the send/download is invalid. | 
 |      */ | 
 |     public static final int MMS_ERROR_INVALID_SUBSCRIPTION_ID = 9; | 
 |  | 
 |     /** | 
 |      * The subscription id for the send/download is inactive. | 
 |      */ | 
 |     public static final int MMS_ERROR_INACTIVE_SUBSCRIPTION = 10; | 
 |  | 
 |     /** | 
 |      * Data is disabled for the MMS APN. | 
 |      */ | 
 |     public static final int MMS_ERROR_DATA_DISABLED = 11; | 
 |  | 
 |     /** Intent extra name for MMS sending result data in byte array type */ | 
 |     public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA"; | 
 |     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */ | 
 |     public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS"; | 
 |  | 
 |     /** | 
 |      * Get carrier-dependent MMS configuration values. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation dialog. | 
 |      * If this method is called on a device that has multiple active subscriptions, this {@link | 
 |      * SmsManager} instance has been created with {@link #getDefault()}, and no user-defined default | 
 |      * subscription is defined, the subscription ID associated with this message will be INVALID, | 
 |      * which will result in the operation being completed on the subscription associated with | 
 |      * logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation is | 
 |      * performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @return the bundle key/values pairs that contains MMS configuration values | 
 |      *  or an empty Bundle if they cannot be found. | 
 |      */ | 
 |     @NonNull public Bundle getCarrierConfigValues() { | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 return iSms.getCarrierConfigValuesForSubscriber(getSubscriptionId()); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             // ignore it | 
 |         } | 
 |         return new Bundle(); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Create a single use app specific incoming SMS request for the calling package. | 
 |      * | 
 |      * This method returns a token that if included in a subsequent incoming SMS message will cause | 
 |      * {@code intent} to be sent with the SMS data. | 
 |      * | 
 |      * The token is only good for one use, after an SMS has been received containing the token all | 
 |      * subsequent SMS messages with the token will be routed as normal. | 
 |      * | 
 |      * An app can only have one request at a time, if the app already has a request pending it will | 
 |      * be replaced with a new request. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @return Token to include in an SMS message. The token will be 11 characters long. | 
 |      * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent | 
 |      */ | 
 |     public String createAppSpecificSmsToken(PendingIntent intent) { | 
 |         try { | 
 |             ISms iccSms = getISmsServiceOrThrow(); | 
 |             return iccSms.createAppSpecificSmsToken(getSubscriptionId(), | 
 |                     null, intent); | 
 |  | 
 |         } catch (RemoteException ex) { | 
 |             ex.rethrowFromSystemServer(); | 
 |             return null; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * callback for providing asynchronous sms messages for financial app. | 
 |      */ | 
 |     public abstract static class FinancialSmsCallback { | 
 |         /** | 
 |          * Callback to send sms messages back to financial app asynchronously. | 
 |          * | 
 |          * @param msgs SMS messages. | 
 |          */ | 
 |         public abstract void onFinancialSmsMessages(CursorWindow msgs); | 
 |     }; | 
 |  | 
 |     /** | 
 |      * Get SMS messages for the calling financial app. | 
 |      * The result will be delivered asynchronously in the passing in callback interface. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param params the parameters to filter SMS messages returned. | 
 |      * @param executor the executor on which callback will be invoked. | 
 |      * @param callback a callback to receive CursorWindow with SMS messages. | 
 |      * | 
 |      */ | 
 |     @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) | 
 |     public void getSmsMessagesForFinancialApp( | 
 |             Bundle params, | 
 |             @NonNull @CallbackExecutor Executor executor, | 
 |             @NonNull FinancialSmsCallback callback) { | 
 |         // This API is not functional and thus removed to avoid future confusion. | 
 |     } | 
 |  | 
 |     /** | 
 |      * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent). | 
 |      * The prefixes is a list of prefix {@code String} separated by this delimiter. | 
 |      * @hide | 
 |      */ | 
 |     public static final String REGEX_PREFIX_DELIMITER = ","; | 
 |     /** | 
 |      * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent). | 
 |      * The success status to be added into the intent to be sent to the calling package. | 
 |      * @hide | 
 |      */ | 
 |     public static final int RESULT_STATUS_SUCCESS = 0; | 
 |     /** | 
 |      * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent). | 
 |      * The timeout status to be added into the intent to be sent to the calling package. | 
 |      * @hide | 
 |      */ | 
 |     public static final int RESULT_STATUS_TIMEOUT = 1; | 
 |     /** | 
 |      * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent). | 
 |      * Intent extra key of the retrieved SMS message as a {@code String}. | 
 |      * @hide | 
 |      */ | 
 |     public static final String EXTRA_SMS_MESSAGE = "android.telephony.extra.SMS_MESSAGE"; | 
 |     /** | 
 |      * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent). | 
 |      * Intent extra key of SMS retriever status, which indicates whether the request for the | 
 |      * coming SMS message is SUCCESS or TIMEOUT | 
 |      * @hide | 
 |      */ | 
 |     public static final String EXTRA_STATUS = "android.telephony.extra.STATUS"; | 
 |     /** | 
 |      * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent). | 
 |      * [Optional] Intent extra key of the retrieved Sim card subscription Id if any. {@code int} | 
 |      * @hide | 
 |      */ | 
 |     public static final String EXTRA_SIM_SUBSCRIPTION_ID = | 
 |             "android.telephony.extra.SIM_SUBSCRIPTION_ID"; | 
 |  | 
 |     /** | 
 |      * Create a single use app specific incoming SMS request for the calling package. | 
 |      * | 
 |      * This method returns a token that if included in a subsequent incoming SMS message, and the | 
 |      * SMS message has a prefix from the given prefixes list, the provided {@code intent} will be | 
 |      * sent with the SMS data to the calling package. | 
 |      * | 
 |      * The token is only good for one use within a reasonable amount of time. After an SMS has been | 
 |      * received containing the token all subsequent SMS messages with the token will be routed as | 
 |      * normal. | 
 |      * | 
 |      * An app can only have one request at a time, if the app already has a request pending it will | 
 |      * be replaced with a new request. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param prefixes this is a list of prefixes string separated by REGEX_PREFIX_DELIMITER. The | 
 |      *  matching SMS message should have at least one of the prefixes in the beginning of the | 
 |      *  message. | 
 |      * @param intent this intent is sent when the matching SMS message is received. | 
 |      * @return Token to include in an SMS message. | 
 |      */ | 
 |     @Nullable | 
 |     public String createAppSpecificSmsTokenWithPackageInfo( | 
 |             @Nullable String prefixes, @NonNull PendingIntent intent) { | 
 |         try { | 
 |             ISms iccSms = getISmsServiceOrThrow(); | 
 |             return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(), | 
 |                     null, prefixes, intent); | 
 |  | 
 |         } catch (RemoteException ex) { | 
 |             ex.rethrowFromSystemServer(); | 
 |             return null; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Set Storage Availability in SmsStorageMonitor | 
 |      * @param storageAvailable storage availability to be set true or false | 
 |      * @hide | 
 |      */ | 
 |     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) | 
 |     @TestApi | 
 |     public void setStorageMonitorMemoryStatusOverride(boolean storageAvailable) { | 
 |         try { | 
 |             ISms iccISms = getISmsServiceOrThrow(); | 
 |             if (iccISms != null) { | 
 |                 iccISms.setStorageMonitorMemoryStatusOverride(getSubscriptionId(), | 
 |                                                                 storageAvailable); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             ex.rethrowFromSystemServer(); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Clear the memory status override set by | 
 |      * {@link #setStorageMonitorMemoryStatusOverride(boolean)} | 
 |      * @hide | 
 |      */ | 
 |     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) | 
 |     @TestApi | 
 |     public void clearStorageMonitorMemoryStatusOverride() { | 
 |         try { | 
 |             ISms iccISms = getISmsServiceOrThrow(); | 
 |             if (iccISms != null) { | 
 |                 iccISms.clearStorageMonitorMemoryStatusOverride(getSubscriptionId()); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             ex.rethrowFromSystemServer(); | 
 |         } | 
 |     } | 
 |  | 
 |     /** @hide */ | 
 |     @Retention(RetentionPolicy.SOURCE) | 
 |     @IntDef(prefix = {"SMS_CATEGORY_"}, | 
 |             value = { | 
 |                     SmsManager.SMS_CATEGORY_NOT_SHORT_CODE, | 
 |                     SmsManager.SMS_CATEGORY_FREE_SHORT_CODE, | 
 |                     SmsManager.SMS_CATEGORY_STANDARD_SHORT_CODE, | 
 |                     SmsManager.SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE, | 
 |                     SmsManager.SMS_CATEGORY_PREMIUM_SHORT_CODE}) | 
 |     public @interface SmsShortCodeCategory {} | 
 |  | 
 |     /** | 
 |      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for regular | 
 |      * phone numbers. | 
 |      * @hide | 
 |      */ | 
 |     @TestApi | 
 |     public static final int SMS_CATEGORY_NOT_SHORT_CODE = 0; | 
 |     /** | 
 |      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for free | 
 |      * (no cost) short codes. | 
 |      * @hide | 
 |      */ | 
 |     @TestApi | 
 |     public static final int SMS_CATEGORY_FREE_SHORT_CODE = 1; | 
 |     /** | 
 |      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for | 
 |      * standard rate (non-premium) | 
 |      * short codes. | 
 |      * @hide | 
 |      */ | 
 |     @TestApi | 
 |     public static final int SMS_CATEGORY_STANDARD_SHORT_CODE = 2; | 
 |     /** | 
 |      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for possible | 
 |      * premium short codes. | 
 |      * @hide | 
 |      */ | 
 |     @TestApi | 
 |     public static final int SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3; | 
 |     /** | 
 |      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for | 
 |      * premium short codes. | 
 |      * @hide | 
 |      */ | 
 |     @TestApi | 
 |     public static final int SMS_CATEGORY_PREMIUM_SHORT_CODE = 4; | 
 |  | 
 |     /** | 
 |      * Check if the destination address is a possible premium short code. | 
 |      * NOTE: the caller is expected to strip non-digits from the destination number with | 
 |      * {@link PhoneNumberUtils#extractNetworkPortion} before calling this method. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier | 
 |      * applications or the Telephony framework and will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this message will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the | 
 |      * operation is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param destAddress the destination address to test for possible short code | 
 |      * @param countryIso the ISO country code | 
 |      * | 
 |      * @return | 
 |      * {@link SmsManager#SMS_CATEGORY_NOT_SHORT_CODE}, | 
 |      * {@link SmsManager#SMS_CATEGORY_FREE_SHORT_CODE}, | 
 |      * {@link SmsManager#SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE}, | 
 |      * {@link SmsManager#SMS_CATEGORY_PREMIUM_SHORT_CODE}, or | 
 |      * {@link SmsManager#SMS_CATEGORY_STANDARD_SHORT_CODE} | 
 |      * | 
 |      * @hide | 
 |      */ | 
 |     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) | 
 |     @TestApi | 
 |     public @SmsShortCodeCategory int checkSmsShortCodeDestination( | 
 |             String destAddress, String countryIso) { | 
 |         try { | 
 |             ISms iccISms = getISmsServiceOrThrow(); | 
 |             if (iccISms != null) { | 
 |                 return iccISms.checkSmsShortCodeDestination(getSubscriptionId(), | 
 |                         null, null, destAddress, countryIso); | 
 |             } | 
 |         } catch (RemoteException e) { | 
 |             Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e); | 
 |         } | 
 |         return SmsManager.SMS_CATEGORY_NOT_SHORT_CODE; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Gets the SMSC address from (U)SIM. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Using this method requires that your app is the | 
 |      * default SMS application, or READ_PRIVILEGED_PHONE_STATE permission, or has the carrier | 
 |      * privileges.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this method will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation | 
 |      * is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @return the SMSC address string, null if failed. | 
 |      */ | 
 |     @SuppressAutoDoc // for carrier privileges and default SMS application. | 
 |     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) | 
 |     @Nullable | 
 |     public String getSmscAddress() { | 
 |         String smsc = null; | 
 |  | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 smsc = iSms.getSmscAddressFromIccEfForSubscriber( | 
 |                         getSubscriptionId(), null); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             throw new RuntimeException(ex); | 
 |         } | 
 |         return smsc; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets the SMSC address on (U)SIM. | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> Using this method requires that your app is the | 
 |      * default SMS application, or has {@link android.Manifest.permission#MODIFY_PHONE_STATE} | 
 |      * permission, or has the carrier privileges.</p> | 
 |      * | 
 |      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation | 
 |      * dialog. If this method is called on a device that has multiple active subscriptions, this | 
 |      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined | 
 |      * default subscription is defined, the subscription ID associated with this method will be | 
 |      * INVALID, which will result in the operation being completed on the subscription associated | 
 |      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation | 
 |      * is performed on the correct subscription. | 
 |      * </p> | 
 |      * | 
 |      * @param smsc the SMSC address string. | 
 |      * @return true for success, false otherwise. Failure can be due modem returning an error. | 
 |      */ | 
 |     @SuppressAutoDoc // for carrier privileges and default SMS application. | 
 |     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) | 
 |     public boolean setSmscAddress(@NonNull String smsc) { | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 return iSms.setSmscAddressOnIccEfForSubscriber( | 
 |                         smsc, getSubscriptionId(), null); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             throw new RuntimeException(ex); | 
 |         } | 
 |         return false; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Gets the premium SMS permission for the specified package. If the package has never | 
 |      * been seen before, the default {@link SmsManager#PREMIUM_SMS_CONSENT_UNKNOWN} | 
 |      * will be returned. | 
 |      * @param packageName the name of the package to query permission | 
 |      * @return one of {@link SmsManager#PREMIUM_SMS_CONSENT_UNKNOWN}, | 
 |      *  {@link SmsManager#PREMIUM_SMS_CONSENT_ASK_USER}, | 
 |      *  {@link SmsManager#PREMIUM_SMS_CONSENT_NEVER_ALLOW}, or | 
 |      *  {@link SmsManager#PREMIUM_SMS_CONSENT_ALWAYS_ALLOW} | 
 |      * @hide | 
 |      */ | 
 |     @SystemApi | 
 |     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) | 
 |     public @PremiumSmsConsent int getPremiumSmsConsent(@NonNull String packageName) { | 
 |         int permission = 0; | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 permission = iSms.getPremiumSmsPermission(packageName); | 
 |             } | 
 |         } catch (RemoteException e) { | 
 |             Log.e(TAG, "getPremiumSmsPermission() RemoteException", e); | 
 |         } | 
 |         return permission; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets the premium SMS permission for the specified package and save the value asynchronously | 
 |      * to persistent storage. | 
 |      * @param packageName the name of the package to set permission | 
 |      * @param permission one of {@link SmsManager#PREMIUM_SMS_CONSENT_ASK_USER}, | 
 |      *  {@link SmsManager#PREMIUM_SMS_CONSENT_NEVER_ALLOW}, or | 
 |      *  {@link SmsManager#PREMIUM_SMS_CONSENT_ALWAYS_ALLOW} | 
 |      * @hide | 
 |      */ | 
 |     @SystemApi | 
 |     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) | 
 |     public void setPremiumSmsConsent( | 
 |             @NonNull String packageName, @PremiumSmsConsent int permission) { | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 iSms.setPremiumSmsPermission(packageName, permission); | 
 |             } | 
 |         } catch (RemoteException e) { | 
 |             Log.e(TAG, "setPremiumSmsPermission() RemoteException", e); | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Reset all cell broadcast ranges. Previously enabled ranges will become invalid after this. | 
 |      * @deprecated Use {@link TelephonyManager#setCellBroadcastIdRanges} with empty list instead | 
 |      * @hide | 
 |      */ | 
 |     @Deprecated | 
 |     @SystemApi | 
 |     @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) | 
 |     public void resetAllCellBroadcastRanges() { | 
 |         try { | 
 |             ISms iSms = getISmsService(); | 
 |             if (iSms != null) { | 
 |                 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use | 
 |                 // the default phone internally. | 
 |                 iSms.resetAllCellBroadcastRanges(getSubscriptionId()); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             ex.rethrowFromSystemServer(); | 
 |         } | 
 |     } | 
 |  | 
 |     private static String formatCrossStackMessageId(long id) { | 
 |         return "{x-message-id:" + id + "}"; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Fetches the EF_PSISMSC value from the UICC that contains the Public Service Identity of | 
 |      * the SM-SC (either a SIP URI or tel URI). The EF_PSISMSC of ISIM and USIM can be found in | 
 |      * DF_TELECOM. | 
 |      * The EF_PSISMSC value is used by the ME to submit SMS over IP as defined in 24.341 [55]. | 
 |      * | 
 |      * @return Uri : Public Service Identity of SM-SC from the ISIM or USIM if the ISIM is not | 
 |      * available. | 
 |      * @throws SecurityException if the caller does not have the required permission/privileges. | 
 |      * @throws IllegalStateException in case of telephony service is not available. | 
 |      * @hide | 
 |      */ | 
 |     @NonNull | 
 |     @SystemApi | 
 |     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) | 
 |     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) | 
 |     public Uri getSmscIdentity() { | 
 |         Uri smscUri = Uri.EMPTY; | 
 |         try { | 
 |             IPhoneSubInfo info = TelephonyManager.getSubscriberInfoService(); | 
 |             if (info == null) { | 
 |                 Rlog.e(TAG, "getSmscIdentity(): IPhoneSubInfo instance is NULL"); | 
 |                 throw new IllegalStateException("Telephony service is not available"); | 
 |             } | 
 |             /** Fetches the SIM EF_PSISMSC value based on subId and appType */ | 
 |             smscUri = info.getSmscIdentity(getSubscriptionId(), TelephonyManager.APPTYPE_ISIM); | 
 |             if (Uri.EMPTY.equals(smscUri)) { | 
 |                 /** Fallback in case where ISIM is not available */ | 
 |                 smscUri = info.getSmscIdentity(getSubscriptionId(), TelephonyManager.APPTYPE_USIM); | 
 |             } | 
 |         } catch (RemoteException ex) { | 
 |             Rlog.e(TAG, "getSmscIdentity(): Exception : " + ex); | 
 |             ex.rethrowAsRuntimeException(); | 
 |         } | 
 |         return smscUri; | 
 |     } | 
 | } |