/* * 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.FlaggedApi; 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.internal.telephony.flags.Flags; 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. * *
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 Note: Using this method requires that your app has the
* {@link android.Manifest.permission#SEND_SMS} permission. Note: Beginning with Android 4.4 (API level 19), if
* and only if 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}. Note: 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.
* Note: 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.
*
* The message will be sent directly over the network and will not be visible in SMS
* applications. Intended for internal carrier use only.
* 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}).
* Note: 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.
* Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
* privileges per {@link android.telephony.TelephonyManager#hasCarrierPrivileges}.
*
* Note: 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.
* Note: Using this method requires that your app has the
* {@link android.Manifest.permission#SEND_SMS} permission. Note: Beginning with Android 4.4 (API level 19), if
* and only if 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}. Note: 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.
* Note: 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.
*
* 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.
* Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
* privileges.
* Note: Using this method requires that your app has the
* {@link android.Manifest.permission#SEND_SMS} permission. Note: Beginning with Android 4.4 (API level 19), if
* and only if 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}. Note: 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.
* Note: Using this method requires that your app has the
* {@link android.Manifest.permission#SEND_SMS} permission. Note: 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.
* Note: 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.
* Note: 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.
* Note: Constructing an {@link SmsManager} in this manner will
* never cause an SMS disambiguation dialog to appear, unlike {@link #getDefault()}.
* Note: Constructing an {@link SmsManager} in this manner will
* never cause an SMS disambiguation dialog to appear, unlike {@link #getDefault()}.
* Note: 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.
* 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.
*
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST} Note: 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.
* Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST} Note: 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.
* Note: 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.
* Note: 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.
* Note: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}.
*
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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.
*
*
* 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: 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.
* Note: Using this method requires that your app is the
* default SMS application, or READ_PRIVILEGED_PHONE_STATE permission, or has the carrier
* privileges. Note: 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.
* Note: 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. Note: 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.
* PendingIntent
is
* broadcast when the message is successfully sent, or failed.
* The result code will be Activity.RESULT_OK
for success,
* or one of these errors:
* 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_ENCODING_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_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
* For RESULT_ERROR_GENERIC_FAILURE
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.
* @param deliveryIntent if not NULL this PendingIntent
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
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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.
*
* PendingIntent
is
* broadcast when the message is successfully sent, or failed.
* The result code will be Activity.RESULT_OK
for success,
* or one of these errors:
* 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_ENCODING_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_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
* For RESULT_ERROR_GENERIC_FAILURE
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.
* @param deliveryIntent if not NULL this PendingIntent
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.
*
* PendingIntent
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.
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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 ArrayList
of strings that, in order, comprise the original message.
* @throws IllegalArgumentException if text is null.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
public ArrayListdivideMessage
.
*
* ArrayList
of strings that, in order,
* comprise the original message
* @param sentIntents if not null, an ArrayList
of
* PendingIntent
s (one for each message part) that is
* broadcast when the corresponding message part has been sent.
* The result code will be Activity.RESULT_OK
for success,
* or one of these errors:
* 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_ENCODING_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_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
* For RESULT_ERROR_GENERIC_FAILURE
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.
* @param deliveryIntents if not null, an ArrayList
of
* PendingIntent
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
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
public void sendMultipartTextMessage(
String destinationAddress, String scAddress, ArrayListdivideMessage
.
*
* ArrayList
of strings that, in order,
* comprise the original message
* @param sentIntents if not null, an ArrayList
of
* PendingIntent
s (one for each message part) that is
* broadcast when the corresponding message part has been sent.
* The result code will be Activity.RESULT_OK
for success,
* or one of these errors:
* 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_ENCODING_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_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
* For RESULT_ERROR_GENERIC_FAILURE
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.
* @param deliveryIntents if not null, an ArrayList
of
* PendingIntent
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, ArrayListPendingIntent
is
* broadcast when the message is successfully sent, or failed.
* The result code will be Activity.RESULT_OK
for success,
* or one of these errors:
* 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_ENCODING_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_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
* For RESULT_ERROR_GENERIC_FAILURE
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.
* @param deliveryIntent if not NULL this PendingIntent
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
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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, getAttributionTag(), 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.
*
* STATUS_ON_ICC_READ
* STATUS_ON_ICC_UNREAD
* STATUS_ON_ICC_SENT
* STATUS_ON_ICC_UNSENT
* @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.
*
* List
of SmsMessage
objects for valid records only.
*
* {@hide}
*/
@RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC)
public @NonNull ListArrayList
of SmsMessage
objects
*
* This is similar to {@link #getMessagesFromIcc} except that it will return ArrayList.
* Suggested to use {@link #getMessagesFromIcc} instead.
*
* {@hide}
*/
@UnsupportedAppUsage
public ArrayListSmsMessage
s from a list of SmsRawData records.
*
* ArrayList
of SmsMessage
objects.
*/
private ArrayListPendingIntent
is
* broadcast when the message is successfully sent, or failed
* The result code will be Activity.RESULT_OK
for success
* or one of these errors:
* MMS_ERROR_UNSPECIFIED
* MMS_ERROR_INVALID_APN
* MMS_ERROR_UNABLE_CONNECT_MMS
* MMS_ERROR_HTTP_FAILURE
* MMS_ERROR_IO_ERROR
* MMS_ERROR_RETRY
* MMS_ERROR_CONFIGURATION_ERROR
* MMS_ERROR_NO_DATA_NETWORK
* MMS_ERROR_INVALID_SUBSCRIPTION_ID
* MMS_ERROR_INACTIVE_SUBSCRIPTION
* MMS_ERROR_DATA_DISABLED
* MMS_ERROR_MMS_DISABLED_BY_CARRIER
* @throws IllegalArgumentException if contentUri is empty
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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.
* PendingIntent
is
* broadcast when the message is successfully sent, or failed
* The result code will be Activity.RESULT_OK
for success
* or one of these errors:
* MMS_ERROR_UNSPECIFIED
* MMS_ERROR_INVALID_APN
* MMS_ERROR_UNABLE_CONNECT_MMS
* MMS_ERROR_HTTP_FAILURE
* MMS_ERROR_IO_ERROR
* MMS_ERROR_RETRY
* MMS_ERROR_CONFIGURATION_ERROR
* MMS_ERROR_NO_DATA_NETWORK
* MMS_ERROR_INVALID_SUBSCRIPTION_ID
* MMS_ERROR_INACTIVE_SUBSCRIPTION
* MMS_ERROR_DATA_DISABLED
* MMS_ERROR_MMS_DISABLED_BY_CARRIER
* @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
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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
*
* PendingIntent
is
* broadcast when the message is downloaded, or the download is failed
* The result code will be Activity.RESULT_OK
for success
* or one of these errors:
* MMS_ERROR_UNSPECIFIED
* MMS_ERROR_INVALID_APN
* MMS_ERROR_UNABLE_CONNECT_MMS
* MMS_ERROR_HTTP_FAILURE
* MMS_ERROR_IO_ERROR
* MMS_ERROR_RETRY
* MMS_ERROR_CONFIGURATION_ERROR
* MMS_ERROR_NO_DATA_NETWORK
* MMS_ERROR_INVALID_SUBSCRIPTION_ID
* MMS_ERROR_INACTIVE_SUBSCRIPTION
* MMS_ERROR_DATA_DISABLED
* MMS_ERROR_MMS_DISABLED_BY_CARRIER
* @throws IllegalArgumentException if locationUrl or contentUri is empty
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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.
* PendingIntent
is
* broadcast when the message is downloaded, or the download is failed
* The result code will be Activity.RESULT_OK
for success
* or one of these errors:
* MMS_ERROR_UNSPECIFIED
* MMS_ERROR_INVALID_APN
* MMS_ERROR_UNABLE_CONNECT_MMS
* MMS_ERROR_HTTP_FAILURE
* MMS_ERROR_IO_ERROR
* MMS_ERROR_RETRY
* MMS_ERROR_CONFIGURATION_ERROR
* MMS_ERROR_NO_DATA_NETWORK
* MMS_ERROR_INVALID_SUBSCRIPTION_ID
* MMS_ERROR_INACTIVE_SUBSCRIPTION
* MMS_ERROR_DATA_DISABLED
* MMS_ERROR_MMS_DISABLED_BY_CARRIER
* @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
* @throws UnsupportedOperationException If the device does not have
* {@link PackageManager#FEATURE_TELEPHONY_MESSAGING}.
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
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 neither Wi-Fi nor mobile 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;
/**
* MMS is disabled by a carrier.
*/
@FlaggedApi(Flags.FLAG_MMS_DISABLED_ERROR)
public static final int MMS_ERROR_MMS_DISABLED_BY_CARRIER = 12;
/**
* The MMS pdu was too large to send or too large to download over the current connection.
* @hide
*/
public static final int MMS_ERROR_TOO_LARGE_FOR_TRANSPORT = 13;
/** 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.
*
*