1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.telephony;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SuppressAutoDoc;
25 import android.annotation.SystemApi;
26 import android.annotation.TestApi;
27 import android.annotation.UnsupportedAppUsage;
28 import android.app.ActivityThread;
29 import android.app.PendingIntent;
30 import android.content.ContentValues;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.pm.PackageManager;
34 import android.database.CursorWindow;
35 import android.net.Uri;
36 import android.os.BaseBundle;
37 import android.os.Binder;
38 import android.os.Build;
39 import android.os.Bundle;
40 import android.os.RemoteException;
41 import android.os.ServiceManager;
42 import android.provider.Telephony;
43 import android.text.TextUtils;
44 import android.util.ArrayMap;
45 import android.util.Log;
46 
47 import com.android.internal.telephony.IIntegerConsumer;
48 import com.android.internal.telephony.IMms;
49 import com.android.internal.telephony.ISms;
50 import com.android.internal.telephony.ITelephony;
51 import com.android.internal.telephony.SmsRawData;
52 
53 import java.lang.annotation.Retention;
54 import java.lang.annotation.RetentionPolicy;
55 import java.util.ArrayList;
56 import java.util.Arrays;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.concurrent.Executor;
60 
61 /*
62  * TODO(code review): Curious question... Why are a lot of these
63  * methods not declared as static, since they do not seem to require
64  * any local object state?  Presumably this cannot be changed without
65  * interfering with the API...
66  */
67 
68 /**
69  * Manages SMS operations such as sending data, text, and pdu SMS messages.
70  * Get this object by calling the static method {@link #getDefault()}. To create an instance of
71  * {@link SmsManager} associated with a specific subscription ID, call
72  * {@link #getSmsManagerForSubscriptionId(int)}. This is typically used for devices that support
73  * multiple active subscriptions at once.
74  *
75  * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19)
76  * and higher, see {@link android.provider.Telephony}.
77  *
78  * @see SubscriptionManager#getActiveSubscriptionInfoList()
79  */
80 public final class SmsManager {
81     private static final String TAG = "SmsManager";
82 
83     /** Singleton object constructed during class initialization. */
84     private static final SmsManager sInstance = new SmsManager(
85             SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
86     private static final Object sLockObject = new Object();
87 
88     /** @hide */
89     public static final int CELL_BROADCAST_RAN_TYPE_GSM = 0;
90     /** @hide */
91     public static final int CELL_BROADCAST_RAN_TYPE_CDMA = 1;
92 
93     /** SMS record length from TS 51.011 10.5.3
94      * @hide
95      */
96     public static final int SMS_RECORD_LENGTH = 176;
97 
98     /** SMS record length from C.S0023 3.4.27
99      * @hide
100      */
101     public static final int CDMA_SMS_RECORD_LENGTH = 255;
102 
103     private static final Map<Integer, SmsManager> sSubInstances =
104             new ArrayMap<Integer, SmsManager>();
105 
106     /** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */
107     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
108     private int mSubId;
109 
110     /*
111      * Key for the various carrier-dependent configuration values.
112      * Some of the values are used by the system in processing SMS or MMS messages. Others
113      * are provided for the convenience of SMS applications.
114      */
115 
116     /**
117      * Whether to append transaction id to MMS WAP Push M-Notification.ind's content location URI
118      * when constructing the download URL of a new MMS (boolean type)
119      */
120     public static final String MMS_CONFIG_APPEND_TRANSACTION_ID =
121             CarrierConfigManager.KEY_MMS_APPEND_TRANSACTION_ID_BOOL;
122     /**
123      * Whether MMS is enabled for the current carrier (boolean type)
124      */
125     public static final String
126             MMS_CONFIG_MMS_ENABLED = CarrierConfigManager.KEY_MMS_MMS_ENABLED_BOOL;
127     /**
128      * Whether group MMS is enabled for the current carrier (boolean type)
129      */
130     public static final String
131             MMS_CONFIG_GROUP_MMS_ENABLED = CarrierConfigManager.KEY_MMS_GROUP_MMS_ENABLED_BOOL;
132     /**
133      * If this is enabled, M-NotifyResp.ind should be sent to the WAP Push content location instead
134      * of the default MMSC (boolean type)
135      */
136     public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED =
137             CarrierConfigManager.KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL;
138     /**
139      * Whether alias is enabled (boolean type)
140      */
141     public static final String
142             MMS_CONFIG_ALIAS_ENABLED = CarrierConfigManager.KEY_MMS_ALIAS_ENABLED_BOOL;
143     /**
144      * Whether audio is allowed to be attached for MMS messages (boolean type)
145      */
146     public static final String
147             MMS_CONFIG_ALLOW_ATTACH_AUDIO = CarrierConfigManager.KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL;
148     /**
149      * Whether multipart SMS is enabled (boolean type)
150      */
151     public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED =
152             CarrierConfigManager.KEY_MMS_MULTIPART_SMS_ENABLED_BOOL;
153     /**
154      * Whether SMS delivery report is enabled (boolean type)
155      */
156     public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED =
157             CarrierConfigManager.KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL;
158     /**
159      * Whether content-disposition field should be expected in an MMS PDU (boolean type)
160      */
161     public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION =
162             CarrierConfigManager.KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL;
163     /**
164      * Whether multipart SMS should be sent as separate messages
165      */
166     public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES =
167             CarrierConfigManager.KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL;
168     /**
169      * Whether MMS read report is enabled (boolean type)
170      */
171     public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED =
172             CarrierConfigManager.KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL;
173     /**
174      * Whether MMS delivery report is enabled (boolean type)
175      */
176     public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED =
177             CarrierConfigManager.KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL;
178     /**
179      * Max MMS message size in bytes (int type)
180      */
181     public static final String
182             MMS_CONFIG_MAX_MESSAGE_SIZE = CarrierConfigManager.KEY_MMS_MAX_MESSAGE_SIZE_INT;
183     /**
184      * Max MMS image width (int type)
185      */
186     public static final String
187             MMS_CONFIG_MAX_IMAGE_WIDTH = CarrierConfigManager.KEY_MMS_MAX_IMAGE_WIDTH_INT;
188     /**
189      * Max MMS image height (int type)
190      */
191     public static final String
192             MMS_CONFIG_MAX_IMAGE_HEIGHT = CarrierConfigManager.KEY_MMS_MAX_IMAGE_HEIGHT_INT;
193     /**
194      * Limit of recipients of MMS messages (int type)
195      */
196     public static final String
197             MMS_CONFIG_RECIPIENT_LIMIT = CarrierConfigManager.KEY_MMS_RECIPIENT_LIMIT_INT;
198     /**
199      * Min alias character count (int type)
200      */
201     public static final String
202             MMS_CONFIG_ALIAS_MIN_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MIN_CHARS_INT;
203     /**
204      * Max alias character count (int type)
205      */
206     public static final String
207             MMS_CONFIG_ALIAS_MAX_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MAX_CHARS_INT;
208     /**
209      * When the number of parts of a multipart SMS reaches this threshold, it should be converted
210      * into an MMS (int type)
211      */
212     public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD =
213             CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT;
214     /**
215      * Some carriers require SMS to be converted into MMS when text length reaches this threshold
216      * (int type)
217      */
218     public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD =
219             CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT;
220     /**
221      * Max message text size (int type)
222      */
223     public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE =
224             CarrierConfigManager.KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT;
225     /**
226      * Max message subject length (int type)
227      */
228     public static final String
229             MMS_CONFIG_SUBJECT_MAX_LENGTH = CarrierConfigManager.KEY_MMS_SUBJECT_MAX_LENGTH_INT;
230     /**
231      * MMS HTTP socket timeout in milliseconds (int type)
232      */
233     public static final String
234             MMS_CONFIG_HTTP_SOCKET_TIMEOUT = CarrierConfigManager.KEY_MMS_HTTP_SOCKET_TIMEOUT_INT;
235     /**
236      * The name of the UA Prof URL HTTP header for MMS HTTP request (String type)
237      */
238     public static final String
239             MMS_CONFIG_UA_PROF_TAG_NAME = CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING;
240     /**
241      * The User-Agent header value for MMS HTTP request (String type)
242      */
243     public static final String
244             MMS_CONFIG_USER_AGENT = CarrierConfigManager.KEY_MMS_USER_AGENT_STRING;
245     /**
246      * The UA Profile URL header value for MMS HTTP request (String type)
247      */
248     public static final String
249             MMS_CONFIG_UA_PROF_URL = CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING;
250     /**
251      * A list of HTTP headers to add to MMS HTTP request, separated by "|" (String type)
252      */
253     public static final String
254             MMS_CONFIG_HTTP_PARAMS = CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING;
255     /**
256      * Email gateway number (String type)
257      */
258     public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER =
259             CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING;
260     /**
261      * The suffix to append to the NAI header value for MMS HTTP request (String type)
262      */
263     public static final String
264             MMS_CONFIG_NAI_SUFFIX = CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING;
265     /**
266      * If true, show the cell broadcast (amber alert) in the SMS settings. Some carriers don't want
267      * this shown. (Boolean type)
268      */
269     public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS =
270             CarrierConfigManager.KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL;
271     /**
272      * Whether the carrier MMSC supports charset field in Content-Type header. If this is false,
273      * then we don't add "charset" to "Content-Type"
274      */
275     public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER =
276             CarrierConfigManager.KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL;
277     /**
278      * If true, add "Connection: close" header to MMS HTTP requests so the connection
279      * is immediately closed (disabling keep-alive). (Boolean type)
280      * @hide
281      */
282     public static final String MMS_CONFIG_CLOSE_CONNECTION =
283             CarrierConfigManager.KEY_MMS_CLOSE_CONNECTION_BOOL;
284 
285     /**
286      * 3gpp2 SMS priority is not specified
287      * @hide
288      */
289     public static final int SMS_MESSAGE_PRIORITY_NOT_SPECIFIED = -1;
290     /**
291      * 3gpp SMS period is not specified
292      * @hide
293      */
294     public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1;
295 
296     /**
297      * Extra key passed into a PendingIntent when the SMS operation failed due to there being no
298      * default set.
299      */
300     private static final String NO_DEFAULT_EXTRA = "noDefault";
301 
302     // result of asking the user for a subscription to perform an operation.
303     private interface SubscriptionResolverResult {
onSuccess(int subId)304         void onSuccess(int subId);
onFailure()305         void onFailure();
306     }
307 
308     /**
309      * Send a text based SMS.
310      *
311      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
312      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
313      *
314      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
315      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
316      * writes messages sent using this method to the SMS Provider (the default SMS app is always
317      * responsible for writing its sent messages to the SMS Provider). For information about
318      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
319      *
320      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
321      * manager on a multi-SIM device, this operation may fail sending the SMS message because no
322      * suitable default subscription could be found. In this case, if {@code sentIntent} is
323      * non-null, then the {@link PendingIntent} will be sent with an error code
324      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
325      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
326      * where this operation may fail.
327      * </p>
328      *
329      *
330      * @param destinationAddress the address to send the message to
331      * @param scAddress is the service center address or null to use
332      *  the current default SMSC
333      * @param text the body of the message to send
334      * @param sentIntent if not NULL this <code>PendingIntent</code> is
335      *  broadcast when the message is successfully sent, or failed.
336      *  The result code will be <code>Activity.RESULT_OK</code> for success,
337      *  or one of these errors:<br>
338      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
339      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
340      *  <code>RESULT_ERROR_NULL_PDU</code><br>
341      *  <code>RESULT_ERROR_NO_SERVICE</code><br>
342      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
343      *  the extra "errorCode" containing a radio technology specific value,
344      *  generally only useful for troubleshooting.<br>
345      *  The per-application based SMS control checks sentIntent. If sentIntent
346      *  is NULL the caller will be checked against all unknown applications,
347      *  which cause smaller number of SMS to be sent in checking period.
348      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
349      *  broadcast when the message is delivered to the recipient.  The
350      *  raw pdu of the status report is in the extended data ("pdu").
351      *
352      * @throws IllegalArgumentException if destinationAddress or text are empty
353      */
sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)354     public void sendTextMessage(
355             String destinationAddress, String scAddress, String text,
356             PendingIntent sentIntent, PendingIntent deliveryIntent) {
357         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
358                 true /* persistMessage*/, ActivityThread.currentPackageName());
359     }
360 
sendTextMessageInternal(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, String packageName)361     private void sendTextMessageInternal(String destinationAddress, String scAddress,
362             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
363             boolean persistMessage, String packageName) {
364         if (TextUtils.isEmpty(destinationAddress)) {
365             throw new IllegalArgumentException("Invalid destinationAddress");
366         }
367 
368         if (TextUtils.isEmpty(text)) {
369             throw new IllegalArgumentException("Invalid message body");
370         }
371 
372         final Context context = ActivityThread.currentApplication().getApplicationContext();
373         // We will only show the SMS disambiguation dialog in the case that the message is being
374         // persisted. This is for two reasons:
375         // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific
376         //    subscription and require special permissions. These messages are usually not sent by
377         //    the device user and should not have an SMS disambiguation dialog associated with them
378         //    because the device user did not trigger them.
379         // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the SEND_SMS
380         //    permission. If we call resolveSubscriptionForOperation from a carrier/OEM app that has
381         //    the correct MODIFY_PHONE_STATE or carrier permissions, but no SEND_SMS, it will throw
382         //    an incorrect SecurityException.
383         if (persistMessage) {
384             resolveSubscriptionForOperation(new SubscriptionResolverResult() {
385                 @Override
386                 public void onSuccess(int subId) {
387                     ISms iSms = getISmsServiceOrThrow();
388                     try {
389                         iSms.sendTextForSubscriber(subId, packageName,
390                                 destinationAddress, scAddress, text, sentIntent, deliveryIntent,
391                                 persistMessage);
392                     } catch (RemoteException e) {
393                         Log.e(TAG, "sendTextMessageInternal: Couldn't send SMS, exception - "
394                                 + e.getMessage());
395                         notifySmsGenericError(sentIntent);
396                     }
397                 }
398 
399                 @Override
400                 public void onFailure() {
401                     notifySmsErrorNoDefaultSet(context, sentIntent);
402                 }
403             });
404         } else {
405             // Not persisting the message, used by sendTextMessageWithoutPersisting() and is not
406             // visible to the user.
407             ISms iSms = getISmsServiceOrThrow();
408             try {
409                 iSms.sendTextForSubscriber(getSubscriptionId(), packageName,
410                         destinationAddress, scAddress, text, sentIntent, deliveryIntent,
411                         persistMessage);
412             } catch (RemoteException e) {
413                 Log.e(TAG, "sendTextMessageInternal (no persist): Couldn't send SMS, exception - "
414                         + e.getMessage());
415                 notifySmsGenericError(sentIntent);
416             }
417         }
418     }
419 
420     /**
421      * Send a text based SMS without writing it into the SMS Provider.
422      *
423      * <p>
424      * The message will be sent directly over the network and will not be visible in SMS
425      * applications. Intended for internal carrier use only.
426      * </p>
427      *
428      * <p>Requires Permission: Both {@link android.Manifest.permission#SEND_SMS} and
429      * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or that the calling app has carrier
430      * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), or that the calling app is
431      * the default IMS app (see
432      * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}).
433      * </p>
434      *
435      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
436      * applications or the Telephony framework and will never trigger an SMS disambiguation
437      * dialog. If this method is called on a device that has multiple active subscriptions, this
438      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
439      * default subscription is defined, the subscription ID associated with this message will be
440      * INVALID, which will result in the SMS being sent on the subscription associated with logical
441      * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
442      * correct subscription.
443      * </p>
444      *
445      * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent)
446      */
447     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
448     @RequiresPermission(allOf = {
449             android.Manifest.permission.MODIFY_PHONE_STATE,
450             android.Manifest.permission.SEND_SMS
451     })
sendTextMessageWithoutPersisting( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)452     public void sendTextMessageWithoutPersisting(
453             String destinationAddress, String scAddress, String text,
454             PendingIntent sentIntent, PendingIntent deliveryIntent) {
455         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
456                 false /* persistMessage */, ActivityThread.currentPackageName());
457     }
458 
459     /**
460      * A variant of {@link SmsManager#sendTextMessage} that allows self to be the caller. This is
461      * for internal use only.
462      *
463      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
464      * applications or the Telephony framework and will never trigger an SMS disambiguation
465      * dialog. If this method is called on a device that has multiple active subscriptions, this
466      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
467      * default subscription is defined, the subscription ID associated with this message will be
468      * INVALID, which will result in the SMS being sent on the subscription associated with logical
469      * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
470      * correct subscription.
471      * </p>
472      *
473      * @param persistMessage whether to persist the sent message in the SMS app. the caller must be
474      * the Phone process if set to false.
475      *
476      * @hide
477      */
sendTextMessageWithSelfPermissions( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage)478     public void sendTextMessageWithSelfPermissions(
479             String destinationAddress, String scAddress, String text,
480             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage) {
481         if (TextUtils.isEmpty(destinationAddress)) {
482             throw new IllegalArgumentException("Invalid destinationAddress");
483         }
484 
485         if (TextUtils.isEmpty(text)) {
486             throw new IllegalArgumentException("Invalid message body");
487         }
488 
489         try {
490             ISms iSms = getISmsServiceOrThrow();
491             iSms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(),
492                     ActivityThread.currentPackageName(),
493                     destinationAddress,
494                     scAddress, text, sentIntent, deliveryIntent, persistMessage);
495         } catch (RemoteException ex) {
496             notifySmsGenericError(sentIntent);
497         }
498     }
499 
500     /**
501      * Send a text based SMS with messaging options.
502      *
503      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
504      * manager on a multi-SIM device, this operation may fail sending the SMS message because no
505      * suitable default subscription could be found. In this case, if {@code sentIntent} is
506      * non-null, then the {@link PendingIntent} will be sent with an error code
507      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
508      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
509      * where this operation may fail.
510      * </p>
511      *
512      * @param destinationAddress the address to send the message to
513      * @param scAddress is the service center address or null to use
514      *  the current default SMSC
515      * @param text the body of the message to send
516      * @param sentIntent if not NULL this <code>PendingIntent</code> is
517      *  broadcast when the message is successfully sent, or failed.
518      *  The result code will be <code>Activity.RESULT_OK</code> for success,
519      *  or one of these errors:<br>
520      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
521      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
522      *  <code>RESULT_ERROR_NULL_PDU</code><br>
523      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
524      *  the extra "errorCode" containing a radio technology specific value,
525      *  generally only useful for troubleshooting.<br>
526      *  The per-application based SMS control checks sentIntent. If sentIntent
527      *  is NULL the caller will be checked against all unknown applications,
528      *  which cause smaller number of SMS to be sent in checking period.
529      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
530      *  broadcast when the message is delivered to the recipient.  The
531      *  raw pdu of the status report is in the extended data ("pdu").
532      * @param priority Priority level of the message
533      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
534      *  ---------------------------------
535      *  PRIORITY      | Level of Priority
536      *  ---------------------------------
537      *      '00'      |     Normal
538      *      '01'      |     Interactive
539      *      '10'      |     Urgent
540      *      '11'      |     Emergency
541      *  ----------------------------------
542      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
543      * @param expectMore is a boolean to indicate the sending messages through same link or not.
544      * @param validityPeriod Validity Period of the message in mins.
545      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
546      *  Validity Period(Minimum) -> 5 mins
547      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
548      *  Any Other values included Negative considered as Invalid Validity Period of the message.
549      *
550      * @throws IllegalArgumentException if destinationAddress or text are empty
551      * {@hide}
552      */
553     @UnsupportedAppUsage
sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority, boolean expectMore, int validityPeriod)554     public void sendTextMessage(
555             String destinationAddress, String scAddress, String text,
556             PendingIntent sentIntent, PendingIntent deliveryIntent,
557             int priority, boolean expectMore, int validityPeriod) {
558         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
559                 true /* persistMessage*/, priority, expectMore, validityPeriod);
560     }
561 
sendTextMessageInternal( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, int priority, boolean expectMore, int validityPeriod)562     private void sendTextMessageInternal(
563             String destinationAddress, String scAddress, String text,
564             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage,
565             int priority, boolean expectMore, int validityPeriod) {
566         if (TextUtils.isEmpty(destinationAddress)) {
567             throw new IllegalArgumentException("Invalid destinationAddress");
568         }
569 
570         if (TextUtils.isEmpty(text)) {
571             throw new IllegalArgumentException("Invalid message body");
572         }
573 
574         if (priority < 0x00 || priority > 0x03) {
575             priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED;
576         }
577 
578         if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
579             validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED;
580         }
581 
582         final int finalPriority = priority;
583         final int finalValidity = validityPeriod;
584         final Context context = ActivityThread.currentApplication().getApplicationContext();
585         // We will only show the SMS disambiguation dialog in the case that the message is being
586         // persisted. This is for two reasons:
587         // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific
588         //    subscription and require special permissions. These messages are usually not sent by
589         //    the device user and should not have an SMS disambiguation dialog associated with them
590         //    because the device user did not trigger them.
591         // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the SEND_SMS
592         //    permission. If we call resolveSubscriptionForOperation from a carrier/OEM app that has
593         //    the correct MODIFY_PHONE_STATE or carrier permissions, but no SEND_SMS, it will throw
594         //    an incorrect SecurityException.
595         if (persistMessage) {
596             resolveSubscriptionForOperation(new SubscriptionResolverResult() {
597                 @Override
598                 public void onSuccess(int subId) {
599                     try {
600                         ISms iSms = getISmsServiceOrThrow();
601                         if (iSms != null) {
602                             iSms.sendTextForSubscriberWithOptions(subId,
603                                     ActivityThread.currentPackageName(), destinationAddress,
604                                     scAddress,
605                                     text, sentIntent, deliveryIntent, persistMessage, finalPriority,
606                                     expectMore, finalValidity);
607                         }
608                     } catch (RemoteException e) {
609                         Log.e(TAG, "sendTextMessageInternal: Couldn't send SMS, exception - "
610                                 + e.getMessage());
611                         notifySmsGenericError(sentIntent);
612                     }
613                 }
614 
615                 @Override
616                 public void onFailure() {
617                     notifySmsErrorNoDefaultSet(context, sentIntent);
618                 }
619             });
620         } else {
621             try {
622                 ISms iSms = getISmsServiceOrThrow();
623                 if (iSms != null) {
624                     iSms.sendTextForSubscriberWithOptions(getSubscriptionId(),
625                             ActivityThread.currentPackageName(), destinationAddress,
626                             scAddress,
627                             text, sentIntent, deliveryIntent, persistMessage, finalPriority,
628                             expectMore, finalValidity);
629                 }
630             } catch (RemoteException e) {
631                 Log.e(TAG, "sendTextMessageInternal(no persist): Couldn't send SMS, exception - "
632                         + e.getMessage());
633                 notifySmsGenericError(sentIntent);
634             }
635         }
636     }
637 
638     /**
639      * Send a text based SMS without writing it into the SMS Provider.
640      *
641      * <p>Requires Permission:
642      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
643      * privileges.
644      * </p>
645      *
646      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
647      * applications or the Telephony framework and will never trigger an SMS disambiguation
648      * dialog. If this method is called on a device that has multiple active subscriptions, this
649      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
650      * default subscription is defined, the subscription ID associated with this message will be
651      * INVALID, which will result in the SMS being sent on the subscription associated with logical
652      * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
653      * correct subscription.
654      * </p>
655      *
656      * @see #sendTextMessage(String, String, String, PendingIntent,
657      * PendingIntent, int, boolean, int)
658      * @hide
659      */
660     @UnsupportedAppUsage
sendTextMessageWithoutPersisting( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority, boolean expectMore, int validityPeriod)661     public void sendTextMessageWithoutPersisting(
662             String destinationAddress, String scAddress, String text,
663             PendingIntent sentIntent, PendingIntent deliveryIntent, int priority,
664             boolean expectMore, int validityPeriod) {
665         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
666                 false /* persistMessage */, priority, expectMore, validityPeriod);
667     }
668 
669     /**
670      *
671      * Inject an SMS PDU into the android application framework.
672      *
673      * <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
674      * privileges per {@link android.telephony.TelephonyManager#hasCarrierPrivileges}.
675      *
676      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
677      * applications or the Telephony framework and will never trigger an SMS disambiguation
678      * dialog. If this method is called on a device that has multiple active subscriptions, this
679      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
680      * default subscription is defined, the subscription ID associated with this message will be
681      * INVALID, which will result in the SMS being injected on the subscription associated with
682      * logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is
683      * delivered to the correct subscription.
684      * </p>
685      *
686      * @param pdu is the byte array of pdu to be injected into android application framework
687      * @param format is the format of SMS pdu ({@link SmsMessage#FORMAT_3GPP} or
688      *  {@link SmsMessage#FORMAT_3GPP2})
689      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
690      *  broadcast when the message is successfully received by the
691      *  android application framework, or failed. This intent is broadcasted at
692      *  the same time an SMS received from radio is acknowledged back.
693      *  The result code will be {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_HANDLED}
694      *  for success, or {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_GENERIC_ERROR} for
695      *  error.
696      *
697      * @throws IllegalArgumentException if the format is invalid.
698      */
injectSmsPdu( byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent)699     public void injectSmsPdu(
700             byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent) {
701         if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) {
702             // Format must be either 3gpp or 3gpp2.
703             throw new IllegalArgumentException(
704                     "Invalid pdu format. format must be either 3gpp or 3gpp2");
705         }
706         try {
707             ISms iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
708             if (iSms != null) {
709                 iSms.injectSmsPduForSubscriber(
710                         getSubscriptionId(), pdu, format, receivedIntent);
711             }
712         } catch (RemoteException ex) {
713             try {
714                 if (receivedIntent != null) {
715                     receivedIntent.send(Telephony.Sms.Intents.RESULT_SMS_GENERIC_ERROR);
716                 }
717             } catch (PendingIntent.CanceledException cx) {
718                 // Don't worry about it, we do not need to notify the caller if this is the case.
719             }
720         }
721     }
722 
723     /**
724      * Divide a message text into several fragments, none bigger than the maximum SMS message size.
725      *
726      * @param text the original message. Must not be null.
727      * @return an <code>ArrayList</code> of strings that, in order, comprise the original message.
728      * @throws IllegalArgumentException if text is null.
729      */
divideMessage(String text)730     public ArrayList<String> divideMessage(String text) {
731         if (null == text) {
732             throw new IllegalArgumentException("text is null");
733         }
734         return SmsMessage.fragmentText(text, getSubscriptionId());
735     }
736 
737     /**
738      * Send a multi-part text based SMS.  The callee should have already
739      * divided the message into correctly sized parts by calling
740      * <code>divideMessage</code>.
741      *
742      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
743      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
744      *
745      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
746      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
747      * writes messages sent using this method to the SMS Provider (the default SMS app is always
748      * responsible for writing its sent messages to the SMS Provider). For information about
749      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
750      *
751      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
752      * manager on a multi-SIM device, this operation may fail sending the SMS message because no
753      * suitable default subscription could be found. In this case, if {@code sentIntent} is
754      * non-null, then the {@link PendingIntent} will be sent with an error code
755      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
756      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
757      * where this operation may fail.
758      * </p>
759      *
760      *
761      * @param destinationAddress the address to send the message to
762      * @param scAddress is the service center address or null to use
763      *   the current default SMSC
764      * @param parts an <code>ArrayList</code> of strings that, in order,
765      *   comprise the original message
766      * @param sentIntents if not null, an <code>ArrayList</code> of
767      *   <code>PendingIntent</code>s (one for each message part) that is
768      *   broadcast when the corresponding message part has been sent.
769      *   The result code will be <code>Activity.RESULT_OK</code> for success,
770      *   or one of these errors:<br>
771      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
772      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
773      *   <code>RESULT_ERROR_NULL_PDU</code><br>
774      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
775      *   the extra "errorCode" containing a radio technology specific value,
776      *   generally only useful for troubleshooting.<br>
777      *   The per-application based SMS control checks sentIntent. If sentIntent
778      *   is NULL the caller will be checked against all unknown applications,
779      *   which cause smaller number of SMS to be sent in checking period.
780      * @param deliveryIntents if not null, an <code>ArrayList</code> of
781      *   <code>PendingIntent</code>s (one for each message part) that is
782      *   broadcast when the corresponding message part has been delivered
783      *   to the recipient.  The raw pdu of the status report is in the
784      *   extended data ("pdu").
785      *
786      * @throws IllegalArgumentException if destinationAddress or data are empty
787      */
sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)788     public void sendMultipartTextMessage(
789             String destinationAddress, String scAddress, ArrayList<String> parts,
790             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
791         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
792                 deliveryIntents, true /* persistMessage*/, ActivityThread.currentPackageName());
793     }
794 
795     /**
796      * Similar method as #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList)
797      * With an additional argument.
798      *
799      * <p class="note"><strong>Note:</strong> This method is intended for internal use the Telephony
800      * framework and will never trigger an SMS disambiguation dialog. If this method is called on a
801      * device that has multiple active subscriptions, this {@link SmsManager} instance has been
802      * created with {@link #getDefault()}, and no user-defined default subscription is defined, the
803      * subscription ID associated with this message will be INVALID, which will result in the SMS
804      * being sent on the subscription associated with logical slot 0. Use
805      * {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the correct
806      * subscription.
807      * </p>
808      *
809      * @param packageName serves as the default package name if
810      * {@link ActivityThread#currentPackageName()} is null.
811      * @hide
812      */
sendMultipartTextMessageExternal( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, String packageName)813     public void sendMultipartTextMessageExternal(
814             String destinationAddress, String scAddress, ArrayList<String> parts,
815             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
816             String packageName) {
817         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
818                 deliveryIntents, true /* persistMessage*/,
819                 ActivityThread.currentPackageName() == null
820                         ? packageName : ActivityThread.currentPackageName());
821     }
822 
sendMultipartTextMessageInternal( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessage, String packageName)823     private void sendMultipartTextMessageInternal(
824             String destinationAddress, String scAddress, List<String> parts,
825             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
826             boolean persistMessage, String packageName) {
827         if (TextUtils.isEmpty(destinationAddress)) {
828             throw new IllegalArgumentException("Invalid destinationAddress");
829         }
830         if (parts == null || parts.size() < 1) {
831             throw new IllegalArgumentException("Invalid message body");
832         }
833 
834         if (parts.size() > 1) {
835             final Context context = ActivityThread.currentApplication().getApplicationContext();
836             // We will only show the SMS disambiguation dialog in the case that the message is being
837             // persisted. This is for two reasons:
838             // 1) Messages that are not persisted are sent by carrier/OEM apps for a specific
839             //    subscription and require special permissions. These messages are usually not sent
840             //    by the device user and should not have an SMS disambiguation dialog associated
841             //    with them because the device user did not trigger them.
842             // 2) The SMS disambiguation dialog ONLY checks to make sure that the user has the
843             //    SEND_SMS permission. If we call resolveSubscriptionForOperation from a carrier/OEM
844             //    app that has the correct MODIFY_PHONE_STATE or carrier permissions, but no
845             //    SEND_SMS, it will throw an incorrect SecurityException.
846             if (persistMessage) {
847                 resolveSubscriptionForOperation(new SubscriptionResolverResult() {
848                     @Override
849                     public void onSuccess(int subId) {
850                         try {
851                             ISms iSms = getISmsServiceOrThrow();
852                             iSms.sendMultipartTextForSubscriber(subId, packageName,
853                                     destinationAddress, scAddress, parts, sentIntents,
854                                     deliveryIntents, persistMessage);
855                         } catch (RemoteException e) {
856                             Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - "
857                                     + e.getMessage());
858                             notifySmsGenericError(sentIntents);
859                         }
860                     }
861 
862                     @Override
863                     public void onFailure() {
864                         notifySmsErrorNoDefaultSet(context, sentIntents);
865                     }
866                 });
867             } else {
868                 // Called by apps that are not user facing, don't show disambiguation dialog.
869                 try {
870                     ISms iSms = getISmsServiceOrThrow();
871                     if (iSms != null) {
872                         iSms.sendMultipartTextForSubscriber(getSubscriptionId(), packageName,
873                                 destinationAddress, scAddress, parts, sentIntents, deliveryIntents,
874                                 persistMessage);
875                     }
876                 } catch (RemoteException e) {
877                     Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - "
878                             + e.getMessage());
879                     notifySmsGenericError(sentIntents);
880                 }
881             }
882         } else {
883             PendingIntent sentIntent = null;
884             PendingIntent deliveryIntent = null;
885             if (sentIntents != null && sentIntents.size() > 0) {
886                 sentIntent = sentIntents.get(0);
887             }
888             if (deliveryIntents != null && deliveryIntents.size() > 0) {
889                 deliveryIntent = deliveryIntents.get(0);
890             }
891             sendTextMessageInternal(destinationAddress, scAddress, parts.get(0),
892                     sentIntent, deliveryIntent, true, packageName);
893         }
894     }
895 
896     /**
897      * Send a multi-part text based SMS without writing it into the SMS Provider.
898      *
899      * <p>
900      * If this method is called on a device with multiple active subscriptions, this
901      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
902      * default subscription is defined, the subscription ID associated with this message will be
903      * INVALID, which will result in the SMS sent on the subscription associated with slot
904      * 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent using the
905      * correct subscription.
906      * </p>
907      *
908      * <p>Requires Permission:
909      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
910      * privileges.
911      * </p>
912      *
913      * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList)
914      * @hide
915      **/
916     @SystemApi
917     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
sendMultipartTextMessageWithoutPersisting( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)918     public void sendMultipartTextMessageWithoutPersisting(
919             String destinationAddress, String scAddress, List<String> parts,
920             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
921         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
922                 deliveryIntents, false /* persistMessage*/, ActivityThread.currentPackageName());
923     }
924 
925     /**
926      * Send a multi-part text based SMS with messaging options. The callee should have already
927      * divided the message into correctly sized parts by calling
928      * <code>divideMessage</code>.
929      *
930      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
931      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
932      *
933      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
934      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
935      * writes messages sent using this method to the SMS Provider (the default SMS app is always
936      * responsible for writing its sent messages to the SMS Provider). For information about
937      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
938      *
939      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
940      * manager on a multi-SIM device, this operation may fail sending the SMS message because no
941      * suitable default subscription could be found. In this case, if {@code sentIntent} is
942      * non-null, then the {@link PendingIntent} will be sent with an error code
943      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
944      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
945      * where this operation may fail.
946      * </p>
947 
948      * @param destinationAddress the address to send the message to
949      * @param scAddress is the service center address or null to use
950      *   the current default SMSC
951      * @param parts an <code>ArrayList</code> of strings that, in order,
952      *   comprise the original message
953      * @param sentIntents if not null, an <code>ArrayList</code> of
954      *   <code>PendingIntent</code>s (one for each message part) that is
955      *   broadcast when the corresponding message part has been sent.
956      *   The result code will be <code>Activity.RESULT_OK</code> for success,
957      *   or one of these errors:<br>
958      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
959      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
960      *   <code>RESULT_ERROR_NULL_PDU</code><br>
961      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
962      *   the extra "errorCode" containing a radio technology specific value,
963      *   generally only useful for troubleshooting.<br>
964      *   The per-application based SMS control checks sentIntent. If sentIntent
965      *   is NULL the caller will be checked against all unknown applications,
966      *   which cause smaller number of SMS to be sent in checking period.
967      * @param deliveryIntents if not null, an <code>ArrayList</code> of
968      *   <code>PendingIntent</code>s (one for each message part) that is
969      *   broadcast when the corresponding message part has been delivered
970      *   to the recipient.  The raw pdu of the status report is in the
971      *   extended data ("pdu").
972      * @param priority Priority level of the message
973      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
974      *  ---------------------------------
975      *  PRIORITY      | Level of Priority
976      *  ---------------------------------
977      *      '00'      |     Normal
978      *      '01'      |     Interactive
979      *      '10'      |     Urgent
980      *      '11'      |     Emergency
981      *  ----------------------------------
982      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
983      * @param expectMore is a boolean to indicate the sending messages through same link or not.
984      * @param validityPeriod Validity Period of the message in mins.
985      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
986      *  Validity Period(Minimum) -> 5 mins
987      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
988      *  Any Other values included Negative considered as Invalid Validity Period of the message.
989      *
990      * @throws IllegalArgumentException if destinationAddress or data are empty
991      * {@hide}
992      */
993     @UnsupportedAppUsage
sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, int priority, boolean expectMore, int validityPeriod)994     public void sendMultipartTextMessage(
995             String destinationAddress, String scAddress, ArrayList<String> parts,
996             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
997             int priority, boolean expectMore, int validityPeriod) {
998         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
999                 deliveryIntents, true /* persistMessage*/, priority, expectMore,
1000                 validityPeriod);
1001     }
1002 
sendMultipartTextMessageInternal( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessage, int priority, boolean expectMore, int validityPeriod)1003     private void sendMultipartTextMessageInternal(
1004             String destinationAddress, String scAddress, List<String> parts,
1005             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
1006             boolean persistMessage, int priority, boolean expectMore, int validityPeriod) {
1007         if (TextUtils.isEmpty(destinationAddress)) {
1008             throw new IllegalArgumentException("Invalid destinationAddress");
1009         }
1010         if (parts == null || parts.size() < 1) {
1011             throw new IllegalArgumentException("Invalid message body");
1012         }
1013 
1014         if (priority < 0x00 || priority > 0x03) {
1015             priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED;
1016         }
1017 
1018         if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
1019             validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED;
1020         }
1021 
1022         if (parts.size() > 1) {
1023             final int finalPriority = priority;
1024             final int finalValidity = validityPeriod;
1025             final Context context = ActivityThread.currentApplication().getApplicationContext();
1026             if (persistMessage) {
1027                 resolveSubscriptionForOperation(new SubscriptionResolverResult() {
1028                     @Override
1029                     public void onSuccess(int subId) {
1030                         try {
1031                             ISms iSms = getISmsServiceOrThrow();
1032                             if (iSms != null) {
1033                                 iSms.sendMultipartTextForSubscriberWithOptions(subId,
1034                                         ActivityThread.currentPackageName(), destinationAddress,
1035                                         scAddress, parts, sentIntents, deliveryIntents,
1036                                         persistMessage, finalPriority, expectMore, finalValidity);
1037                             }
1038                         } catch (RemoteException e) {
1039                             Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - "
1040                                     + e.getMessage());
1041                             notifySmsGenericError(sentIntents);
1042                         }
1043                     }
1044 
1045                     @Override
1046                     public void onFailure() {
1047                         notifySmsErrorNoDefaultSet(context, sentIntents);
1048                     }
1049                 });
1050             } else {
1051                 // Sent by apps that are not user visible, so don't show SIM disambiguation dialog.
1052                 try {
1053                     ISms iSms = getISmsServiceOrThrow();
1054                     if (iSms != null) {
1055                         iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
1056                                 ActivityThread.currentPackageName(), destinationAddress,
1057                                 scAddress, parts, sentIntents, deliveryIntents,
1058                                 persistMessage, finalPriority, expectMore, finalValidity);
1059                     }
1060                 } catch (RemoteException e) {
1061                     Log.e(TAG, "sendMultipartTextMessageInternal (no persist): Couldn't send SMS - "
1062                             + e.getMessage());
1063                     notifySmsGenericError(sentIntents);
1064                 }
1065             }
1066         } else {
1067             PendingIntent sentIntent = null;
1068             PendingIntent deliveryIntent = null;
1069             if (sentIntents != null && sentIntents.size() > 0) {
1070                 sentIntent = sentIntents.get(0);
1071             }
1072             if (deliveryIntents != null && deliveryIntents.size() > 0) {
1073                 deliveryIntent = deliveryIntents.get(0);
1074             }
1075             sendTextMessageInternal(destinationAddress, scAddress, parts.get(0),
1076                     sentIntent, deliveryIntent, persistMessage, priority, expectMore,
1077                     validityPeriod);
1078         }
1079     }
1080 
1081     /**
1082      * Send a multi-part text based SMS without writing it into the SMS Provider.
1083      *
1084      * <p>Requires Permission:
1085      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
1086      * privileges.
1087      * </p>
1088      *
1089      * <p class="note"><strong>Note:</strong> This method is intended for internal use the Telephony
1090      * framework and will never trigger an SMS disambiguation dialog. If this method is called on a
1091      * device that has multiple active subscriptions, this {@link SmsManager} instance has been
1092      * created with {@link #getDefault()}, and no user-defined default subscription is defined, the
1093      * subscription ID associated with this message will be INVALID, which will result in the SMS
1094      * being sent on the subscription associated with logical slot 0. Use
1095      * {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the correct
1096      * subscription.
1097      * </p>
1098      *
1099      * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList,
1100      * ArrayList, int, boolean, int)
1101      * @hide
1102      **/
sendMultipartTextMessageWithoutPersisting( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, int priority, boolean expectMore, int validityPeriod)1103     public void sendMultipartTextMessageWithoutPersisting(
1104             String destinationAddress, String scAddress, List<String> parts,
1105             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
1106             int priority, boolean expectMore, int validityPeriod) {
1107         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
1108                 deliveryIntents, false /* persistMessage*/, priority, expectMore,
1109                 validityPeriod);
1110     }
1111 
1112     /**
1113      * Send a data based SMS to a specific application port.
1114      *
1115      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
1116      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
1117      *
1118      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
1119      * manager on a multi-SIM device, this operation may fail sending the SMS message because no
1120      * suitable default subscription could be found. In this case, if {@code sentIntent} is
1121      * non-null, then the {@link PendingIntent} will be sent with an error code
1122      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
1123      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
1124      * where this operation may fail.
1125      * </p>
1126      *
1127      * @param destinationAddress the address to send the message to
1128      * @param scAddress is the service center address or null to use
1129      *  the current default SMSC
1130      * @param destinationPort the port to deliver the message to
1131      * @param data the body of the message to send
1132      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1133      *  broadcast when the message is successfully sent, or failed.
1134      *  The result code will be <code>Activity.RESULT_OK</code> for success,
1135      *  or one of these errors:<br>
1136      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
1137      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
1138      *  <code>RESULT_ERROR_NULL_PDU</code><br>
1139      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
1140      *  the extra "errorCode" containing a radio technology specific value,
1141      *  generally only useful for troubleshooting.<br>
1142      *  The per-application based SMS control checks sentIntent. If sentIntent
1143      *  is NULL the caller will be checked against all unknown applications,
1144      *  which cause smaller number of SMS to be sent in checking period.
1145      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
1146      *  broadcast when the message is delivered to the recipient.  The
1147      *  raw pdu of the status report is in the extended data ("pdu").
1148      *
1149      * @throws IllegalArgumentException if destinationAddress or data are empty
1150      */
sendDataMessage( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)1151     public void sendDataMessage(
1152             String destinationAddress, String scAddress, short destinationPort,
1153             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
1154         if (TextUtils.isEmpty(destinationAddress)) {
1155             throw new IllegalArgumentException("Invalid destinationAddress");
1156         }
1157 
1158         if (data == null || data.length == 0) {
1159             throw new IllegalArgumentException("Invalid message data");
1160         }
1161 
1162         final Context context = ActivityThread.currentApplication().getApplicationContext();
1163         resolveSubscriptionForOperation(new SubscriptionResolverResult() {
1164             @Override
1165             public void onSuccess(int subId) {
1166                 try {
1167                     ISms iSms = getISmsServiceOrThrow();
1168                     iSms.sendDataForSubscriber(subId, ActivityThread.currentPackageName(),
1169                             destinationAddress, scAddress, destinationPort & 0xFFFF, data,
1170                             sentIntent, deliveryIntent);
1171                 } catch (RemoteException e) {
1172                     Log.e(TAG, "sendDataMessage: Couldn't send SMS - Exception: " + e.getMessage());
1173                     notifySmsGenericError(sentIntent);
1174                 }
1175             }
1176             @Override
1177             public void onFailure() {
1178                 notifySmsErrorNoDefaultSet(context, sentIntent);
1179             }
1180         });
1181     }
1182 
1183     /**
1184      * A variant of {@link SmsManager#sendDataMessage} that allows self to be the caller. This is
1185      * for internal use only.
1186      *
1187      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1188      * applications or the Telephony framework and will never trigger an SMS disambiguation
1189      * dialog. If this method is called on a device that has multiple active subscriptions, this
1190      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1191      * default subscription is defined, the subscription ID associated with this message will be
1192      * INVALID, which will result in the SMS being sent on the subscription associated with logical
1193      * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
1194      * correct subscription.
1195      * </p>
1196      *
1197      * @hide
1198      */
sendDataMessageWithSelfPermissions( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)1199     public void sendDataMessageWithSelfPermissions(
1200             String destinationAddress, String scAddress, short destinationPort,
1201             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
1202         if (TextUtils.isEmpty(destinationAddress)) {
1203             throw new IllegalArgumentException("Invalid destinationAddress");
1204         }
1205 
1206         if (data == null || data.length == 0) {
1207             throw new IllegalArgumentException("Invalid message data");
1208         }
1209 
1210         try {
1211             ISms iSms = getISmsServiceOrThrow();
1212             iSms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(),
1213                     ActivityThread.currentPackageName(), destinationAddress, scAddress,
1214                     destinationPort & 0xFFFF, data, sentIntent, deliveryIntent);
1215         } catch (RemoteException e) {
1216             Log.e(TAG, "sendDataMessageWithSelfPermissions: Couldn't send SMS - Exception: "
1217                     + e.getMessage());
1218             notifySmsGenericError(sentIntent);
1219         }
1220     }
1221 
1222     /**
1223      * Get the SmsManager associated with the default subscription id. The instance will always be
1224      * associated with the default subscription id, even if the default subscription id changes.
1225      *
1226      * <p class="note"><strong>Note:</strong> For devices that support multiple active subscriptions
1227      * at a time, SmsManager will track the subscription set by the user as the default SMS
1228      * subscription. If the user has not set a default, {@link SmsManager} may
1229      * start an activity to kick off a subscription disambiguation dialog. Most operations will not
1230      * complete until the user has chosen the subscription that will be associated with the
1231      * operation. If the user cancels the dialog without choosing a subscription, one of the
1232      * following will happen, depending on the target SDK version of the application. For
1233      * compatibility purposes, if the target SDK level is <= 28, telephony will still send the SMS
1234      * over the first available subscription. If the target SDK level is > 28, the operation will
1235      * fail to complete.
1236      * </p>
1237      *
1238      * <p class="note"><strong>Note:</strong> If this method is used to perform an operation on a
1239      * device that has multiple active subscriptions, the user has not set a default SMS
1240      * subscription, and the operation is being performed while the application is not in the
1241      * foreground, the SMS disambiguation dialog will not be shown. The result of the operation will
1242      * conclude as if the user cancelled the disambiguation dialog and the operation will finish as
1243      * outlined above, depending on the target SDK version of the calling application. It is safer
1244      * to use {@link #getSmsManagerForSubscriptionId(int)} if the application will perform the
1245      * operation while in the background because this can cause unpredictable results, such as the
1246      * operation being sent over the wrong subscription or failing completely, depending on the
1247      * user's default SMS subscription setting.
1248      * </p>
1249      *
1250      * @return the {@link SmsManager} associated with the default subscription id.
1251      *
1252      * @see SubscriptionManager#getDefaultSmsSubscriptionId()
1253      */
getDefault()1254     public static SmsManager getDefault() {
1255         return sInstance;
1256     }
1257 
1258     /**
1259      * Get the instance of the SmsManager associated with a particular subscription ID.
1260      *
1261      * <p class="note"><strong>Note:</strong> Constructing an {@link SmsManager} in this manner will
1262      * never cause an SMS disambiguation dialog to appear, unlike {@link #getDefault()}.
1263      * </p>
1264      *
1265      * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager}
1266      * @return the instance of the SmsManager associated with subscription
1267      *
1268      * @see SubscriptionManager#getActiveSubscriptionInfoList()
1269      * @see SubscriptionManager#getDefaultSmsSubscriptionId()
1270      */
getSmsManagerForSubscriptionId(int subId)1271     public static SmsManager getSmsManagerForSubscriptionId(int subId) {
1272         synchronized(sLockObject) {
1273             SmsManager smsManager = sSubInstances.get(subId);
1274             if (smsManager == null) {
1275                 smsManager = new SmsManager(subId);
1276                 sSubInstances.put(subId, smsManager);
1277             }
1278             return smsManager;
1279         }
1280     }
1281 
SmsManager(int subId)1282     private SmsManager(int subId) {
1283         mSubId = subId;
1284     }
1285 
1286     /**
1287      * Get the associated subscription id. If the instance was returned by {@link #getDefault()},
1288      * then this method may return different values at different points in time (if the user
1289      * changes the default subscription id).
1290      *
1291      * <p class="note"><strong>Note:</strong> This method used to display a disambiguation dialog to
1292      * the user asking them to choose a default subscription to send SMS messages over if they
1293      * haven't chosen yet. Starting in API level 29, we allow the user to not have a default set as
1294      * a valid option for the default SMS subscription on multi-SIM devices. We no longer show the
1295      * disambiguation dialog and return {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if the
1296      * device has multiple active subscriptions and no default is set.
1297      * </p>
1298      *
1299      * @return associated subscription ID or {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if
1300      * the default subscription id cannot be determined or the device has multiple active
1301      * subscriptions and and no default is set ("ask every time") by the user.
1302      */
getSubscriptionId()1303     public int getSubscriptionId() {
1304         try {
1305             return (mSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)
1306                     ? getISmsServiceOrThrow().getPreferredSmsSubscription() : mSubId;
1307         } catch (RemoteException e) {
1308             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1309         }
1310     }
1311 
1312     /**
1313      * Resolves the subscription id to use for the associated operation if
1314      * {@link #getSubscriptionId()} returns {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
1315      *
1316      * If app targets API level 28 or below and they are either sending the SMS from the background
1317      * or the device has more than one active subscription available and no default is set, we will
1318      * use the first logical slot to send the SMS and possibly fail later in the SMS sending
1319      * process.
1320      *
1321      * Regardless of the API level, if the app is the foreground app, then we will show the SMS
1322      * disambiguation dialog. If the app is in the background and tries to perform an operation, we
1323      * will not show the disambiguation dialog.
1324      *
1325      * See {@link #getDefault()} for a detailed explanation of how this method operates.
1326      *
1327      * @param resolverResult The callback that will be called when the subscription is resolved or
1328      *                       fails to be resolved.
1329      */
resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult)1330     private void resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult) {
1331         int subId = getSubscriptionId();
1332         boolean isSmsSimPickActivityNeeded = false;
1333         final Context context = ActivityThread.currentApplication().getApplicationContext();
1334         try {
1335             ISms iSms = getISmsService();
1336             if (iSms != null) {
1337                 // Determines if the SMS SIM pick activity should be shown. This is only shown if:
1338                 // 1) The device has multiple active subscriptions and an SMS default subscription
1339                 //    hasn't been set, and
1340                 // 2) SmsManager is being called from the foreground app.
1341                 // Android does not allow background activity starts, so we need to block this.
1342                 // if Q+, do not perform requested operation if these two operations are not set. If
1343                 // <P, perform these operations on phone 0 (for compatibility purposes, since we
1344                 // used to not wait for the result of this activity).
1345                 isSmsSimPickActivityNeeded = iSms.isSmsSimPickActivityNeeded(subId);
1346             }
1347         } catch (RemoteException ex) {
1348             Log.e(TAG, "resolveSubscriptionForOperation", ex);
1349         }
1350         if (!isSmsSimPickActivityNeeded) {
1351             sendResolverResult(resolverResult, subId, false /*pickActivityShown*/);
1352             return;
1353         }
1354         // We need to ask the user pick an appropriate subid for the operation.
1355         Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for package "
1356                 + context.getPackageName());
1357         try {
1358             // Create the SMS pick activity and call back once the activity is complete. Can't do
1359             // it here because we do not have access to the activity context that is performing this
1360             // operation.
1361             // Requires that the calling process has the SEND_SMS permission.
1362             getITelephony().enqueueSmsPickResult(context.getOpPackageName(),
1363                     new IIntegerConsumer.Stub() {
1364                         @Override
1365                         public void accept(int subId) {
1366                             // Runs on binder thread attached to this app's process.
1367                             sendResolverResult(resolverResult, subId, true /*pickActivityShown*/);
1368                         }
1369                     });
1370         } catch (RemoteException ex) {
1371             Log.e(TAG, "Unable to launch activity", ex);
1372             // pickActivityShown is true here because we want to call sendResolverResult and always
1373             // have this operation fail. This is because we received a RemoteException here, which
1374             // means that telephony is not available and the next operation to Telephony will fail
1375             // as well anyways, so we might as well shortcut fail here first.
1376             sendResolverResult(resolverResult, subId, true /*pickActivityShown*/);
1377         }
1378     }
1379 
sendResolverResult(SubscriptionResolverResult resolverResult, int subId, boolean pickActivityShown)1380     private void sendResolverResult(SubscriptionResolverResult resolverResult, int subId,
1381             boolean pickActivityShown) {
1382         if (SubscriptionManager.isValidSubscriptionId(subId)) {
1383             resolverResult.onSuccess(subId);
1384             return;
1385         }
1386 
1387         if (getTargetSdkVersion() <= Build.VERSION_CODES.P && !pickActivityShown) {
1388             // Do not fail, return a success with an INVALID subid for apps targeting P or below
1389             // that tried to perform an operation and the SMS disambiguation dialog was never shown,
1390             // as these applications may not have been written to handle the failure case properly.
1391             // This will resolve to performing the operation on phone 0 in telephony.
1392             resolverResult.onSuccess(subId);
1393         } else {
1394             // Fail if the app targets Q or above or it targets P and below and the disambiguation
1395             // dialog was shown and the user clicked out of it.
1396             resolverResult.onFailure();
1397         }
1398     }
1399 
getTargetSdkVersion()1400     private static int getTargetSdkVersion() {
1401         final Context context = ActivityThread.currentApplication().getApplicationContext();
1402         int targetSdk;
1403         try {
1404             targetSdk = context.getPackageManager().getApplicationInfo(
1405                     context.getOpPackageName(), 0).targetSdkVersion;
1406         } catch (PackageManager.NameNotFoundException e) {
1407             // Default to old behavior if we can not find this.
1408             targetSdk = -1;
1409         }
1410         return targetSdk;
1411     }
1412 
getITelephony()1413     private static ITelephony getITelephony() {
1414         ITelephony binder = ITelephony.Stub.asInterface(
1415                 ServiceManager.getService(Context.TELEPHONY_SERVICE));
1416         if (binder == null) {
1417             throw new RuntimeException("Could not find Telephony Service.");
1418         }
1419         return binder;
1420     }
1421 
notifySmsErrorNoDefaultSet(Context context, PendingIntent pendingIntent)1422     private static void notifySmsErrorNoDefaultSet(Context context, PendingIntent pendingIntent) {
1423         if (pendingIntent != null) {
1424             Intent errorMessage = new Intent();
1425             errorMessage.putExtra(NO_DEFAULT_EXTRA, true);
1426             try {
1427                 pendingIntent.send(context, RESULT_ERROR_GENERIC_FAILURE, errorMessage);
1428             } catch (PendingIntent.CanceledException e) {
1429                 // Don't worry about it, we do not need to notify the caller if this is the case.
1430             }
1431         }
1432     }
1433 
notifySmsErrorNoDefaultSet(Context context, List<PendingIntent> pendingIntents)1434     private static void notifySmsErrorNoDefaultSet(Context context,
1435             List<PendingIntent> pendingIntents) {
1436         if (pendingIntents != null) {
1437             for (PendingIntent pendingIntent : pendingIntents) {
1438                 Intent errorMessage = new Intent();
1439                 errorMessage.putExtra(NO_DEFAULT_EXTRA, true);
1440                 try {
1441                     pendingIntent.send(context, RESULT_ERROR_GENERIC_FAILURE, errorMessage);
1442                 } catch (PendingIntent.CanceledException e) {
1443                     // Don't worry about it, we do not need to notify the caller if this is the
1444                     // case.
1445                 }
1446             }
1447         }
1448     }
1449 
notifySmsGenericError(PendingIntent pendingIntent)1450     private static void notifySmsGenericError(PendingIntent pendingIntent) {
1451         if (pendingIntent != null) {
1452             try {
1453                 pendingIntent.send(RESULT_ERROR_GENERIC_FAILURE);
1454             } catch (PendingIntent.CanceledException e) {
1455                 // Don't worry about it, we do not need to notify the caller if this is the case.
1456             }
1457         }
1458     }
1459 
notifySmsGenericError(List<PendingIntent> pendingIntents)1460     private static void notifySmsGenericError(List<PendingIntent> pendingIntents) {
1461         if (pendingIntents != null) {
1462             for (PendingIntent pendingIntent : pendingIntents) {
1463                 try {
1464                     pendingIntent.send(RESULT_ERROR_GENERIC_FAILURE);
1465                 } catch (PendingIntent.CanceledException e) {
1466                     // Don't worry about it, we do not need to notify the caller if this is the
1467                     // case.
1468                 }
1469             }
1470         }
1471     }
1472 
1473     /**
1474      * Returns the ISms service, or throws an UnsupportedOperationException if
1475      * the service does not exist.
1476      */
getISmsServiceOrThrow()1477     private static ISms getISmsServiceOrThrow() {
1478         ISms iSms = getISmsService();
1479         if (iSms == null) {
1480             throw new UnsupportedOperationException("Sms is not supported");
1481         }
1482         return iSms;
1483     }
1484 
getISmsService()1485     private static ISms getISmsService() {
1486         return ISms.Stub.asInterface(ServiceManager.getService("isms"));
1487     }
1488 
1489     /**
1490      * Copy a raw SMS PDU to the ICC.
1491      * ICC (Integrated Circuit Card) is the card of the device.
1492      * For example, this can be the SIM or USIM for GSM.
1493      *
1494      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1495      * applications or the Telephony framework and will never trigger an SMS disambiguation
1496      * dialog. If this method is called on a device that has multiple active subscriptions, this
1497      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1498      * default subscription is defined, the subscription ID associated with this message will be
1499      * INVALID, which will result in the operation being completed on the subscription associated
1500      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1501      * operation is performed on the correct subscription.
1502      * </p>
1503      *
1504      * @param smsc the SMSC for this message, or NULL for the default SMSC
1505      * @param pdu the raw PDU to store
1506      * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
1507      *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
1508      * @return true for success
1509      *
1510      * @throws IllegalArgumentException if pdu is NULL
1511      * {@hide}
1512      */
1513     @UnsupportedAppUsage
copyMessageToIcc(byte[] smsc, byte[] pdu,int status)1514     public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
1515         boolean success = false;
1516 
1517         if (null == pdu) {
1518             throw new IllegalArgumentException("pdu is NULL");
1519         }
1520         try {
1521             ISms iSms = getISmsService();
1522             if (iSms != null) {
1523                 success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
1524                         ActivityThread.currentPackageName(),
1525                         status, pdu, smsc);
1526             }
1527         } catch (RemoteException ex) {
1528             // ignore it
1529         }
1530 
1531         return success;
1532     }
1533 
1534     /**
1535      * Delete the specified message from the ICC.
1536      * ICC (Integrated Circuit Card) is the card of the device.
1537      * For example, this can be the SIM or USIM for GSM.
1538      *
1539      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1540      * applications or the Telephony framework and will never trigger an SMS disambiguation
1541      * dialog. If this method is called on a device that has multiple active subscriptions, this
1542      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1543      * default subscription is defined, the subscription ID associated with this message will be
1544      * INVALID, which will result in the operation being completed on the subscription associated
1545      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1546      * operation is performed on the correct subscription.
1547      * </p>
1548      *
1549      * @param messageIndex is the record index of the message on ICC
1550      * @return true for success
1551      *
1552      * {@hide}
1553      */
1554     @UnsupportedAppUsage
1555     public boolean
deleteMessageFromIcc(int messageIndex)1556     deleteMessageFromIcc(int messageIndex) {
1557         boolean success = false;
1558         byte[] pdu = new byte[SMS_RECORD_LENGTH-1];
1559         Arrays.fill(pdu, (byte)0xff);
1560 
1561         try {
1562             ISms iSms = getISmsService();
1563             if (iSms != null) {
1564                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
1565                         ActivityThread.currentPackageName(),
1566                         messageIndex, STATUS_ON_ICC_FREE, pdu);
1567             }
1568         } catch (RemoteException ex) {
1569             // ignore it
1570         }
1571 
1572         return success;
1573     }
1574 
1575     /**
1576      * Update the specified message on the ICC.
1577      * ICC (Integrated Circuit Card) is the card of the device.
1578      * For example, this can be the SIM or USIM for GSM.
1579      *
1580      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1581      * applications or the Telephony framework and will never trigger an SMS disambiguation
1582      * dialog. If this method is called on a device that has multiple active subscriptions, this
1583      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1584      * default subscription is defined, the subscription ID associated with this message will be
1585      * INVALID, which will result in the operation being completed on the subscription associated
1586      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1587      * operation is performed on the correct subscription.
1588      * </p>
1589      *
1590      * @param messageIndex record index of message to update
1591      * @param newStatus new message status (STATUS_ON_ICC_READ,
1592      *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
1593      *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
1594      * @param pdu the raw PDU to store
1595      * @return true for success
1596      *
1597      * {@hide}
1598      */
1599     @UnsupportedAppUsage
updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu)1600     public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
1601         boolean success = false;
1602 
1603         try {
1604             ISms iSms = getISmsService();
1605             if (iSms != null) {
1606                 success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
1607                         ActivityThread.currentPackageName(),
1608                         messageIndex, newStatus, pdu);
1609             }
1610         } catch (RemoteException ex) {
1611             // ignore it
1612         }
1613 
1614         return success;
1615     }
1616 
1617     /**
1618      * Retrieves all messages currently stored on ICC.
1619      * ICC (Integrated Circuit Card) is the card of the device.
1620      * For example, this can be the SIM or USIM for GSM.
1621      *
1622      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1623      * applications or the Telephony framework and will never trigger an SMS disambiguation
1624      * dialog. If this method is called on a device that has multiple active subscriptions, this
1625      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1626      * default subscription is defined, the subscription ID associated with this message will be
1627      * INVALID, which will result in the operation being completed on the subscription associated
1628      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1629      * operation is performed on the correct subscription.
1630      * </p>
1631      *
1632      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
1633      *
1634      * {@hide}
1635      */
1636     @UnsupportedAppUsage
getAllMessagesFromIcc()1637     public ArrayList<SmsMessage> getAllMessagesFromIcc() {
1638         List<SmsRawData> records = null;
1639 
1640         try {
1641             ISms iSms = getISmsService();
1642             if (iSms != null) {
1643                 records = iSms.getAllMessagesFromIccEfForSubscriber(
1644                         getSubscriptionId(),
1645                         ActivityThread.currentPackageName());
1646             }
1647         } catch (RemoteException ex) {
1648             // ignore it
1649         }
1650 
1651         return createMessageListFromRawRecords(records);
1652     }
1653 
1654     /**
1655      * Enable reception of cell broadcast (SMS-CB) messages with the given
1656      * message identifier and RAN type. The RAN type specify this message ID
1657      * belong to 3GPP (GSM) or 3GPP2(CDMA).Note that if two different clients
1658      * enable the same message identifier, they must both disable it for the device to stop
1659      * receiving those messages. All received messages will be broadcast in an
1660      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
1661      * Note: This call is blocking, callers may want to avoid calling it from
1662      * the main thread of an application.
1663      *
1664      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1665      * applications or the Telephony framework and will never trigger an SMS disambiguation
1666      * dialog. If this method is called on a device that has multiple active subscriptions, this
1667      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1668      * default subscription is defined, the subscription ID associated with this message will be
1669      * INVALID, which will result in the operation being completed on the subscription associated
1670      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1671      * operation is performed on the correct subscription.
1672      * </p>
1673      *
1674      * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
1675      * or C.R1001-G (3GPP2)
1676      * @param ranType as defined in class SmsManager, the value can be one of these:
1677      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
1678      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
1679      * @return true if successful, false otherwise
1680      * @see #disableCellBroadcast(int, int)
1681      *
1682      * {@hide}
1683      */
enableCellBroadcast(int messageIdentifier, int ranType)1684     public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
1685         boolean success = false;
1686 
1687         try {
1688             ISms iSms = getISmsService();
1689             if (iSms != null) {
1690                 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use
1691                 // the default phone internally.
1692                 success = iSms.enableCellBroadcastForSubscriber(getSubscriptionId(),
1693                         messageIdentifier, ranType);
1694             }
1695         } catch (RemoteException ex) {
1696             // ignore it
1697         }
1698 
1699         return success;
1700     }
1701 
1702     /**
1703      * Disable reception of cell broadcast (SMS-CB) messages with the given
1704      * message identifier and RAN type. The RAN type specify this message ID
1705      * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
1706      * enable the same message identifier, they must both disable it for the
1707      * device to stop receiving those messages.
1708      * Note: This call is blocking, callers may want to avoid calling it from
1709      * the main thread of an application.
1710      *
1711      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1712      * applications or the Telephony framework and will never trigger an SMS disambiguation
1713      * dialog. If this method is called on a device that has multiple active subscriptions, this
1714      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1715      * default subscription is defined, the subscription ID associated with this message will be
1716      * INVALID, which will result in the operation being completed on the subscription associated
1717      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1718      * operation is performed on the correct subscription.
1719      * </p>
1720      *
1721      * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
1722      * or C.R1001-G (3GPP2)
1723      * @param ranType as defined in class SmsManager, the value can be one of these:
1724      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
1725      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
1726      * @return true if successful, false otherwise
1727      *
1728      * @see #enableCellBroadcast(int, int)
1729      *
1730      * {@hide}
1731      */
disableCellBroadcast(int messageIdentifier, int ranType)1732     public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
1733         boolean success = false;
1734 
1735         try {
1736             ISms iSms = getISmsService();
1737             if (iSms != null) {
1738                 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use
1739                 // the default phone internally.
1740                 success = iSms.disableCellBroadcastForSubscriber(getSubscriptionId(),
1741                         messageIdentifier, ranType);
1742             }
1743         } catch (RemoteException ex) {
1744             // ignore it
1745         }
1746 
1747         return success;
1748     }
1749 
1750     /**
1751      * Enable reception of cell broadcast (SMS-CB) messages with the given
1752      * message identifier range and RAN type. The RAN type specify this message ID
1753      * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable
1754      * the same message identifier, they must both disable it for the device to stop
1755      * receiving those messages. All received messages will be broadcast in an
1756      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
1757      * Note: This call is blocking, callers may want to avoid calling it from
1758      * the main thread of an application.
1759      *
1760      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1761      * applications or the Telephony framework and will never trigger an SMS disambiguation
1762      * dialog. If this method is called on a device that has multiple active subscriptions, this
1763      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1764      * default subscription is defined, the subscription ID associated with this message will be
1765      * INVALID, which will result in the operation being completed on the subscription associated
1766      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1767      * operation is performed on the correct subscription.
1768      * </p>
1769      *
1770      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
1771      * or C.R1001-G (3GPP2)
1772      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
1773      * or C.R1001-G (3GPP2)
1774      * @param ranType as defined in class SmsManager, the value can be one of these:
1775      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
1776      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
1777      * @return true if successful, false otherwise
1778      * @see #disableCellBroadcastRange(int, int, int)
1779      *
1780      * @throws IllegalArgumentException if endMessageId < startMessageId
1781      * {@hide}
1782      */
1783     @UnsupportedAppUsage
enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)1784     public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
1785         boolean success = false;
1786 
1787         if (endMessageId < startMessageId) {
1788             throw new IllegalArgumentException("endMessageId < startMessageId");
1789         }
1790         try {
1791             ISms iSms = getISmsService();
1792             if (iSms != null) {
1793                 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use
1794                 // the default phone internally.
1795                 success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
1796                         startMessageId, endMessageId, ranType);
1797             }
1798         } catch (RemoteException ex) {
1799             // ignore it
1800         }
1801 
1802         return success;
1803     }
1804 
1805     /**
1806      * Disable reception of cell broadcast (SMS-CB) messages with the given
1807      * message identifier range and RAN type. The RAN type specify this message
1808      * ID range belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different
1809      * clients enable the same message identifier, they must both disable it for
1810      * the device to stop receiving those messages.
1811      * Note: This call is blocking, callers may want to avoid calling it from
1812      * the main thread of an application.
1813      *
1814      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1815      * applications or the Telephony framework and will never trigger an SMS disambiguation
1816      * dialog. If this method is called on a device that has multiple active subscriptions, this
1817      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1818      * default subscription is defined, the subscription ID associated with this message will be
1819      * INVALID, which will result in the operation being completed on the subscription associated
1820      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1821      * operation is performed on the correct subscription.
1822      * </p>
1823      *
1824      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
1825      * or C.R1001-G (3GPP2)
1826      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
1827      * or C.R1001-G (3GPP2)
1828      * @param ranType as defined in class SmsManager, the value can be one of these:
1829      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
1830      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
1831      * @return true if successful, false otherwise
1832      *
1833      * @see #enableCellBroadcastRange(int, int, int)
1834      *
1835      * @throws IllegalArgumentException if endMessageId < startMessageId
1836      * {@hide}
1837      */
1838     @UnsupportedAppUsage
disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)1839     public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
1840         boolean success = false;
1841 
1842         if (endMessageId < startMessageId) {
1843             throw new IllegalArgumentException("endMessageId < startMessageId");
1844         }
1845         try {
1846             ISms iSms = getISmsService();
1847             if (iSms != null) {
1848                 // If getSubscriptionId() returns INVALID or an inactive subscription, we will use
1849                 // the default phone internally.
1850                 success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
1851                         startMessageId, endMessageId, ranType);
1852             }
1853         } catch (RemoteException ex) {
1854             // ignore it
1855         }
1856 
1857         return success;
1858     }
1859 
1860     /**
1861      * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
1862      * records returned by <code>getAllMessagesFromIcc()</code>
1863      *
1864      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1865      * applications or the Telephony framework and will never trigger an SMS disambiguation
1866      * dialog. If this method is called on a device that has multiple active subscriptions, this
1867      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1868      * default subscription is defined, the subscription ID associated with this message will be
1869      * INVALID, which will result in the operation being completed on the subscription associated
1870      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1871      * operation is performed on the correct subscription.
1872      * </p>
1873      *
1874      * @param records SMS EF records, returned by
1875      *   <code>getAllMessagesFromIcc</code>
1876      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
1877      */
createMessageListFromRawRecords(List<SmsRawData> records)1878     private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
1879         ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
1880         if (records != null) {
1881             int count = records.size();
1882             for (int i = 0; i < count; i++) {
1883                 SmsRawData data = records.get(i);
1884                 // List contains all records, including "free" records (null)
1885                 if (data != null) {
1886                     SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes(),
1887                             getSubscriptionId());
1888                     if (sms != null) {
1889                         messages.add(sms);
1890                     }
1891                 }
1892             }
1893         }
1894         return messages;
1895     }
1896 
1897     /**
1898      * SMS over IMS is supported if IMS is registered and SMS is supported
1899      * on IMS.
1900      *
1901      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1902      * applications or the Telephony framework and will never trigger an SMS disambiguation
1903      * dialog. If this method is called on a device that has multiple active subscriptions, this
1904      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1905      * default subscription is defined, the subscription ID associated with this message will be
1906      * INVALID, which will result in the operation being completed on the subscription associated
1907      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1908      * operation is performed on the correct subscription.
1909      * </p>
1910      *
1911      * @return true if SMS over IMS is supported, false otherwise
1912      *
1913      * @see #getImsSmsFormat()
1914      *
1915      * @hide
1916      */
isImsSmsSupported()1917     public boolean isImsSmsSupported() {
1918         boolean boSupported = false;
1919         try {
1920             ISms iSms = getISmsService();
1921             if (iSms != null) {
1922                 boSupported = iSms.isImsSmsSupportedForSubscriber(getSubscriptionId());
1923             }
1924         } catch (RemoteException ex) {
1925             // ignore it
1926         }
1927         return boSupported;
1928     }
1929 
1930     /**
1931      * Gets SMS format supported on IMS.  SMS over IMS format is either 3GPP or 3GPP2.
1932      *
1933      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
1934      * applications or the Telephony framework and will never trigger an SMS disambiguation
1935      * dialog. If this method is called on a device that has multiple active subscriptions, this
1936      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
1937      * default subscription is defined, the subscription ID associated with this message will be
1938      * INVALID, which will result in the operation being completed on the subscription associated
1939      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
1940      * operation is performed on the correct subscription.
1941      * </p>
1942      *
1943      * @return SmsMessage.FORMAT_3GPP,
1944      *         SmsMessage.FORMAT_3GPP2
1945      *      or SmsMessage.FORMAT_UNKNOWN
1946      *
1947      * @see #isImsSmsSupported()
1948      *
1949      * @hide
1950      */
getImsSmsFormat()1951     public String getImsSmsFormat() {
1952         String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
1953         try {
1954             ISms iSms = getISmsService();
1955             if (iSms != null) {
1956                 format = iSms.getImsSmsFormatForSubscriber(getSubscriptionId());
1957             }
1958         } catch (RemoteException ex) {
1959             // ignore it
1960         }
1961         return format;
1962     }
1963 
1964     /**
1965      * Get default sms subscription id.
1966      *
1967      * <p class="note"><strong>Note:</strong>This returns a value different from
1968      * {@link SubscriptionManager#getDefaultSmsSubscriptionId} if the user has not chosen a default.
1969      * In this case it returns the active subscription id if there's only one active subscription
1970      * available.
1971      *
1972      * @return the user-defined default SMS subscription id, or the active subscription id if
1973      * there's only one active subscription available, otherwise
1974      * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
1975      */
getDefaultSmsSubscriptionId()1976     public static int getDefaultSmsSubscriptionId() {
1977         try {
1978             return getISmsService().getPreferredSmsSubscription();
1979         } catch (RemoteException e) {
1980             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1981         } catch (NullPointerException e) {
1982             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1983         }
1984     }
1985 
1986     /**
1987      * Get SMS prompt property,  enabled or not
1988      *
1989      * @return true if enabled, false otherwise
1990      * @hide
1991      */
1992     @UnsupportedAppUsage
isSMSPromptEnabled()1993     public boolean isSMSPromptEnabled() {
1994         ISms iSms = null;
1995         try {
1996             iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
1997             return iSms.isSMSPromptEnabled();
1998         } catch (RemoteException ex) {
1999             return false;
2000         } catch (NullPointerException ex) {
2001             return false;
2002         }
2003     }
2004 
2005     // see SmsMessage.getStatusOnIcc
2006 
2007     /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
2008     static public final int STATUS_ON_ICC_FREE      = 0;
2009 
2010     /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
2011     static public final int STATUS_ON_ICC_READ      = 1;
2012 
2013     /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
2014     static public final int STATUS_ON_ICC_UNREAD    = 3;
2015 
2016     /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
2017     static public final int STATUS_ON_ICC_SENT      = 5;
2018 
2019     /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
2020     static public final int STATUS_ON_ICC_UNSENT    = 7;
2021 
2022     // SMS send failure result codes
2023 
2024     /**
2025      * No error.
2026      * @hide
2027      */
2028     @SystemApi
2029     static public final int RESULT_ERROR_NONE    = 0;
2030     /** Generic failure cause */
2031     static public final int RESULT_ERROR_GENERIC_FAILURE    = 1;
2032     /** Failed because radio was explicitly turned off */
2033     static public final int RESULT_ERROR_RADIO_OFF          = 2;
2034     /** Failed because no pdu provided */
2035     static public final int RESULT_ERROR_NULL_PDU           = 3;
2036     /** Failed because service is currently unavailable */
2037     static public final int RESULT_ERROR_NO_SERVICE         = 4;
2038     /** Failed because we reached the sending queue limit. */
2039     static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
2040     /**
2041      * Failed because FDN is enabled.
2042      * @hide
2043      */
2044     @SystemApi
2045     static public final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
2046     /** Failed because user denied the sending of this short code. */
2047     static public final int RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7;
2048     /** Failed because the user has denied this app ever send premium short codes. */
2049     static public final int RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8;
2050     /**
2051      * Failed because the radio was not available
2052      * @hide
2053      */
2054     @SystemApi
2055     static public final int RESULT_RADIO_NOT_AVAILABLE = 9;
2056     /**
2057      * Failed because of network rejection
2058      * @hide
2059      */
2060     @SystemApi
2061     static public final int RESULT_NETWORK_REJECT = 10;
2062     /**
2063      * Failed because of invalid arguments
2064      * @hide
2065      */
2066     @SystemApi
2067     static public final int RESULT_INVALID_ARGUMENTS = 11;
2068     /**
2069      * Failed because of an invalid state
2070      * @hide
2071      */
2072     @SystemApi
2073     static public final int RESULT_INVALID_STATE = 12;
2074     /**
2075      * Failed because there is no memory
2076      * @hide
2077      */
2078     @SystemApi
2079     static public final int RESULT_NO_MEMORY = 13;
2080     /**
2081      * Failed because the sms format is not valid
2082      * @hide
2083      */
2084     @SystemApi
2085     static public final int RESULT_INVALID_SMS_FORMAT = 14;
2086     /**
2087      * Failed because of a system error
2088      * @hide
2089      */
2090     @SystemApi
2091     static public final int RESULT_SYSTEM_ERROR = 15;
2092     /**
2093      * Failed because of a modem error
2094      * @hide
2095      */
2096     @SystemApi
2097     static public final int RESULT_MODEM_ERROR = 16;
2098     /**
2099      * Failed because of a network error
2100      * @hide
2101      */
2102     @SystemApi
2103     static public final int RESULT_NETWORK_ERROR = 17;
2104     /**
2105      * Failed because of an encoding error
2106      * @hide
2107      */
2108     @SystemApi
2109     static public final int RESULT_ENCODING_ERROR = 18;
2110     /**
2111      * Failed because of an invalid smsc address
2112      * @hide
2113      */
2114     @SystemApi
2115     static public final int RESULT_INVALID_SMSC_ADDRESS = 19;
2116     /**
2117      * Failed because the operation is not allowed
2118      * @hide
2119      */
2120     @SystemApi
2121     static public final int RESULT_OPERATION_NOT_ALLOWED = 20;
2122     /**
2123      * Failed because of an internal error
2124      * @hide
2125      */
2126     @SystemApi
2127     static public final int RESULT_INTERNAL_ERROR = 21;
2128     /**
2129      * Failed because there are no resources
2130      * @hide
2131      */
2132     @SystemApi
2133     static public final int RESULT_NO_RESOURCES = 22;
2134     /**
2135      * Failed because the operation was cancelled
2136      * @hide
2137      */
2138     @SystemApi
2139     static public final int RESULT_CANCELLED = 23;
2140     /**
2141      * Failed because the request is not supported
2142      * @hide
2143      */
2144     @SystemApi
2145     static public final int RESULT_REQUEST_NOT_SUPPORTED = 24;
2146 
2147 
2148     static private final String PHONE_PACKAGE_NAME = "com.android.phone";
2149 
2150     /**
2151      * Send an MMS message
2152      *
2153      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
2154      * dialog. If this method is called on a device that has multiple active subscriptions, this
2155      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
2156      * default subscription is defined, the subscription ID associated with this message will be
2157      * INVALID, which will result in the operation being completed on the subscription associated
2158      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
2159      * operation is performed on the correct subscription.
2160      * </p>
2161      *
2162      * @param context application context
2163      * @param contentUri the content Uri from which the message pdu will be read
2164      * @param locationUrl the optional location url where message should be sent to
2165      * @param configOverrides the carrier-specific messaging configuration values to override for
2166      *  sending the message.
2167      * @param sentIntent if not NULL this <code>PendingIntent</code> is
2168      *  broadcast when the message is successfully sent, or failed
2169      * @throws IllegalArgumentException if contentUri is empty
2170      */
sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent)2171     public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
2172             Bundle configOverrides, PendingIntent sentIntent) {
2173         if (contentUri == null) {
2174             throw new IllegalArgumentException("Uri contentUri null");
2175         }
2176         try {
2177             final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2178             if (iMms == null) {
2179                 return;
2180             }
2181 
2182             iMms.sendMessage(getSubscriptionId(), ActivityThread.currentPackageName(), contentUri,
2183                     locationUrl, configOverrides, sentIntent);
2184         } catch (RemoteException e) {
2185             // Ignore it
2186         }
2187     }
2188 
2189     /**
2190      * Download an MMS message from carrier by a given location URL
2191      *
2192      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
2193      * dialog. If this method is called on a device that has multiple active subscriptions, this
2194      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
2195      * default subscription is defined, the subscription ID associated with this message will be
2196      * INVALID, which will result in the operation being completed on the subscription associated
2197      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
2198      * operation is performed on the correct subscription.
2199      * </p>
2200      *
2201      * @param context application context
2202      * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
2203      *  from the MMS WAP push notification
2204      * @param contentUri the content uri to which the downloaded pdu will be written
2205      * @param configOverrides the carrier-specific messaging configuration values to override for
2206      *  downloading the message.
2207      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
2208      *  broadcast when the message is downloaded, or the download is failed
2209      * @throws IllegalArgumentException if locationUrl or contentUri is empty
2210      */
downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent)2211     public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
2212             Bundle configOverrides, PendingIntent downloadedIntent) {
2213         if (TextUtils.isEmpty(locationUrl)) {
2214             throw new IllegalArgumentException("Empty MMS location URL");
2215         }
2216         if (contentUri == null) {
2217             throw new IllegalArgumentException("Uri contentUri null");
2218         }
2219         try {
2220             final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2221             if (iMms == null) {
2222                 return;
2223             }
2224             iMms.downloadMessage(getSubscriptionId(), ActivityThread.currentPackageName(),
2225                     locationUrl, contentUri, configOverrides, downloadedIntent);
2226         } catch (RemoteException e) {
2227             // Ignore it
2228         }
2229     }
2230 
2231     // MMS send/download failure result codes
2232     public static final int MMS_ERROR_UNSPECIFIED = 1;
2233     public static final int MMS_ERROR_INVALID_APN = 2;
2234     public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
2235     public static final int MMS_ERROR_HTTP_FAILURE = 4;
2236     public static final int MMS_ERROR_IO_ERROR = 5;
2237     public static final int MMS_ERROR_RETRY = 6;
2238     public static final int MMS_ERROR_CONFIGURATION_ERROR = 7;
2239     public static final int MMS_ERROR_NO_DATA_NETWORK = 8;
2240 
2241     /** Intent extra name for MMS sending result data in byte array type */
2242     public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
2243     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
2244     public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
2245 
2246     /**
2247      * Import a text message into system's SMS store
2248      *
2249      * Only default SMS apps can import SMS
2250      *
2251      * @param address the destination(source) address of the sent(received) message
2252      * @param type the type of the message
2253      * @param text the message text
2254      * @param timestampMillis the message timestamp in milliseconds
2255      * @param seen if the message is seen
2256      * @param read if the message is read
2257      * @return the message URI, null if failed
2258      * @hide
2259      */
importTextMessage(String address, int type, String text, long timestampMillis, boolean seen, boolean read)2260     public Uri importTextMessage(String address, int type, String text, long timestampMillis,
2261             boolean seen, boolean read) {
2262         try {
2263             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2264             if (iMms != null) {
2265                 return iMms.importTextMessage(ActivityThread.currentPackageName(),
2266                         address, type, text, timestampMillis, seen, read);
2267             }
2268         } catch (RemoteException ex) {
2269             // ignore it
2270         }
2271         return null;
2272     }
2273 
2274     /** Represents the received SMS message for importing {@hide} */
2275     public static final int SMS_TYPE_INCOMING = 0;
2276     /** Represents the sent SMS message for importing {@hide} */
2277     public static final int SMS_TYPE_OUTGOING = 1;
2278 
2279     /**
2280      * Import a multimedia message into system's MMS store. Only the following PDU type is
2281      * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind
2282      *
2283      * Only default SMS apps can import MMS
2284      *
2285      * @param contentUri the content uri from which to read the PDU of the message to import
2286      * @param messageId the optional message id. Use null if not specifying
2287      * @param timestampSecs the optional message timestamp. Use -1 if not specifying
2288      * @param seen if the message is seen
2289      * @param read if the message is read
2290      * @return the message URI, null if failed
2291      * @throws IllegalArgumentException if pdu is empty
2292      * {@hide}
2293      */
importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs, boolean seen, boolean read)2294     public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs,
2295             boolean seen, boolean read) {
2296         if (contentUri == null) {
2297             throw new IllegalArgumentException("Uri contentUri null");
2298         }
2299         try {
2300             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2301             if (iMms != null) {
2302                 return iMms.importMultimediaMessage(ActivityThread.currentPackageName(),
2303                         contentUri, messageId, timestampSecs, seen, read);
2304             }
2305         } catch (RemoteException ex) {
2306             // ignore it
2307         }
2308         return null;
2309     }
2310 
2311     /**
2312      * Delete a system stored SMS or MMS message
2313      *
2314      * Only default SMS apps can delete system stored SMS and MMS messages
2315      *
2316      * @param messageUri the URI of the stored message
2317      * @return true if deletion is successful, false otherwise
2318      * @throws IllegalArgumentException if messageUri is empty
2319      * {@hide}
2320      */
deleteStoredMessage(Uri messageUri)2321     public boolean deleteStoredMessage(Uri messageUri) {
2322         if (messageUri == null) {
2323             throw new IllegalArgumentException("Empty message URI");
2324         }
2325         try {
2326             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2327             if (iMms != null) {
2328                 return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri);
2329             }
2330         } catch (RemoteException ex) {
2331             // ignore it
2332         }
2333         return false;
2334     }
2335 
2336     /**
2337      * Delete a system stored SMS or MMS thread
2338      *
2339      * Only default SMS apps can delete system stored SMS and MMS conversations
2340      *
2341      * @param conversationId the ID of the message conversation
2342      * @return true if deletion is successful, false otherwise
2343      * {@hide}
2344      */
deleteStoredConversation(long conversationId)2345     public boolean deleteStoredConversation(long conversationId) {
2346         try {
2347             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2348             if (iMms != null) {
2349                 return iMms.deleteStoredConversation(
2350                         ActivityThread.currentPackageName(), conversationId);
2351             }
2352         } catch (RemoteException ex) {
2353             // ignore it
2354         }
2355         return false;
2356     }
2357 
2358     /**
2359      * Update the status properties of a system stored SMS or MMS message, e.g.
2360      * the read status of a message, etc.
2361      *
2362      * @param messageUri the URI of the stored message
2363      * @param statusValues a list of status properties in key-value pairs to update
2364      * @return true if update is successful, false otherwise
2365      * @throws IllegalArgumentException if messageUri is empty
2366      * {@hide}
2367      */
updateStoredMessageStatus(Uri messageUri, ContentValues statusValues)2368     public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) {
2369         if (messageUri == null) {
2370             throw new IllegalArgumentException("Empty message URI");
2371         }
2372         try {
2373             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2374             if (iMms != null) {
2375                 return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(),
2376                         messageUri, statusValues);
2377             }
2378         } catch (RemoteException ex) {
2379             // ignore it
2380         }
2381         return false;
2382     }
2383 
2384     /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */
2385     public static final String MESSAGE_STATUS_SEEN = "seen";
2386     /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */
2387     public static final String MESSAGE_STATUS_READ = "read";
2388 
2389     /**
2390      * Archive or unarchive a stored conversation
2391      *
2392      * @param conversationId the ID of the message conversation
2393      * @param archived true to archive the conversation, false to unarchive
2394      * @return true if update is successful, false otherwise
2395      * {@hide}
2396      */
archiveStoredConversation(long conversationId, boolean archived)2397     public boolean archiveStoredConversation(long conversationId, boolean archived) {
2398         try {
2399             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2400             if (iMms != null) {
2401                 return iMms.archiveStoredConversation(ActivityThread.currentPackageName(),
2402                         conversationId, archived);
2403             }
2404         } catch (RemoteException ex) {
2405             // ignore it
2406         }
2407         return false;
2408     }
2409 
2410     /**
2411      * Add a text message draft to system SMS store
2412      *
2413      * Only default SMS apps can add SMS draft
2414      *
2415      * @param address the destination address of message
2416      * @param text the body of the message to send
2417      * @return the URI of the stored draft message
2418      * {@hide}
2419      */
addTextMessageDraft(String address, String text)2420     public Uri addTextMessageDraft(String address, String text) {
2421         try {
2422             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2423             if (iMms != null) {
2424                 return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text);
2425             }
2426         } catch (RemoteException ex) {
2427             // ignore it
2428         }
2429         return null;
2430     }
2431 
2432     /**
2433      * Add a multimedia message draft to system MMS store
2434      *
2435      * Only default SMS apps can add MMS draft
2436      *
2437      * @param contentUri the content uri from which to read the PDU data of the draft MMS
2438      * @return the URI of the stored draft message
2439      * @throws IllegalArgumentException if pdu is empty
2440      * {@hide}
2441      */
addMultimediaMessageDraft(Uri contentUri)2442     public Uri addMultimediaMessageDraft(Uri contentUri) {
2443         if (contentUri == null) {
2444             throw new IllegalArgumentException("Uri contentUri null");
2445         }
2446         try {
2447             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2448             if (iMms != null) {
2449                 return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(),
2450                         contentUri);
2451             }
2452         } catch (RemoteException ex) {
2453             // ignore it
2454         }
2455         return null;
2456     }
2457 
2458     /**
2459      * Send a system stored text message.
2460      *
2461      * You can only send a failed text message or a draft text message.
2462      *
2463      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
2464      * manager on a multi-SIM device, this operation may fail sending the SMS message because no
2465      * suitable default subscription could be found. In this case, if {@code sentIntent} is
2466      * non-null, then the {@link PendingIntent} will be sent with an error code
2467      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
2468      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
2469      * where this operation may fail.
2470      * </p>
2471      *
2472      * @param messageUri the URI of the stored message
2473      * @param scAddress is the service center address or null to use the current default SMSC
2474      * @param sentIntent if not NULL this <code>PendingIntent</code> is
2475      *  broadcast when the message is successfully sent, or failed.
2476      *  The result code will be <code>Activity.RESULT_OK</code> for success,
2477      *  or one of these errors:<br>
2478      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
2479      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
2480      *  <code>RESULT_ERROR_NULL_PDU</code><br>
2481      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
2482      *  the extra "errorCode" containing a radio technology specific value,
2483      *  generally only useful for troubleshooting.<br>
2484      *  The per-application based SMS control checks sentIntent. If sentIntent
2485      *  is NULL the caller will be checked against all unknown applications,
2486      *  which cause smaller number of SMS to be sent in checking period.
2487      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
2488      *  broadcast when the message is delivered to the recipient.  The
2489      *  raw pdu of the status report is in the extended data ("pdu").
2490      *
2491      * @throws IllegalArgumentException if messageUri is empty
2492      * {@hide}
2493      */
sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)2494     public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent,
2495             PendingIntent deliveryIntent) {
2496         if (messageUri == null) {
2497             throw new IllegalArgumentException("Empty message URI");
2498         }
2499         final Context context = ActivityThread.currentApplication().getApplicationContext();
2500         resolveSubscriptionForOperation(new SubscriptionResolverResult() {
2501             @Override
2502             public void onSuccess(int subId) {
2503                 try {
2504                     ISms iSms = getISmsServiceOrThrow();
2505                     iSms.sendStoredText(subId, ActivityThread.currentPackageName(), messageUri,
2506                             scAddress, sentIntent, deliveryIntent);
2507                 } catch (RemoteException e) {
2508                     Log.e(TAG, "sendStoredTextMessage: Couldn't send SMS - Exception: "
2509                             + e.getMessage());
2510                     notifySmsGenericError(sentIntent);
2511                 }
2512             }
2513             @Override
2514             public void onFailure() {
2515                 notifySmsErrorNoDefaultSet(context, sentIntent);
2516             }
2517         });
2518     }
2519 
2520     /**
2521      * Send a system stored multi-part text message.
2522      *
2523      * You can only send a failed text message or a draft text message.
2524      * The provided <code>PendingIntent</code> lists should match the part number of the
2525      * divided text of the stored message by using <code>divideMessage</code>
2526      *
2527      * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
2528      * manager on a multi-SIM device, this operation may fail sending the SMS message because no
2529      * suitable default subscription could be found. In this case, if {@code sentIntent} is
2530      * non-null, then the {@link PendingIntent} will be sent with an error code
2531      * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
2532      * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
2533      * where this operation may fail.
2534      * </p>
2535      *
2536      * @param messageUri the URI of the stored message
2537      * @param scAddress is the service center address or null to use
2538      *   the current default SMSC
2539      * @param sentIntents if not null, an <code>ArrayList</code> of
2540      *   <code>PendingIntent</code>s (one for each message part) that is
2541      *   broadcast when the corresponding message part has been sent.
2542      *   The result code will be <code>Activity.RESULT_OK</code> for success,
2543      *   or one of these errors:<br>
2544      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
2545      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
2546      *   <code>RESULT_ERROR_NULL_PDU</code><br>
2547      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
2548      *   the extra "errorCode" containing a radio technology specific value,
2549      *   generally only useful for troubleshooting.<br>
2550      *   The per-application based SMS control checks sentIntent. If sentIntent
2551      *   is NULL the caller will be checked against all unknown applications,
2552      *   which cause smaller number of SMS to be sent in checking period.
2553      * @param deliveryIntents if not null, an <code>ArrayList</code> of
2554      *   <code>PendingIntent</code>s (one for each message part) that is
2555      *   broadcast when the corresponding message part has been delivered
2556      *   to the recipient.  The raw pdu of the status report is in the
2557      *   extended data ("pdu").
2558      *
2559      * @throws IllegalArgumentException if messageUri is empty
2560      * {@hide}
2561      */
sendStoredMultipartTextMessage(Uri messageUri, String scAddress, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)2562     public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress,
2563             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
2564         if (messageUri == null) {
2565             throw new IllegalArgumentException("Empty message URI");
2566         }
2567         final Context context = ActivityThread.currentApplication().getApplicationContext();
2568         resolveSubscriptionForOperation(new SubscriptionResolverResult() {
2569             @Override
2570             public void onSuccess(int subId) {
2571                 try {
2572                     ISms iSms = getISmsServiceOrThrow();
2573                     iSms.sendStoredMultipartText(subId, ActivityThread.currentPackageName(),
2574                             messageUri, scAddress, sentIntents, deliveryIntents);
2575                 } catch (RemoteException e) {
2576                     Log.e(TAG, "sendStoredTextMessage: Couldn't send SMS - Exception: "
2577                             + e.getMessage());
2578                     notifySmsGenericError(sentIntents);
2579                 }
2580             }
2581             @Override
2582             public void onFailure() {
2583                 notifySmsErrorNoDefaultSet(context, sentIntents);
2584             }
2585         });
2586     }
2587 
2588     /**
2589      * Send a system stored MMS message
2590      *
2591      * This is used for sending a previously sent, but failed-to-send, message or
2592      * for sending a text message that has been stored as a draft.
2593      *
2594      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
2595      * dialog. If this method is called on a device that has multiple active subscriptions, this
2596      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
2597      * default subscription is defined, the subscription ID associated with this message will be
2598      * INVALID, which will result in the operation being completed on the subscription associated
2599      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
2600      * operation is performed on the correct subscription.
2601      * </p>
2602      *
2603      * @param messageUri the URI of the stored message
2604      * @param configOverrides the carrier-specific messaging configuration values to override for
2605      *  sending the message.
2606      * @param sentIntent if not NULL this <code>PendingIntent</code> is
2607      *  broadcast when the message is successfully sent, or failed
2608      * @throws IllegalArgumentException if messageUri is empty
2609      * {@hide}
2610      */
sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides, PendingIntent sentIntent)2611     public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides,
2612             PendingIntent sentIntent) {
2613         if (messageUri == null) {
2614             throw new IllegalArgumentException("Empty message URI");
2615         }
2616         try {
2617             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2618             if (iMms != null) {
2619                 iMms.sendStoredMessage(
2620                         getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
2621                         configOverrides, sentIntent);
2622             }
2623         } catch (RemoteException ex) {
2624             // ignore it
2625         }
2626     }
2627 
2628     /**
2629      * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system
2630      *
2631      * When this flag is on, all SMS/MMS sent/received are stored by system automatically
2632      * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
2633      * automatically
2634      *
2635      * This flag can only be changed by default SMS apps
2636      *
2637      * @param enabled Whether to enable message auto persisting
2638      * {@hide}
2639      */
setAutoPersisting(boolean enabled)2640     public void setAutoPersisting(boolean enabled) {
2641         try {
2642             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2643             if (iMms != null) {
2644                 iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled);
2645             }
2646         } catch (RemoteException ex) {
2647             // ignore it
2648         }
2649     }
2650 
2651     /**
2652      * Get the value of the flag to automatically write sent/received SMS/MMS messages into system
2653      *
2654      * When this flag is on, all SMS/MMS sent/received are stored by system automatically
2655      * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
2656      * automatically
2657      *
2658      * @return the current value of the auto persist flag
2659      * {@hide}
2660      */
getAutoPersisting()2661     public boolean getAutoPersisting() {
2662         try {
2663             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2664             if (iMms != null) {
2665                 return iMms.getAutoPersisting();
2666             }
2667         } catch (RemoteException ex) {
2668             // ignore it
2669         }
2670         return false;
2671     }
2672 
2673     /**
2674      * Get carrier-dependent configuration values.
2675      *
2676      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
2677      * applications or the Telephony framework and will never trigger an SMS disambiguation
2678      * dialog. If this method is called on a device that has multiple active subscriptions, this
2679      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
2680      * default subscription is defined, the subscription ID associated with this message will be
2681      * INVALID, which will result in the operation being completed on the subscription associated
2682      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
2683      * operation is performed on the correct subscription.
2684      * </p>
2685      *
2686      * @return bundle key/values pairs of configuration values
2687      */
getCarrierConfigValues()2688     public Bundle getCarrierConfigValues() {
2689         try {
2690             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
2691             if (iMms != null) {
2692                 return iMms.getCarrierConfigValues(getSubscriptionId());
2693             }
2694         } catch (RemoteException ex) {
2695             // ignore it
2696         }
2697         return null;
2698     }
2699 
2700     /**
2701      * Create a single use app specific incoming SMS request for the calling package.
2702      *
2703      * This method returns a token that if included in a subsequent incoming SMS message will cause
2704      * {@code intent} to be sent with the SMS data.
2705      *
2706      * The token is only good for one use, after an SMS has been received containing the token all
2707      * subsequent SMS messages with the token will be routed as normal.
2708      *
2709      * An app can only have one request at a time, if the app already has a request pending it will
2710      * be replaced with a new request.
2711      *
2712      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
2713      * dialog. If this method is called on a device that has multiple active subscriptions, this
2714      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
2715      * default subscription is defined, the subscription ID associated with this message will be
2716      * INVALID, which will result in the operation being completed on the subscription associated
2717      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
2718      * operation is performed on the correct subscription.
2719      * </p>
2720      *
2721      * @return Token to include in an SMS message. The token will be 11 characters long.
2722      * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent
2723      */
createAppSpecificSmsToken(PendingIntent intent)2724     public String createAppSpecificSmsToken(PendingIntent intent) {
2725         try {
2726             ISms iccSms = getISmsServiceOrThrow();
2727             return iccSms.createAppSpecificSmsToken(getSubscriptionId(),
2728                     ActivityThread.currentPackageName(), intent);
2729 
2730         } catch (RemoteException ex) {
2731             ex.rethrowFromSystemServer();
2732             return null;
2733         }
2734     }
2735 
2736     /** callback for providing asynchronous sms messages for financial app. */
2737     public abstract static class FinancialSmsCallback {
2738         /**
2739          * Callback to send sms messages back to financial app asynchronously.
2740          *
2741          * @param msgs SMS messages.
2742          */
onFinancialSmsMessages(CursorWindow msgs)2743         public abstract void onFinancialSmsMessages(CursorWindow msgs);
2744     };
2745 
2746     /**
2747      * Get SMS messages for the calling financial app.
2748      * The result will be delivered asynchronously in the passing in callback interface.
2749      *
2750      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
2751      * dialog. If this method is called on a device that has multiple active subscriptions, this
2752      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
2753      * default subscription is defined, the subscription ID associated with this message will be
2754      * INVALID, which will result in the operation being completed on the subscription associated
2755      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
2756      * operation is performed on the correct subscription.
2757      * </p>
2758      *
2759      * @param params the parameters to filter SMS messages returned.
2760      * @param executor the executor on which callback will be invoked.
2761      * @param callback a callback to receive CursorWindow with SMS messages.
2762      */
2763     @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS)
getSmsMessagesForFinancialApp( Bundle params, @NonNull @CallbackExecutor Executor executor, @NonNull FinancialSmsCallback callback)2764     public void getSmsMessagesForFinancialApp(
2765             Bundle params,
2766             @NonNull @CallbackExecutor Executor executor,
2767             @NonNull FinancialSmsCallback callback) {
2768         try {
2769             ISms iccSms = getISmsServiceOrThrow();
2770             iccSms.getSmsMessagesForFinancialApp(
2771                     getSubscriptionId(), ActivityThread.currentPackageName(), params,
2772                     new IFinancialSmsCallback.Stub() {
2773                         public void onGetSmsMessagesForFinancialApp(CursorWindow msgs) {
2774                             Binder.withCleanCallingIdentity(() -> executor.execute(
2775                                     () -> callback.onFinancialSmsMessages(msgs)));
2776                         }});
2777         } catch (RemoteException ex) {
2778             ex.rethrowFromSystemServer();
2779         }
2780     }
2781 
2782     /**
2783      * @see #createAppSpecificSmsTokenWithPackageInfo().
2784      * The prefixes is a list of prefix {@code String} separated by this delimiter.
2785      * @hide
2786      */
2787     public static final String REGEX_PREFIX_DELIMITER = ",";
2788     /**
2789      * @see #createAppSpecificSmsTokenWithPackageInfo().
2790      * The success status to be added into the intent to be sent to the calling package.
2791      * @hide
2792      */
2793     public static final int RESULT_STATUS_SUCCESS = 0;
2794     /**
2795      * @see #createAppSpecificSmsTokenWithPackageInfo().
2796      * The timeout status to be added into the intent to be sent to the calling package.
2797      * @hide
2798      */
2799     public static final int RESULT_STATUS_TIMEOUT = 1;
2800     /**
2801      * @see #createAppSpecificSmsTokenWithPackageInfo().
2802      * Intent extra key of the retrieved SMS message as a {@code String}.
2803      * @hide
2804      */
2805     public static final String EXTRA_SMS_MESSAGE = "android.telephony.extra.SMS_MESSAGE";
2806     /**
2807      * @see #createAppSpecificSmsTokenWithPackageInfo().
2808      * Intent extra key of SMS retriever status, which indicates whether the request for the
2809      * coming SMS message is SUCCESS or TIMEOUT
2810      * @hide
2811      */
2812     public static final String EXTRA_STATUS = "android.telephony.extra.STATUS";
2813     /**
2814      * @see #createAppSpecificSmsTokenWithPackageInfo().
2815      * [Optional] Intent extra key of the retrieved Sim card subscription Id if any. {@code int}
2816      * @hide
2817      */
2818     public static final String EXTRA_SIM_SUBSCRIPTION_ID =
2819             "android.telephony.extra.SIM_SUBSCRIPTION_ID";
2820 
2821     /**
2822      * Create a single use app specific incoming SMS request for the calling package.
2823      *
2824      * This method returns a token that if included in a subsequent incoming SMS message, and the
2825      * SMS message has a prefix from the given prefixes list, the provided {@code intent} will be
2826      * sent with the SMS data to the calling package.
2827      *
2828      * The token is only good for one use within a reasonable amount of time. After an SMS has been
2829      * received containing the token all subsequent SMS messages with the token will be routed as
2830      * normal.
2831      *
2832      * An app can only have one request at a time, if the app already has a request pending it will
2833      * be replaced with a new request.
2834      *
2835      * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
2836      * dialog. If this method is called on a device that has multiple active subscriptions, this
2837      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
2838      * default subscription is defined, the subscription ID associated with this message will be
2839      * INVALID, which will result in the operation being completed on the subscription associated
2840      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
2841      * operation is performed on the correct subscription.
2842      * </p>
2843      *
2844      * @param prefixes this is a list of prefixes string separated by REGEX_PREFIX_DELIMITER. The
2845      *  matching SMS message should have at least one of the prefixes in the beginning of the
2846      *  message.
2847      * @param intent this intent is sent when the matching SMS message is received.
2848      * @return Token to include in an SMS message.
2849      */
2850     @Nullable
createAppSpecificSmsTokenWithPackageInfo( @ullable String prefixes, @NonNull PendingIntent intent)2851     public String createAppSpecificSmsTokenWithPackageInfo(
2852             @Nullable String prefixes, @NonNull PendingIntent intent) {
2853         try {
2854             ISms iccSms = getISmsServiceOrThrow();
2855             return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(),
2856                     ActivityThread.currentPackageName(), prefixes, intent);
2857 
2858         } catch (RemoteException ex) {
2859             ex.rethrowFromSystemServer();
2860             return null;
2861         }
2862     }
2863 
2864     /**
2865      * Filters a bundle to only contain MMS config variables.
2866      *
2867      * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS
2868      * config and unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the
2869      * supplied bundle.
2870      *
2871      * @param config a Bundle that contains MMS config variables and possibly more.
2872      * @return a new Bundle that only contains the MMS_CONFIG_* keys defined above.
2873      * @hide
2874      */
getMmsConfig(BaseBundle config)2875     public static Bundle getMmsConfig(BaseBundle config) {
2876         Bundle filtered = new Bundle();
2877         filtered.putBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID,
2878                 config.getBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID));
2879         filtered.putBoolean(MMS_CONFIG_MMS_ENABLED, config.getBoolean(MMS_CONFIG_MMS_ENABLED));
2880         filtered.putBoolean(MMS_CONFIG_GROUP_MMS_ENABLED,
2881                 config.getBoolean(MMS_CONFIG_GROUP_MMS_ENABLED));
2882         filtered.putBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED,
2883                 config.getBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED));
2884         filtered.putBoolean(MMS_CONFIG_ALIAS_ENABLED, config.getBoolean(MMS_CONFIG_ALIAS_ENABLED));
2885         filtered.putBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO,
2886                 config.getBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO));
2887         filtered.putBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED,
2888                 config.getBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED));
2889         filtered.putBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED,
2890                 config.getBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED));
2891         filtered.putBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
2892                 config.getBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION));
2893         filtered.putBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES,
2894                 config.getBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES));
2895         filtered.putBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED,
2896                 config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED));
2897         filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED,
2898                 config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED));
2899         filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION,
2900                 config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION));
2901         filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE));
2902         filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH));
2903         filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT));
2904         filtered.putInt(MMS_CONFIG_RECIPIENT_LIMIT, config.getInt(MMS_CONFIG_RECIPIENT_LIMIT));
2905         filtered.putInt(MMS_CONFIG_ALIAS_MIN_CHARS, config.getInt(MMS_CONFIG_ALIAS_MIN_CHARS));
2906         filtered.putInt(MMS_CONFIG_ALIAS_MAX_CHARS, config.getInt(MMS_CONFIG_ALIAS_MAX_CHARS));
2907         filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD,
2908                 config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD));
2909         filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD,
2910                 config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD));
2911         filtered.putInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE,
2912                 config.getInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE));
2913         filtered.putInt(MMS_CONFIG_SUBJECT_MAX_LENGTH,
2914                 config.getInt(MMS_CONFIG_SUBJECT_MAX_LENGTH));
2915         filtered.putInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT,
2916                 config.getInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
2917         filtered.putString(MMS_CONFIG_UA_PROF_TAG_NAME,
2918                 config.getString(MMS_CONFIG_UA_PROF_TAG_NAME));
2919         filtered.putString(MMS_CONFIG_USER_AGENT, config.getString(MMS_CONFIG_USER_AGENT));
2920         filtered.putString(MMS_CONFIG_UA_PROF_URL, config.getString(MMS_CONFIG_UA_PROF_URL));
2921         filtered.putString(MMS_CONFIG_HTTP_PARAMS, config.getString(MMS_CONFIG_HTTP_PARAMS));
2922         filtered.putString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER,
2923                 config.getString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER));
2924         filtered.putString(MMS_CONFIG_NAI_SUFFIX, config.getString(MMS_CONFIG_NAI_SUFFIX));
2925         filtered.putBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS,
2926                 config.getBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS));
2927         filtered.putBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER,
2928                 config.getBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER));
2929         return filtered;
2930     }
2931 
2932     /** @hide */
2933     @Retention(RetentionPolicy.SOURCE)
2934     @IntDef(prefix = {"SMS_CATEGORY_"},
2935             value = {
2936                     SmsManager.SMS_CATEGORY_NOT_SHORT_CODE,
2937                     SmsManager.SMS_CATEGORY_FREE_SHORT_CODE,
2938                     SmsManager.SMS_CATEGORY_STANDARD_SHORT_CODE,
2939                     SmsManager.SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE,
2940                     SmsManager.SMS_CATEGORY_PREMIUM_SHORT_CODE})
2941     public @interface SmsShortCodeCategory {}
2942 
2943     /**
2944      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for regular
2945      * phone numbers.
2946      * @hide
2947      */
2948     @TestApi
2949     public static final int SMS_CATEGORY_NOT_SHORT_CODE = 0;
2950     /**
2951      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for free
2952      * (no cost) short codes.
2953      * @hide
2954      */
2955     @TestApi
2956     public static final int SMS_CATEGORY_FREE_SHORT_CODE = 1;
2957     /**
2958      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for
2959      * standard rate (non-premium)
2960      * short codes.
2961      * @hide
2962      */
2963     @TestApi
2964     public static final int SMS_CATEGORY_STANDARD_SHORT_CODE = 2;
2965     /**
2966      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for possible
2967      * premium short codes.
2968      * @hide
2969      */
2970     @TestApi
2971     public static final int SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3;
2972     /**
2973      * Return value from {@link #checkSmsShortCodeDestination(String, String)} ()} for
2974      * premium short codes.
2975      * @hide
2976      */
2977     @TestApi
2978     public static final int SMS_CATEGORY_PREMIUM_SHORT_CODE = 4;
2979 
2980     /**
2981      * Check if the destination address is a possible premium short code.
2982      * NOTE: the caller is expected to strip non-digits from the destination number with
2983      * {@link PhoneNumberUtils#extractNetworkPortion} before calling this method.
2984      *
2985      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
2986      * applications or the Telephony framework and will never trigger an SMS disambiguation
2987      * dialog. If this method is called on a device that has multiple active subscriptions, this
2988      * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
2989      * default subscription is defined, the subscription ID associated with this message will be
2990      * INVALID, which will result in the operation being completed on the subscription associated
2991      * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
2992      * operation is performed on the correct subscription.
2993      * </p>
2994      *
2995      * @param destAddress the destination address to test for possible short code
2996      * @param countryIso the ISO country code
2997      *
2998      * @return
2999      * {@link SmsManager#SMS_CATEGORY_NOT_SHORT_CODE},
3000      * {@link SmsManager#SMS_CATEGORY_FREE_SHORT_CODE},
3001      * {@link SmsManager#SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE},
3002      * {@link SmsManager#SMS_CATEGORY_PREMIUM_SHORT_CODE}, or
3003      * {@link SmsManager#SMS_CATEGORY_STANDARD_SHORT_CODE}
3004      *
3005      * @hide
3006      */
3007     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
3008     @TestApi
checkSmsShortCodeDestination( String destAddress, String countryIso)3009     public @SmsShortCodeCategory int checkSmsShortCodeDestination(
3010             String destAddress, String countryIso) {
3011         try {
3012             ISms iccISms = getISmsServiceOrThrow();
3013             if (iccISms != null) {
3014                 return iccISms.checkSmsShortCodeDestination(getSubscriptionId(),
3015                         ActivityThread.currentPackageName(), destAddress, countryIso);
3016             }
3017         } catch (RemoteException e) {
3018             Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e);
3019         }
3020         return SmsManager.SMS_CATEGORY_NOT_SHORT_CODE;
3021     }
3022 }
3023