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.RequiresPermission;
20 import android.annotation.SuppressAutoDoc;
21 import android.annotation.SystemApi;
22 import android.app.ActivityThread;
23 import android.app.PendingIntent;
24 import android.content.ActivityNotFoundException;
25 import android.content.ContentValues;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.net.Uri;
29 import android.os.BaseBundle;
30 import android.os.Bundle;
31 import android.os.RemoteException;
32 import android.os.ServiceManager;
33 import android.text.TextUtils;
34 import android.util.ArrayMap;
35 import android.util.Log;
36 
37 import com.android.internal.telephony.IMms;
38 import com.android.internal.telephony.ISms;
39 import com.android.internal.telephony.SmsRawData;
40 
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.List;
44 import java.util.Map;
45 
46 /*
47  * TODO(code review): Curious question... Why are a lot of these
48  * methods not declared as static, since they do not seem to require
49  * any local object state?  Presumably this cannot be changed without
50  * interfering with the API...
51  */
52 
53 /**
54  * Manages SMS operations such as sending data, text, and pdu SMS messages.
55  * Get this object by calling the static method {@link #getDefault()}.
56  *
57  * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19)
58  * and higher, see {@link android.provider.Telephony}.
59  */
60 public final class SmsManager {
61     private static final String TAG = "SmsManager";
62     /**
63      * A psuedo-subId that represents the default subId at any given time. The actual subId it
64      * represents changes as the default subId is changed.
65      */
66     private static final int DEFAULT_SUBSCRIPTION_ID = -1002;
67 
68     /** Singleton object constructed during class initialization. */
69     private static final SmsManager sInstance = new SmsManager(DEFAULT_SUBSCRIPTION_ID);
70     private static final Object sLockObject = new Object();
71 
72     /** @hide */
73     public static final int CELL_BROADCAST_RAN_TYPE_GSM = 0;
74     /** @hide */
75     public static final int CELL_BROADCAST_RAN_TYPE_CDMA = 1;
76 
77     /** SMS record length from TS 51.011 10.5.3
78      * @hide
79      */
80     public static final int SMS_RECORD_LENGTH = 176;
81 
82     /** SMS record length from C.S0023 3.4.27
83      * @hide
84      */
85     public static final int CDMA_SMS_RECORD_LENGTH = 255;
86 
87     private static final Map<Integer, SmsManager> sSubInstances =
88             new ArrayMap<Integer, SmsManager>();
89 
90     /** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */
91     private int mSubId;
92 
93     /*
94      * Key for the various carrier-dependent configuration values.
95      * Some of the values are used by the system in processing SMS or MMS messages. Others
96      * are provided for the convenience of SMS applications.
97      */
98 
99     /**
100      * Whether to append transaction id to MMS WAP Push M-Notification.ind's content location URI
101      * when constructing the download URL of a new MMS (boolean type)
102      */
103     public static final String MMS_CONFIG_APPEND_TRANSACTION_ID =
104             CarrierConfigManager.KEY_MMS_APPEND_TRANSACTION_ID_BOOL;
105     /**
106      * Whether MMS is enabled for the current carrier (boolean type)
107      */
108     public static final String
109         MMS_CONFIG_MMS_ENABLED = CarrierConfigManager.KEY_MMS_MMS_ENABLED_BOOL;
110     /**
111      * Whether group MMS is enabled for the current carrier (boolean type)
112      */
113     public static final String
114             MMS_CONFIG_GROUP_MMS_ENABLED = CarrierConfigManager.KEY_MMS_GROUP_MMS_ENABLED_BOOL;
115     /**
116      * If this is enabled, M-NotifyResp.ind should be sent to the WAP Push content location instead
117      * of the default MMSC (boolean type)
118      */
119     public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED =
120             CarrierConfigManager.KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL;
121     /**
122      * Whether alias is enabled (boolean type)
123      */
124     public static final String
125             MMS_CONFIG_ALIAS_ENABLED = CarrierConfigManager.KEY_MMS_ALIAS_ENABLED_BOOL;
126     /**
127      * Whether audio is allowed to be attached for MMS messages (boolean type)
128      */
129     public static final String
130             MMS_CONFIG_ALLOW_ATTACH_AUDIO = CarrierConfigManager.KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL;
131     /**
132      * Whether multipart SMS is enabled (boolean type)
133      */
134     public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED =
135             CarrierConfigManager.KEY_MMS_MULTIPART_SMS_ENABLED_BOOL;
136     /**
137      * Whether SMS delivery report is enabled (boolean type)
138      */
139     public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED =
140             CarrierConfigManager.KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL;
141     /**
142      * Whether content-disposition field should be expected in an MMS PDU (boolean type)
143      */
144     public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION =
145             CarrierConfigManager.KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL;
146     /**
147      * Whether multipart SMS should be sent as separate messages
148      */
149     public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES =
150             CarrierConfigManager.KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL;
151     /**
152      * Whether MMS read report is enabled (boolean type)
153      */
154     public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED =
155             CarrierConfigManager.KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL;
156     /**
157      * Whether MMS delivery report is enabled (boolean type)
158      */
159     public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED =
160             CarrierConfigManager.KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL;
161     /**
162      * Max MMS message size in bytes (int type)
163      */
164     public static final String
165             MMS_CONFIG_MAX_MESSAGE_SIZE = CarrierConfigManager.KEY_MMS_MAX_MESSAGE_SIZE_INT;
166     /**
167      * Max MMS image width (int type)
168      */
169     public static final String
170             MMS_CONFIG_MAX_IMAGE_WIDTH = CarrierConfigManager.KEY_MMS_MAX_IMAGE_WIDTH_INT;
171     /**
172      * Max MMS image height (int type)
173      */
174     public static final String
175             MMS_CONFIG_MAX_IMAGE_HEIGHT = CarrierConfigManager.KEY_MMS_MAX_IMAGE_HEIGHT_INT;
176     /**
177      * Limit of recipients of MMS messages (int type)
178      */
179     public static final String
180             MMS_CONFIG_RECIPIENT_LIMIT = CarrierConfigManager.KEY_MMS_RECIPIENT_LIMIT_INT;
181     /**
182      * Min alias character count (int type)
183      */
184     public static final String
185             MMS_CONFIG_ALIAS_MIN_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MIN_CHARS_INT;
186     /**
187      * Max alias character count (int type)
188      */
189     public static final String
190             MMS_CONFIG_ALIAS_MAX_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MAX_CHARS_INT;
191     /**
192      * When the number of parts of a multipart SMS reaches this threshold, it should be converted
193      * into an MMS (int type)
194      */
195     public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD =
196             CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT;
197     /**
198      * Some carriers require SMS to be converted into MMS when text length reaches this threshold
199      * (int type)
200      */
201     public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD =
202             CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT;
203     /**
204      * Max message text size (int type)
205      */
206     public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE =
207             CarrierConfigManager.KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT;
208     /**
209      * Max message subject length (int type)
210      */
211     public static final String
212             MMS_CONFIG_SUBJECT_MAX_LENGTH = CarrierConfigManager.KEY_MMS_SUBJECT_MAX_LENGTH_INT;
213     /**
214      * MMS HTTP socket timeout in milliseconds (int type)
215      */
216     public static final String
217             MMS_CONFIG_HTTP_SOCKET_TIMEOUT = CarrierConfigManager.KEY_MMS_HTTP_SOCKET_TIMEOUT_INT;
218     /**
219      * The name of the UA Prof URL HTTP header for MMS HTTP request (String type)
220      */
221     public static final String
222             MMS_CONFIG_UA_PROF_TAG_NAME = CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING;
223     /**
224      * The User-Agent header value for MMS HTTP request (String type)
225      */
226     public static final String
227             MMS_CONFIG_USER_AGENT = CarrierConfigManager.KEY_MMS_USER_AGENT_STRING;
228     /**
229      * The UA Profile URL header value for MMS HTTP request (String type)
230      */
231     public static final String
232             MMS_CONFIG_UA_PROF_URL = CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING;
233     /**
234      * A list of HTTP headers to add to MMS HTTP request, separated by "|" (String type)
235      */
236     public static final String
237             MMS_CONFIG_HTTP_PARAMS = CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING;
238     /**
239      * Email gateway number (String type)
240      */
241     public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER =
242             CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING;
243     /**
244      * The suffix to append to the NAI header value for MMS HTTP request (String type)
245      */
246     public static final String
247             MMS_CONFIG_NAI_SUFFIX = CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING;
248     /**
249      * If true, show the cell broadcast (amber alert) in the SMS settings. Some carriers don't want
250      * this shown. (Boolean type)
251      */
252     public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS =
253             CarrierConfigManager.KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL;
254     /**
255      * Whether the carrier MMSC supports charset field in Content-Type header. If this is false,
256      * then we don't add "charset" to "Content-Type"
257      */
258     public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER =
259             CarrierConfigManager.KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL;
260     /**
261      * If true, add "Connection: close" header to MMS HTTP requests so the connection
262      * is immediately closed (disabling keep-alive). (Boolean type)
263      * @hide
264      */
265     public static final String MMS_CONFIG_CLOSE_CONNECTION =
266             CarrierConfigManager.KEY_MMS_CLOSE_CONNECTION_BOOL;
267 
268     /*
269      * Forwarded constants from SimDialogActivity.
270      */
271     private static String DIALOG_TYPE_KEY = "dialog_type";
272     private static final int SMS_PICK = 2;
273 
274     /**
275      * Send a text based SMS.
276      *
277      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
278      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
279      *
280      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
281      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
282      * writes messages sent using this method to the SMS Provider (the default SMS app is always
283      * responsible for writing its sent messages to the SMS Provider). For information about
284      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
285      *
286      *
287      * @param destinationAddress the address to send the message to
288      * @param scAddress is the service center address or null to use
289      *  the current default SMSC
290      * @param text the body of the message to send
291      * @param sentIntent if not NULL this <code>PendingIntent</code> is
292      *  broadcast when the message is successfully sent, or failed.
293      *  The result code will be <code>Activity.RESULT_OK</code> for success,
294      *  or one of these errors:<br>
295      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
296      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
297      *  <code>RESULT_ERROR_NULL_PDU</code><br>
298      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
299      *  the extra "errorCode" containing a radio technology specific value,
300      *  generally only useful for troubleshooting.<br>
301      *  The per-application based SMS control checks sentIntent. If sentIntent
302      *  is NULL the caller will be checked against all unknown applications,
303      *  which cause smaller number of SMS to be sent in checking period.
304      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
305      *  broadcast when the message is delivered to the recipient.  The
306      *  raw pdu of the status report is in the extended data ("pdu").
307      *
308      * @throws IllegalArgumentException if destinationAddress or text are empty
309      */
sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)310     public void sendTextMessage(
311             String destinationAddress, String scAddress, String text,
312             PendingIntent sentIntent, PendingIntent deliveryIntent) {
313         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
314                 true /* persistMessage*/);
315     }
316 
sendTextMessageInternal(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage)317     private void sendTextMessageInternal(String destinationAddress, String scAddress,
318             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
319             boolean persistMessage) {
320         if (TextUtils.isEmpty(destinationAddress)) {
321             throw new IllegalArgumentException("Invalid destinationAddress");
322         }
323 
324         if (TextUtils.isEmpty(text)) {
325             throw new IllegalArgumentException("Invalid message body");
326         }
327 
328         try {
329             ISms iccISms = getISmsServiceOrThrow();
330             iccISms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
331                     destinationAddress,
332                     scAddress, text, sentIntent, deliveryIntent,
333                     persistMessage);
334         } catch (RemoteException ex) {
335             // ignore it
336         }
337     }
338 
339     /**
340      * Send a text based SMS without writing it into the SMS Provider.
341      *
342      * <p>
343      * The message will be sent directly over the network and will not be visible in SMS
344      * applications. Intended for internal carrier use only.
345      * </p>
346      *
347      * <p>Requires Permission: Both {@link android.Manifest.permission#SEND_SMS} and
348      * {@link android.Manifest.permission#MODIFY_PHONE_STATE}, or that the calling app has carrier
349      * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), or that the calling app is
350      * the default IMS app (see
351      * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}).
352      *
353      * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent)
354      */
355     @SystemApi
356     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
357     @RequiresPermission(allOf = {
358             android.Manifest.permission.MODIFY_PHONE_STATE,
359             android.Manifest.permission.SEND_SMS
360     })
sendTextMessageWithoutPersisting( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)361     public void sendTextMessageWithoutPersisting(
362             String destinationAddress, String scAddress, String text,
363             PendingIntent sentIntent, PendingIntent deliveryIntent) {
364         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
365                 false /* persistMessage */);
366     }
367 
368     /**
369      * A variant of {@link SmsManager#sendTextMessage} that allows self to be the caller. This is
370      * for internal use only.
371      *
372      * @param persistMessage whether to persist the sent message in the SMS app. the caller must be
373      * the Phone process if set to false.
374      *
375      * @hide
376      */
sendTextMessageWithSelfPermissions( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage)377     public void sendTextMessageWithSelfPermissions(
378             String destinationAddress, String scAddress, String text,
379             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage) {
380         if (TextUtils.isEmpty(destinationAddress)) {
381             throw new IllegalArgumentException("Invalid destinationAddress");
382         }
383 
384         if (TextUtils.isEmpty(text)) {
385             throw new IllegalArgumentException("Invalid message body");
386         }
387 
388         try {
389             ISms iccISms = getISmsServiceOrThrow();
390             iccISms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(),
391                     ActivityThread.currentPackageName(),
392                     destinationAddress,
393                     scAddress, text, sentIntent, deliveryIntent, persistMessage);
394         } catch (RemoteException ex) {
395             // ignore it
396         }
397     }
398 
399     /**
400      * Send a text based SMS with messaging options.
401      *
402      * @param destinationAddress the address to send the message to
403      * @param scAddress is the service center address or null to use
404      *  the current default SMSC
405      * @param text the body of the message to send
406      * @param sentIntent if not NULL this <code>PendingIntent</code> is
407      *  broadcast when the message is successfully sent, or failed.
408      *  The result code will be <code>Activity.RESULT_OK</code> for success,
409      *  or one of these errors:<br>
410      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
411      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
412      *  <code>RESULT_ERROR_NULL_PDU</code><br>
413      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
414      *  the extra "errorCode" containing a radio technology specific value,
415      *  generally only useful for troubleshooting.<br>
416      *  The per-application based SMS control checks sentIntent. If sentIntent
417      *  is NULL the caller will be checked against all unknown applications,
418      *  which cause smaller number of SMS to be sent in checking period.
419      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
420      *  broadcast when the message is delivered to the recipient.  The
421      *  raw pdu of the status report is in the extended data ("pdu").
422      * @param priority Priority level of the message
423      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
424      *  ---------------------------------
425      *  PRIORITY      | Level of Priority
426      *  ---------------------------------
427      *      '00'      |     Normal
428      *      '01'      |     Interactive
429      *      '10'      |     Urgent
430      *      '11'      |     Emergency
431      *  ----------------------------------
432      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
433      * @param expectMore is a boolean to indicate the sending messages through same link or not.
434      * @param validityPeriod Validity Period of the message in mins.
435      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
436      *  Validity Period(Minimum) -> 5 mins
437      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
438      *  Any Other values included Negative considered as Invalid Validity Period of the message.
439      *
440      * @throws IllegalArgumentException if destinationAddress or text are empty
441      * {@hide}
442      */
sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority, boolean expectMore, int validityPeriod)443     public void sendTextMessage(
444             String destinationAddress, String scAddress, String text,
445             PendingIntent sentIntent, PendingIntent deliveryIntent,
446             int priority, boolean expectMore, int validityPeriod) {
447         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
448                 true /* persistMessage*/, priority, expectMore, validityPeriod);
449     }
450 
sendTextMessageInternal( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage, int priority, boolean expectMore, int validityPeriod)451     private void sendTextMessageInternal(
452             String destinationAddress, String scAddress, String text,
453             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage,
454             int priority, boolean expectMore, int validityPeriod) {
455         if (TextUtils.isEmpty(destinationAddress)) {
456             throw new IllegalArgumentException("Invalid destinationAddress");
457         }
458 
459         if (TextUtils.isEmpty(text)) {
460             throw new IllegalArgumentException("Invalid message body");
461         }
462 
463         if (priority < 0x00 || priority > 0x03) {
464             throw new IllegalArgumentException("Invalid priority");
465         }
466 
467         if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
468             throw new IllegalArgumentException("Invalid validity period");
469         }
470 
471         try {
472              ISms iccISms = getISmsServiceOrThrow();
473             if (iccISms != null) {
474                 iccISms.sendTextForSubscriberWithOptions(getSubscriptionId(),
475                         ActivityThread.currentPackageName(), destinationAddress, scAddress, text,
476                         sentIntent, deliveryIntent, persistMessage,  priority, expectMore,
477                         validityPeriod);
478             }
479         } catch (RemoteException ex) {
480             // ignore it
481         }
482     }
483 
484     /**
485      * Send a text based SMS without writing it into the SMS Provider.
486      *
487      * <p>Requires Permission:
488      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
489      * privileges.
490      * </p>
491      *
492      * @see #sendTextMessage(String, String, String, PendingIntent,
493      * PendingIntent, int, boolean, int)
494      * @hide
495      */
sendTextMessageWithoutPersisting( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority, boolean expectMore, int validityPeriod)496     public void sendTextMessageWithoutPersisting(
497             String destinationAddress, String scAddress, String text,
498             PendingIntent sentIntent, PendingIntent deliveryIntent, int priority,
499             boolean expectMore, int validityPeriod) {
500         sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
501                 false /* persistMessage */, priority, expectMore, validityPeriod);
502     }
503 
504     /**
505      *
506      * Inject an SMS PDU into the android application framework.
507      *
508      * <p>Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
509      * privileges per {@link android.telephony.TelephonyManager#hasCarrierPrivileges}.
510      *
511      * @param pdu is the byte array of pdu to be injected into android application framework
512      * @param format is the format of SMS pdu ({@link SmsMessage#FORMAT_3GPP} or
513      *  {@link SmsMessage#FORMAT_3GPP2})
514      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
515      *  broadcast when the message is successfully received by the
516      *  android application framework, or failed. This intent is broadcasted at
517      *  the same time an SMS received from radio is acknowledged back.
518      *  The result code will be {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_HANDLED}
519      *  for success, or {@link android.provider.Telephony.Sms.Intents#RESULT_SMS_GENERIC_ERROR} for
520      *  error.
521      *
522      * @throws IllegalArgumentException if the format is invalid.
523      */
injectSmsPdu( byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent)524     public void injectSmsPdu(
525             byte[] pdu, @SmsMessage.Format String format, PendingIntent receivedIntent) {
526         if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) {
527             // Format must be either 3gpp or 3gpp2.
528             throw new IllegalArgumentException(
529                     "Invalid pdu format. format must be either 3gpp or 3gpp2");
530         }
531         try {
532             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
533             if (iccISms != null) {
534                 iccISms.injectSmsPduForSubscriber(
535                         getSubscriptionId(), pdu, format, receivedIntent);
536             }
537         } catch (RemoteException ex) {
538           // ignore it
539         }
540     }
541 
542     /**
543      * Divide a message text into several fragments, none bigger than
544      * the maximum SMS message size.
545      *
546      * @param text the original message.  Must not be null.
547      * @return an <code>ArrayList</code> of strings that, in order,
548      *   comprise the original message
549      *
550      * @throws IllegalArgumentException if text is null
551      */
divideMessage(String text)552     public ArrayList<String> divideMessage(String text) {
553         if (null == text) {
554             throw new IllegalArgumentException("text is null");
555         }
556         return SmsMessage.fragmentText(text);
557     }
558 
559     /**
560      * Send a multi-part text based SMS.  The callee should have already
561      * divided the message into correctly sized parts by calling
562      * <code>divideMessage</code>.
563      *
564      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
565      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
566      *
567      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
568      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
569      * writes messages sent using this method to the SMS Provider (the default SMS app is always
570      * responsible for writing its sent messages to the SMS Provider). For information about
571      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
572      *
573      * @param destinationAddress the address to send the message to
574      * @param scAddress is the service center address or null to use
575      *   the current default SMSC
576      * @param parts an <code>ArrayList</code> of strings that, in order,
577      *   comprise the original message
578      * @param sentIntents if not null, an <code>ArrayList</code> of
579      *   <code>PendingIntent</code>s (one for each message part) that is
580      *   broadcast when the corresponding message part has been sent.
581      *   The result code will be <code>Activity.RESULT_OK</code> for success,
582      *   or one of these errors:<br>
583      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
584      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
585      *   <code>RESULT_ERROR_NULL_PDU</code><br>
586      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
587      *   the extra "errorCode" containing a radio technology specific value,
588      *   generally only useful for troubleshooting.<br>
589      *   The per-application based SMS control checks sentIntent. If sentIntent
590      *   is NULL the caller will be checked against all unknown applications,
591      *   which cause smaller number of SMS to be sent in checking period.
592      * @param deliveryIntents if not null, an <code>ArrayList</code> of
593      *   <code>PendingIntent</code>s (one for each message part) that is
594      *   broadcast when the corresponding message part has been delivered
595      *   to the recipient.  The raw pdu of the status report is in the
596      *   extended data ("pdu").
597      *
598      * @throws IllegalArgumentException if destinationAddress or data are empty
599      */
sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)600     public void sendMultipartTextMessage(
601             String destinationAddress, String scAddress, ArrayList<String> parts,
602             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
603         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
604                 deliveryIntents, true /* persistMessage*/);
605     }
606 
sendMultipartTextMessageInternal( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessage)607     private void sendMultipartTextMessageInternal(
608             String destinationAddress, String scAddress, List<String> parts,
609             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
610             boolean persistMessage) {
611         if (TextUtils.isEmpty(destinationAddress)) {
612             throw new IllegalArgumentException("Invalid destinationAddress");
613         }
614         if (parts == null || parts.size() < 1) {
615             throw new IllegalArgumentException("Invalid message body");
616         }
617 
618         if (parts.size() > 1) {
619             try {
620                 ISms iccISms = getISmsServiceOrThrow();
621                 iccISms.sendMultipartTextForSubscriber(getSubscriptionId(),
622                         ActivityThread.currentPackageName(),
623                         destinationAddress, scAddress, parts,
624                         sentIntents, deliveryIntents, persistMessage);
625             } catch (RemoteException ex) {
626                 // ignore it
627             }
628         } else {
629             PendingIntent sentIntent = null;
630             PendingIntent deliveryIntent = null;
631             if (sentIntents != null && sentIntents.size() > 0) {
632                 sentIntent = sentIntents.get(0);
633             }
634             if (deliveryIntents != null && deliveryIntents.size() > 0) {
635                 deliveryIntent = deliveryIntents.get(0);
636             }
637             sendTextMessage(destinationAddress, scAddress, parts.get(0),
638                     sentIntent, deliveryIntent);
639         }
640     }
641 
642     /**
643      * Send a multi-part text based SMS without writing it into the SMS Provider.
644      *
645      * <p>Requires Permission:
646      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
647      * privileges.
648      * </p>
649      *
650      * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList)
651      * @hide
652      **/
653     @SystemApi
654     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
sendMultipartTextMessageWithoutPersisting( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents)655     public void sendMultipartTextMessageWithoutPersisting(
656             String destinationAddress, String scAddress, List<String> parts,
657             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
658         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
659                 deliveryIntents, false /* persistMessage*/);
660     }
661 
662     /**
663      * Send a multi-part text based SMS with messaging options. The callee should have already
664      * divided the message into correctly sized parts by calling
665      * <code>divideMessage</code>.
666      *
667      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
668      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
669      *
670      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
671      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
672      * writes messages sent using this method to the SMS Provider (the default SMS app is always
673      * responsible for writing its sent messages to the SMS Provider). For information about
674      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
675      *
676      * @param destinationAddress the address to send the message to
677      * @param scAddress is the service center address or null to use
678      *   the current default SMSC
679      * @param parts an <code>ArrayList</code> of strings that, in order,
680      *   comprise the original message
681      * @param sentIntents if not null, an <code>ArrayList</code> of
682      *   <code>PendingIntent</code>s (one for each message part) that is
683      *   broadcast when the corresponding message part has been sent.
684      *   The result code will be <code>Activity.RESULT_OK</code> for success,
685      *   or one of these errors:<br>
686      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
687      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
688      *   <code>RESULT_ERROR_NULL_PDU</code><br>
689      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
690      *   the extra "errorCode" containing a radio technology specific value,
691      *   generally only useful for troubleshooting.<br>
692      *   The per-application based SMS control checks sentIntent. If sentIntent
693      *   is NULL the caller will be checked against all unknown applications,
694      *   which cause smaller number of SMS to be sent in checking period.
695      * @param deliveryIntents if not null, an <code>ArrayList</code> of
696      *   <code>PendingIntent</code>s (one for each message part) that is
697      *   broadcast when the corresponding message part has been delivered
698      *   to the recipient.  The raw pdu of the status report is in the
699      *   extended data ("pdu").
700      * @param priority Priority level of the message
701      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
702      *  ---------------------------------
703      *  PRIORITY      | Level of Priority
704      *  ---------------------------------
705      *      '00'      |     Normal
706      *      '01'      |     Interactive
707      *      '10'      |     Urgent
708      *      '11'      |     Emergency
709      *  ----------------------------------
710      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
711      * @param expectMore is a boolean to indicate the sending messages through same link or not.
712      * @param validityPeriod Validity Period of the message in mins.
713      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
714      *  Validity Period(Minimum) -> 5 mins
715      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
716      *  Any Other values included Negative considered as Invalid Validity Period of the message.
717      *
718      * @throws IllegalArgumentException if destinationAddress or data are empty
719      * {@hide}
720      */
sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, int priority, boolean expectMore, int validityPeriod)721     public void sendMultipartTextMessage(
722             String destinationAddress, String scAddress, ArrayList<String> parts,
723             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
724             int priority, boolean expectMore, int validityPeriod) {
725         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
726                 deliveryIntents, true /* persistMessage*/);
727     }
728 
sendMultipartTextMessageInternal( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, boolean persistMessage, int priority, boolean expectMore, int validityPeriod)729     private void sendMultipartTextMessageInternal(
730             String destinationAddress, String scAddress, List<String> parts,
731             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
732             boolean persistMessage, int priority, boolean expectMore, int validityPeriod) {
733         if (TextUtils.isEmpty(destinationAddress)) {
734             throw new IllegalArgumentException("Invalid destinationAddress");
735         }
736         if (parts == null || parts.size() < 1) {
737             throw new IllegalArgumentException("Invalid message body");
738         }
739 
740         if (priority < 0x00 || priority > 0x03) {
741             throw new IllegalArgumentException("Invalid priority");
742         }
743 
744         if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
745             throw new IllegalArgumentException("Invalid validity period");
746         }
747 
748         if (parts.size() > 1) {
749             try {
750                  ISms iccISms = getISmsServiceOrThrow();
751                 if (iccISms != null) {
752                     iccISms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
753                             ActivityThread.currentPackageName(), destinationAddress, scAddress,
754                             parts, sentIntents, deliveryIntents, persistMessage, priority,
755                             expectMore, validityPeriod);
756                 }
757             } catch (RemoteException ex) {
758                 // ignore it
759             }
760         } else {
761             PendingIntent sentIntent = null;
762             PendingIntent deliveryIntent = null;
763             if (sentIntents != null && sentIntents.size() > 0) {
764                 sentIntent = sentIntents.get(0);
765             }
766             if (deliveryIntents != null && deliveryIntents.size() > 0) {
767                 deliveryIntent = deliveryIntents.get(0);
768             }
769             sendTextMessageInternal(destinationAddress, scAddress, parts.get(0),
770                     sentIntent, deliveryIntent, persistMessage, priority, expectMore,
771                     validityPeriod);
772         }
773     }
774 
775     /**
776      * Send a multi-part text based SMS without writing it into the SMS Provider.
777      *
778      * <p>Requires Permission:
779      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
780      * privileges.
781      * </p>
782      *
783      * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList,
784      * ArrayList, int, boolean, int)
785      * @hide
786      **/
sendMultipartTextMessageWithoutPersisting( String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents, int priority, boolean expectMore, int validityPeriod)787     public void sendMultipartTextMessageWithoutPersisting(
788             String destinationAddress, String scAddress, List<String> parts,
789             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
790             int priority, boolean expectMore, int validityPeriod) {
791         sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
792                 deliveryIntents, false /* persistMessage*/, priority, expectMore,
793                 validityPeriod);
794     }
795 
796    /**
797      * Send a data based SMS to a specific application port.
798      *
799      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
800      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
801      *
802      * @param destinationAddress the address to send the message to
803      * @param scAddress is the service center address or null to use
804      *  the current default SMSC
805      * @param destinationPort the port to deliver the message to
806      * @param data the body of the message to send
807      * @param sentIntent if not NULL this <code>PendingIntent</code> is
808      *  broadcast when the message is successfully sent, or failed.
809      *  The result code will be <code>Activity.RESULT_OK</code> for success,
810      *  or one of these errors:<br>
811      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
812      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
813      *  <code>RESULT_ERROR_NULL_PDU</code><br>
814      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
815      *  the extra "errorCode" containing a radio technology specific value,
816      *  generally only useful for troubleshooting.<br>
817      *  The per-application based SMS control checks sentIntent. If sentIntent
818      *  is NULL the caller will be checked against all unknown applications,
819      *  which cause smaller number of SMS to be sent in checking period.
820      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
821      *  broadcast when the message is delivered to the recipient.  The
822      *  raw pdu of the status report is in the extended data ("pdu").
823      *
824      * @throws IllegalArgumentException if destinationAddress or data are empty
825      */
sendDataMessage( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)826     public void sendDataMessage(
827             String destinationAddress, String scAddress, short destinationPort,
828             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
829         if (TextUtils.isEmpty(destinationAddress)) {
830             throw new IllegalArgumentException("Invalid destinationAddress");
831         }
832 
833         if (data == null || data.length == 0) {
834             throw new IllegalArgumentException("Invalid message data");
835         }
836 
837         try {
838             ISms iccISms = getISmsServiceOrThrow();
839             iccISms.sendDataForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
840                     destinationAddress, scAddress, destinationPort & 0xFFFF,
841                     data, sentIntent, deliveryIntent);
842         } catch (RemoteException ex) {
843             // ignore it
844         }
845     }
846 
847     /**
848      * A variant of {@link SmsManager#sendDataMessage} that allows self to be the caller. This is
849      * for internal use only.
850      *
851      * @hide
852      */
sendDataMessageWithSelfPermissions( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)853     public void sendDataMessageWithSelfPermissions(
854             String destinationAddress, String scAddress, short destinationPort,
855             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
856         if (TextUtils.isEmpty(destinationAddress)) {
857             throw new IllegalArgumentException("Invalid destinationAddress");
858         }
859 
860         if (data == null || data.length == 0) {
861             throw new IllegalArgumentException("Invalid message data");
862         }
863 
864         try {
865             ISms iccISms = getISmsServiceOrThrow();
866             iccISms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(),
867                     ActivityThread.currentPackageName(), destinationAddress, scAddress,
868                     destinationPort & 0xFFFF, data, sentIntent, deliveryIntent);
869         } catch (RemoteException ex) {
870             // ignore it
871         }
872     }
873 
874 
875 
876     /**
877      * Get the SmsManager associated with the default subscription id. The instance will always be
878      * associated with the default subscription id, even if the default subscription id is changed.
879      *
880      * @return the SmsManager associated with the default subscription id
881      */
getDefault()882     public static SmsManager getDefault() {
883         return sInstance;
884     }
885 
886     /**
887      * Get the the instance of the SmsManager associated with a particular subscription id
888      *
889      * @param subId an SMS subscription id, typically accessed using
890      *   {@link android.telephony.SubscriptionManager}
891      * @return the instance of the SmsManager associated with subId
892      */
getSmsManagerForSubscriptionId(int subId)893     public static SmsManager getSmsManagerForSubscriptionId(int subId) {
894         // TODO(shri): Add javadoc link once SubscriptionManager is made public api
895         synchronized(sLockObject) {
896             SmsManager smsManager = sSubInstances.get(subId);
897             if (smsManager == null) {
898                 smsManager = new SmsManager(subId);
899                 sSubInstances.put(subId, smsManager);
900             }
901             return smsManager;
902         }
903     }
904 
SmsManager(int subId)905     private SmsManager(int subId) {
906         mSubId = subId;
907     }
908 
909     /**
910      * Get the associated subscription id. If the instance was returned by {@link #getDefault()},
911      * then this method may return different values at different points in time (if the user
912      * changes the default subscription id). It will return < 0 if the default subscription id
913      * cannot be determined.
914      *
915      * Additionally, to support legacy applications that are not multi-SIM aware,
916      * if the following are true:
917      *     - We are using a multi-SIM device
918      *     - A default SMS SIM has not been selected
919      *     - At least one SIM subscription is available
920      * then ask the user to set the default SMS SIM.
921      *
922      * @return associated subscription id
923      */
getSubscriptionId()924     public int getSubscriptionId() {
925         final int subId = (mSubId == DEFAULT_SUBSCRIPTION_ID)
926                 ? getDefaultSmsSubscriptionId() : mSubId;
927         boolean isSmsSimPickActivityNeeded = false;
928         final Context context = ActivityThread.currentApplication().getApplicationContext();
929         try {
930             ISms iccISms = getISmsService();
931             if (iccISms != null) {
932                 isSmsSimPickActivityNeeded = iccISms.isSmsSimPickActivityNeeded(subId);
933             }
934         } catch (RemoteException ex) {
935             Log.e(TAG, "Exception in getSubscriptionId");
936         }
937 
938         if (isSmsSimPickActivityNeeded) {
939             Log.d(TAG, "getSubscriptionId isSmsSimPickActivityNeeded is true");
940             // ask the user for a default SMS SIM.
941             Intent intent = new Intent();
942             intent.setClassName("com.android.settings",
943                     "com.android.settings.sim.SimDialogActivity");
944             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
945             intent.putExtra(DIALOG_TYPE_KEY, SMS_PICK);
946             try {
947                 context.startActivity(intent);
948             } catch (ActivityNotFoundException anfe) {
949                 // If Settings is not installed, only log the error as we do not want to break
950                 // legacy applications.
951                 Log.e(TAG, "Unable to launch Settings application.");
952             }
953         }
954 
955         return subId;
956     }
957 
958     /**
959      * Returns the ISms service, or throws an UnsupportedOperationException if
960      * the service does not exist.
961      */
getISmsServiceOrThrow()962     private static ISms getISmsServiceOrThrow() {
963         ISms iccISms = getISmsService();
964         if (iccISms == null) {
965             throw new UnsupportedOperationException("Sms is not supported");
966         }
967         return iccISms;
968     }
969 
getISmsService()970     private static ISms getISmsService() {
971         return ISms.Stub.asInterface(ServiceManager.getService("isms"));
972     }
973 
974     /**
975      * Copy a raw SMS PDU to the ICC.
976      * ICC (Integrated Circuit Card) is the card of the device.
977      * For example, this can be the SIM or USIM for GSM.
978      *
979      * @param smsc the SMSC for this message, or NULL for the default SMSC
980      * @param pdu the raw PDU to store
981      * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
982      *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
983      * @return true for success
984      *
985      * @throws IllegalArgumentException if pdu is NULL
986      * {@hide}
987      */
copyMessageToIcc(byte[] smsc, byte[] pdu,int status)988     public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
989         boolean success = false;
990 
991         if (null == pdu) {
992             throw new IllegalArgumentException("pdu is NULL");
993         }
994         try {
995             ISms iccISms = getISmsService();
996             if (iccISms != null) {
997                 success = iccISms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
998                         ActivityThread.currentPackageName(),
999                         status, pdu, smsc);
1000             }
1001         } catch (RemoteException ex) {
1002             // ignore it
1003         }
1004 
1005         return success;
1006     }
1007 
1008     /**
1009      * Delete the specified message from the ICC.
1010      * ICC (Integrated Circuit Card) is the card of the device.
1011      * For example, this can be the SIM or USIM for GSM.
1012      *
1013      * @param messageIndex is the record index of the message on ICC
1014      * @return true for success
1015      *
1016      * {@hide}
1017      */
1018     public boolean
deleteMessageFromIcc(int messageIndex)1019     deleteMessageFromIcc(int messageIndex) {
1020         boolean success = false;
1021         byte[] pdu = new byte[SMS_RECORD_LENGTH-1];
1022         Arrays.fill(pdu, (byte)0xff);
1023 
1024         try {
1025             ISms iccISms = getISmsService();
1026             if (iccISms != null) {
1027                 success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
1028                         ActivityThread.currentPackageName(),
1029                         messageIndex, STATUS_ON_ICC_FREE, pdu);
1030             }
1031         } catch (RemoteException ex) {
1032             // ignore it
1033         }
1034 
1035         return success;
1036     }
1037 
1038     /**
1039      * Update the specified message on the ICC.
1040      * ICC (Integrated Circuit Card) is the card of the device.
1041      * For example, this can be the SIM or USIM for GSM.
1042      *
1043      * @param messageIndex record index of message to update
1044      * @param newStatus new message status (STATUS_ON_ICC_READ,
1045      *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
1046      *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
1047      * @param pdu the raw PDU to store
1048      * @return true for success
1049      *
1050      * {@hide}
1051      */
updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu)1052     public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
1053         boolean success = false;
1054 
1055         try {
1056             ISms iccISms = getISmsService();
1057             if (iccISms != null) {
1058                 success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
1059                         ActivityThread.currentPackageName(),
1060                         messageIndex, newStatus, pdu);
1061             }
1062         } catch (RemoteException ex) {
1063             // ignore it
1064         }
1065 
1066         return success;
1067     }
1068 
1069     /**
1070      * Retrieves all messages currently stored on ICC.
1071      * ICC (Integrated Circuit Card) is the card of the device.
1072      * For example, this can be the SIM or USIM for GSM.
1073      *
1074      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
1075      *
1076      * {@hide}
1077      */
getAllMessagesFromIcc()1078     public ArrayList<SmsMessage> getAllMessagesFromIcc() {
1079         List<SmsRawData> records = null;
1080 
1081         try {
1082             ISms iccISms = getISmsService();
1083             if (iccISms != null) {
1084                 records = iccISms.getAllMessagesFromIccEfForSubscriber(
1085                         getSubscriptionId(),
1086                         ActivityThread.currentPackageName());
1087             }
1088         } catch (RemoteException ex) {
1089             // ignore it
1090         }
1091 
1092         return createMessageListFromRawRecords(records);
1093     }
1094 
1095     /**
1096      * Enable reception of cell broadcast (SMS-CB) messages with the given
1097      * message identifier and RAN type. The RAN type specify this message ID
1098      * belong to 3GPP (GSM) or 3GPP2(CDMA).Note that if two different clients
1099      * enable the same message identifier, they must both disable it for the device to stop
1100      * receiving those messages. All received messages will be broadcast in an
1101      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
1102      * Note: This call is blocking, callers may want to avoid calling it from
1103      * the main thread of an application.
1104      *
1105      * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
1106      * or C.R1001-G (3GPP2)
1107      * @param ranType as defined in class SmsManager, the value can be one of these:
1108      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
1109      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
1110      * @return true if successful, false otherwise
1111      * @see #disableCellBroadcast(int, int)
1112      *
1113      * {@hide}
1114      */
enableCellBroadcast(int messageIdentifier, int ranType)1115     public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
1116         boolean success = false;
1117 
1118         try {
1119             ISms iccISms = getISmsService();
1120             if (iccISms != null) {
1121                 success = iccISms.enableCellBroadcastForSubscriber(
1122                         getSubscriptionId(), messageIdentifier, ranType);
1123             }
1124         } catch (RemoteException ex) {
1125             // ignore it
1126         }
1127 
1128         return success;
1129     }
1130 
1131     /**
1132      * Disable reception of cell broadcast (SMS-CB) messages with the given
1133      * message identifier and RAN type. The RAN type specify this message ID
1134      * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
1135      * enable the same message identifier, they must both disable it for the
1136      * device to stop receiving those messages.
1137      * Note: This call is blocking, callers may want to avoid calling it from
1138      * the main thread of an application.
1139      *
1140      * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
1141      * or C.R1001-G (3GPP2)
1142      * @param ranType as defined in class SmsManager, the value can be one of these:
1143      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
1144      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
1145      * @return true if successful, false otherwise
1146      *
1147      * @see #enableCellBroadcast(int, int)
1148      *
1149      * {@hide}
1150      */
disableCellBroadcast(int messageIdentifier, int ranType)1151     public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
1152         boolean success = false;
1153 
1154         try {
1155             ISms iccISms = getISmsService();
1156             if (iccISms != null) {
1157                 success = iccISms.disableCellBroadcastForSubscriber(
1158                         getSubscriptionId(), messageIdentifier, ranType);
1159             }
1160         } catch (RemoteException ex) {
1161             // ignore it
1162         }
1163 
1164         return success;
1165     }
1166 
1167     /**
1168      * Enable reception of cell broadcast (SMS-CB) messages with the given
1169      * message identifier range and RAN type. The RAN type specify this message ID
1170      * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable
1171      * the same message identifier, they must both disable it for the device to stop
1172      * receiving those messages. All received messages will be broadcast in an
1173      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
1174      * Note: This call is blocking, callers may want to avoid calling it from
1175      * the main thread of an application.
1176      *
1177      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
1178      * or C.R1001-G (3GPP2)
1179      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
1180      * or C.R1001-G (3GPP2)
1181      * @param ranType as defined in class SmsManager, the value can be one of these:
1182      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
1183      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
1184      * @return true if successful, false otherwise
1185      * @see #disableCellBroadcastRange(int, int, int)
1186      *
1187      * @throws IllegalArgumentException if endMessageId < startMessageId
1188      * {@hide}
1189      */
enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)1190     public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
1191         boolean success = false;
1192 
1193         if (endMessageId < startMessageId) {
1194             throw new IllegalArgumentException("endMessageId < startMessageId");
1195         }
1196         try {
1197             ISms iccISms = getISmsService();
1198             if (iccISms != null) {
1199                 success = iccISms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
1200                         startMessageId, endMessageId, ranType);
1201             }
1202         } catch (RemoteException ex) {
1203             // ignore it
1204         }
1205 
1206         return success;
1207     }
1208 
1209     /**
1210      * Disable reception of cell broadcast (SMS-CB) messages with the given
1211      * message identifier range and RAN type. The RAN type specify this message
1212      * ID range belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different
1213      * clients enable the same message identifier, they must both disable it for
1214      * the device to stop receiving those messages.
1215      * Note: This call is blocking, callers may want to avoid calling it from
1216      * the main thread of an application.
1217      *
1218      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
1219      * or C.R1001-G (3GPP2)
1220      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
1221      * or C.R1001-G (3GPP2)
1222      * @param ranType as defined in class SmsManager, the value can be one of these:
1223      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
1224      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
1225      * @return true if successful, false otherwise
1226      *
1227      * @see #enableCellBroadcastRange(int, int, int)
1228      *
1229      * @throws IllegalArgumentException if endMessageId < startMessageId
1230      * {@hide}
1231      */
disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)1232     public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
1233         boolean success = false;
1234 
1235         if (endMessageId < startMessageId) {
1236             throw new IllegalArgumentException("endMessageId < startMessageId");
1237         }
1238         try {
1239             ISms iccISms = getISmsService();
1240             if (iccISms != null) {
1241                 success = iccISms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
1242                         startMessageId, endMessageId, ranType);
1243             }
1244         } catch (RemoteException ex) {
1245             // ignore it
1246         }
1247 
1248         return success;
1249     }
1250 
1251     /**
1252      * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
1253      * records returned by <code>getAllMessagesFromIcc()</code>
1254      *
1255      * @param records SMS EF records, returned by
1256      *   <code>getAllMessagesFromIcc</code>
1257      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
1258      */
createMessageListFromRawRecords(List<SmsRawData> records)1259     private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
1260         ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
1261         if (records != null) {
1262             int count = records.size();
1263             for (int i = 0; i < count; i++) {
1264                 SmsRawData data = records.get(i);
1265                 // List contains all records, including "free" records (null)
1266                 if (data != null) {
1267                     SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes(),
1268                             getSubscriptionId());
1269                     if (sms != null) {
1270                         messages.add(sms);
1271                     }
1272                 }
1273             }
1274         }
1275         return messages;
1276     }
1277 
1278     /**
1279      * SMS over IMS is supported if IMS is registered and SMS is supported
1280      * on IMS.
1281      *
1282      * @return true if SMS over IMS is supported, false otherwise
1283      *
1284      * @see #getImsSmsFormat()
1285      *
1286      * @hide
1287      */
isImsSmsSupported()1288     public boolean isImsSmsSupported() {
1289         boolean boSupported = false;
1290         try {
1291             ISms iccISms = getISmsService();
1292             if (iccISms != null) {
1293                 boSupported = iccISms.isImsSmsSupportedForSubscriber(getSubscriptionId());
1294             }
1295         } catch (RemoteException ex) {
1296             // ignore it
1297         }
1298         return boSupported;
1299     }
1300 
1301     /**
1302      * Gets SMS format supported on IMS.  SMS over IMS format is
1303      * either 3GPP or 3GPP2.
1304      *
1305      * @return SmsMessage.FORMAT_3GPP,
1306      *         SmsMessage.FORMAT_3GPP2
1307      *      or SmsMessage.FORMAT_UNKNOWN
1308      *
1309      * @see #isImsSmsSupported()
1310      *
1311      * @hide
1312      */
getImsSmsFormat()1313     public String getImsSmsFormat() {
1314         String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
1315         try {
1316             ISms iccISms = getISmsService();
1317             if (iccISms != null) {
1318                 format = iccISms.getImsSmsFormatForSubscriber(getSubscriptionId());
1319             }
1320         } catch (RemoteException ex) {
1321             // ignore it
1322         }
1323         return format;
1324     }
1325 
1326     /**
1327      * Get default sms subscription id
1328      *
1329      * @return the default SMS subscription id
1330      */
getDefaultSmsSubscriptionId()1331     public static int getDefaultSmsSubscriptionId() {
1332         ISms iccISms = null;
1333         try {
1334             iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
1335             return iccISms.getPreferredSmsSubscription();
1336         } catch (RemoteException ex) {
1337             return -1;
1338         } catch (NullPointerException ex) {
1339             return -1;
1340         }
1341     }
1342 
1343     /**
1344      * Get SMS prompt property,  enabled or not
1345      *
1346      * @return true if enabled, false otherwise
1347      * @hide
1348      */
isSMSPromptEnabled()1349     public boolean isSMSPromptEnabled() {
1350         ISms iccISms = null;
1351         try {
1352             iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
1353             return iccISms.isSMSPromptEnabled();
1354         } catch (RemoteException ex) {
1355             return false;
1356         } catch (NullPointerException ex) {
1357             return false;
1358         }
1359     }
1360 
1361     // see SmsMessage.getStatusOnIcc
1362 
1363     /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
1364     static public final int STATUS_ON_ICC_FREE      = 0;
1365 
1366     /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
1367     static public final int STATUS_ON_ICC_READ      = 1;
1368 
1369     /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
1370     static public final int STATUS_ON_ICC_UNREAD    = 3;
1371 
1372     /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
1373     static public final int STATUS_ON_ICC_SENT      = 5;
1374 
1375     /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
1376     static public final int STATUS_ON_ICC_UNSENT    = 7;
1377 
1378     // SMS send failure result codes
1379 
1380     /**
1381      * No error.
1382      * @hide
1383      */
1384     @SystemApi
1385     static public final int RESULT_ERROR_NONE    = 0;
1386     /** Generic failure cause */
1387     static public final int RESULT_ERROR_GENERIC_FAILURE    = 1;
1388     /** Failed because radio was explicitly turned off */
1389     static public final int RESULT_ERROR_RADIO_OFF          = 2;
1390     /** Failed because no pdu provided */
1391     static public final int RESULT_ERROR_NULL_PDU           = 3;
1392     /** Failed because service is currently unavailable */
1393     static public final int RESULT_ERROR_NO_SERVICE         = 4;
1394     /** Failed because we reached the sending queue limit. */
1395     static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
1396     /**
1397      * Failed because FDN is enabled.
1398      * @hide
1399      */
1400     @SystemApi
1401     static public final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
1402     /** Failed because user denied the sending of this short code. */
1403     static public final int RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7;
1404     /** Failed because the user has denied this app ever send premium short codes. */
1405     static public final int RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8;
1406     /**
1407      * Failed because the radio was not available
1408      * @hide
1409      */
1410     @SystemApi
1411     static public final int RESULT_RADIO_NOT_AVAILABLE = 9;
1412     /**
1413      * Failed because of network rejection
1414      * @hide
1415      */
1416     @SystemApi
1417     static public final int RESULT_NETWORK_REJECT = 10;
1418     /**
1419      * Failed because of invalid arguments
1420      * @hide
1421      */
1422     @SystemApi
1423     static public final int RESULT_INVALID_ARGUMENTS = 11;
1424     /**
1425      * Failed because of an invalid state
1426      * @hide
1427      */
1428     @SystemApi
1429     static public final int RESULT_INVALID_STATE = 12;
1430     /**
1431      * Failed because there is no memory
1432      * @hide
1433      */
1434     @SystemApi
1435     static public final int RESULT_NO_MEMORY = 13;
1436     /**
1437      * Failed because the sms format is not valid
1438      * @hide
1439      */
1440     @SystemApi
1441     static public final int RESULT_INVALID_SMS_FORMAT = 14;
1442     /**
1443      * Failed because of a system error
1444      * @hide
1445      */
1446     @SystemApi
1447     static public final int RESULT_SYSTEM_ERROR = 15;
1448     /**
1449      * Failed because of a modem error
1450      * @hide
1451      */
1452     @SystemApi
1453     static public final int RESULT_MODEM_ERROR = 16;
1454     /**
1455      * Failed because of a network error
1456      * @hide
1457      */
1458     @SystemApi
1459     static public final int RESULT_NETWORK_ERROR = 17;
1460     /**
1461      * Failed because of an encoding error
1462      * @hide
1463      */
1464     @SystemApi
1465     static public final int RESULT_ENCODING_ERROR = 18;
1466     /**
1467      * Failed because of an invalid smsc address
1468      * @hide
1469      */
1470     @SystemApi
1471     static public final int RESULT_INVALID_SMSC_ADDRESS = 19;
1472     /**
1473      * Failed because the operation is not allowed
1474      * @hide
1475      */
1476     @SystemApi
1477     static public final int RESULT_OPERATION_NOT_ALLOWED = 20;
1478     /**
1479      * Failed because of an internal error
1480      * @hide
1481      */
1482     @SystemApi
1483     static public final int RESULT_INTERNAL_ERROR = 21;
1484     /**
1485      * Failed because there are no resources
1486      * @hide
1487      */
1488     @SystemApi
1489     static public final int RESULT_NO_RESOURCES = 22;
1490     /**
1491      * Failed because the operation was cancelled
1492      * @hide
1493      */
1494     @SystemApi
1495     static public final int RESULT_CANCELLED = 23;
1496     /**
1497      * Failed because the request is not supported
1498      * @hide
1499      */
1500     @SystemApi
1501     static public final int RESULT_REQUEST_NOT_SUPPORTED = 24;
1502 
1503 
1504     static private final String PHONE_PACKAGE_NAME = "com.android.phone";
1505 
1506     /**
1507      * Send an MMS message
1508      *
1509      * @param context application context
1510      * @param contentUri the content Uri from which the message pdu will be read
1511      * @param locationUrl the optional location url where message should be sent to
1512      * @param configOverrides the carrier-specific messaging configuration values to override for
1513      *  sending the message.
1514      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1515      *  broadcast when the message is successfully sent, or failed
1516      * @throws IllegalArgumentException if contentUri is empty
1517      */
sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent)1518     public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
1519             Bundle configOverrides, PendingIntent sentIntent) {
1520         if (contentUri == null) {
1521             throw new IllegalArgumentException("Uri contentUri null");
1522         }
1523         try {
1524             final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1525             if (iMms == null) {
1526                 return;
1527             }
1528 
1529             iMms.sendMessage(getSubscriptionId(), ActivityThread.currentPackageName(), contentUri,
1530                     locationUrl, configOverrides, sentIntent);
1531         } catch (RemoteException e) {
1532             // Ignore it
1533         }
1534     }
1535 
1536     /**
1537      * Download an MMS message from carrier by a given location URL
1538      *
1539      * @param context application context
1540      * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
1541      *  from the MMS WAP push notification
1542      * @param contentUri the content uri to which the downloaded pdu will be written
1543      * @param configOverrides the carrier-specific messaging configuration values to override for
1544      *  downloading the message.
1545      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
1546      *  broadcast when the message is downloaded, or the download is failed
1547      * @throws IllegalArgumentException if locationUrl or contentUri is empty
1548      */
downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent)1549     public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
1550             Bundle configOverrides, PendingIntent downloadedIntent) {
1551         if (TextUtils.isEmpty(locationUrl)) {
1552             throw new IllegalArgumentException("Empty MMS location URL");
1553         }
1554         if (contentUri == null) {
1555             throw new IllegalArgumentException("Uri contentUri null");
1556         }
1557         try {
1558             final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1559             if (iMms == null) {
1560                 return;
1561             }
1562             iMms.downloadMessage(
1563                     getSubscriptionId(), ActivityThread.currentPackageName(), locationUrl,
1564                     contentUri, configOverrides, downloadedIntent);
1565         } catch (RemoteException e) {
1566             // Ignore it
1567         }
1568     }
1569 
1570     // MMS send/download failure result codes
1571     public static final int MMS_ERROR_UNSPECIFIED = 1;
1572     public static final int MMS_ERROR_INVALID_APN = 2;
1573     public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
1574     public static final int MMS_ERROR_HTTP_FAILURE = 4;
1575     public static final int MMS_ERROR_IO_ERROR = 5;
1576     public static final int MMS_ERROR_RETRY = 6;
1577     public static final int MMS_ERROR_CONFIGURATION_ERROR = 7;
1578     public static final int MMS_ERROR_NO_DATA_NETWORK = 8;
1579 
1580     /** Intent extra name for MMS sending result data in byte array type */
1581     public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
1582     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
1583     public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
1584 
1585     /**
1586      * Import a text message into system's SMS store
1587      *
1588      * Only default SMS apps can import SMS
1589      *
1590      * @param address the destination(source) address of the sent(received) message
1591      * @param type the type of the message
1592      * @param text the message text
1593      * @param timestampMillis the message timestamp in milliseconds
1594      * @param seen if the message is seen
1595      * @param read if the message is read
1596      * @return the message URI, null if failed
1597      * @hide
1598      */
importTextMessage(String address, int type, String text, long timestampMillis, boolean seen, boolean read)1599     public Uri importTextMessage(String address, int type, String text, long timestampMillis,
1600             boolean seen, boolean read) {
1601         try {
1602             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1603             if (iMms != null) {
1604                 return iMms.importTextMessage(ActivityThread.currentPackageName(),
1605                         address, type, text, timestampMillis, seen, read);
1606             }
1607         } catch (RemoteException ex) {
1608             // ignore it
1609         }
1610         return null;
1611     }
1612 
1613     /** Represents the received SMS message for importing {@hide} */
1614     public static final int SMS_TYPE_INCOMING = 0;
1615     /** Represents the sent SMS message for importing {@hide} */
1616     public static final int SMS_TYPE_OUTGOING = 1;
1617 
1618     /**
1619      * Import a multimedia message into system's MMS store. Only the following PDU type is
1620      * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind
1621      *
1622      * Only default SMS apps can import MMS
1623      *
1624      * @param contentUri the content uri from which to read the PDU of the message to import
1625      * @param messageId the optional message id. Use null if not specifying
1626      * @param timestampSecs the optional message timestamp. Use -1 if not specifying
1627      * @param seen if the message is seen
1628      * @param read if the message is read
1629      * @return the message URI, null if failed
1630      * @throws IllegalArgumentException if pdu is empty
1631      * {@hide}
1632      */
importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs, boolean seen, boolean read)1633     public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs,
1634             boolean seen, boolean read) {
1635         if (contentUri == null) {
1636             throw new IllegalArgumentException("Uri contentUri null");
1637         }
1638         try {
1639             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1640             if (iMms != null) {
1641                 return iMms.importMultimediaMessage(ActivityThread.currentPackageName(),
1642                         contentUri, messageId, timestampSecs, seen, read);
1643             }
1644         } catch (RemoteException ex) {
1645             // ignore it
1646         }
1647         return null;
1648     }
1649 
1650     /**
1651      * Delete a system stored SMS or MMS message
1652      *
1653      * Only default SMS apps can delete system stored SMS and MMS messages
1654      *
1655      * @param messageUri the URI of the stored message
1656      * @return true if deletion is successful, false otherwise
1657      * @throws IllegalArgumentException if messageUri is empty
1658      * {@hide}
1659      */
deleteStoredMessage(Uri messageUri)1660     public boolean deleteStoredMessage(Uri messageUri) {
1661         if (messageUri == null) {
1662             throw new IllegalArgumentException("Empty message URI");
1663         }
1664         try {
1665             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1666             if (iMms != null) {
1667                 return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri);
1668             }
1669         } catch (RemoteException ex) {
1670             // ignore it
1671         }
1672         return false;
1673     }
1674 
1675     /**
1676      * Delete a system stored SMS or MMS thread
1677      *
1678      * Only default SMS apps can delete system stored SMS and MMS conversations
1679      *
1680      * @param conversationId the ID of the message conversation
1681      * @return true if deletion is successful, false otherwise
1682      * {@hide}
1683      */
deleteStoredConversation(long conversationId)1684     public boolean deleteStoredConversation(long conversationId) {
1685         try {
1686             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1687             if (iMms != null) {
1688                 return iMms.deleteStoredConversation(
1689                         ActivityThread.currentPackageName(), conversationId);
1690             }
1691         } catch (RemoteException ex) {
1692             // ignore it
1693         }
1694         return false;
1695     }
1696 
1697     /**
1698      * Update the status properties of a system stored SMS or MMS message, e.g.
1699      * the read status of a message, etc.
1700      *
1701      * @param messageUri the URI of the stored message
1702      * @param statusValues a list of status properties in key-value pairs to update
1703      * @return true if update is successful, false otherwise
1704      * @throws IllegalArgumentException if messageUri is empty
1705      * {@hide}
1706      */
updateStoredMessageStatus(Uri messageUri, ContentValues statusValues)1707     public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) {
1708         if (messageUri == null) {
1709             throw new IllegalArgumentException("Empty message URI");
1710         }
1711         try {
1712             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1713             if (iMms != null) {
1714                 return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(),
1715                         messageUri, statusValues);
1716             }
1717         } catch (RemoteException ex) {
1718             // ignore it
1719         }
1720         return false;
1721     }
1722 
1723     /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */
1724     public static final String MESSAGE_STATUS_SEEN = "seen";
1725     /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */
1726     public static final String MESSAGE_STATUS_READ = "read";
1727 
1728     /**
1729      * Archive or unarchive a stored conversation
1730      *
1731      * @param conversationId the ID of the message conversation
1732      * @param archived true to archive the conversation, false to unarchive
1733      * @return true if update is successful, false otherwise
1734      * {@hide}
1735      */
archiveStoredConversation(long conversationId, boolean archived)1736     public boolean archiveStoredConversation(long conversationId, boolean archived) {
1737         try {
1738             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1739             if (iMms != null) {
1740                 return iMms.archiveStoredConversation(ActivityThread.currentPackageName(),
1741                         conversationId, archived);
1742             }
1743         } catch (RemoteException ex) {
1744             // ignore it
1745         }
1746         return false;
1747     }
1748 
1749     /**
1750      * Add a text message draft to system SMS store
1751      *
1752      * Only default SMS apps can add SMS draft
1753      *
1754      * @param address the destination address of message
1755      * @param text the body of the message to send
1756      * @return the URI of the stored draft message
1757      * {@hide}
1758      */
addTextMessageDraft(String address, String text)1759     public Uri addTextMessageDraft(String address, String text) {
1760         try {
1761             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1762             if (iMms != null) {
1763                 return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text);
1764             }
1765         } catch (RemoteException ex) {
1766             // ignore it
1767         }
1768         return null;
1769     }
1770 
1771     /**
1772      * Add a multimedia message draft to system MMS store
1773      *
1774      * Only default SMS apps can add MMS draft
1775      *
1776      * @param contentUri the content uri from which to read the PDU data of the draft MMS
1777      * @return the URI of the stored draft message
1778      * @throws IllegalArgumentException if pdu is empty
1779      * {@hide}
1780      */
addMultimediaMessageDraft(Uri contentUri)1781     public Uri addMultimediaMessageDraft(Uri contentUri) {
1782         if (contentUri == null) {
1783             throw new IllegalArgumentException("Uri contentUri null");
1784         }
1785         try {
1786             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1787             if (iMms != null) {
1788                 return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(),
1789                         contentUri);
1790             }
1791         } catch (RemoteException ex) {
1792             // ignore it
1793         }
1794         return null;
1795     }
1796 
1797     /**
1798      * Send a system stored text message.
1799      *
1800      * You can only send a failed text message or a draft text message.
1801      *
1802      * @param messageUri the URI of the stored message
1803      * @param scAddress is the service center address or null to use the current default SMSC
1804      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1805      *  broadcast when the message is successfully sent, or failed.
1806      *  The result code will be <code>Activity.RESULT_OK</code> for success,
1807      *  or one of these errors:<br>
1808      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
1809      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
1810      *  <code>RESULT_ERROR_NULL_PDU</code><br>
1811      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
1812      *  the extra "errorCode" containing a radio technology specific value,
1813      *  generally only useful for troubleshooting.<br>
1814      *  The per-application based SMS control checks sentIntent. If sentIntent
1815      *  is NULL the caller will be checked against all unknown applications,
1816      *  which cause smaller number of SMS to be sent in checking period.
1817      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
1818      *  broadcast when the message is delivered to the recipient.  The
1819      *  raw pdu of the status report is in the extended data ("pdu").
1820      *
1821      * @throws IllegalArgumentException if messageUri is empty
1822      * {@hide}
1823      */
sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)1824     public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent,
1825             PendingIntent deliveryIntent) {
1826         if (messageUri == null) {
1827             throw new IllegalArgumentException("Empty message URI");
1828         }
1829         try {
1830             ISms iccISms = getISmsServiceOrThrow();
1831             iccISms.sendStoredText(
1832                     getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
1833                     scAddress, sentIntent, deliveryIntent);
1834         } catch (RemoteException ex) {
1835             // ignore it
1836         }
1837     }
1838 
1839     /**
1840      * Send a system stored multi-part text message.
1841      *
1842      * You can only send a failed text message or a draft text message.
1843      * The provided <code>PendingIntent</code> lists should match the part number of the
1844      * divided text of the stored message by using <code>divideMessage</code>
1845      *
1846      * @param messageUri the URI of the stored message
1847      * @param scAddress is the service center address or null to use
1848      *   the current default SMSC
1849      * @param sentIntents if not null, an <code>ArrayList</code> of
1850      *   <code>PendingIntent</code>s (one for each message part) that is
1851      *   broadcast when the corresponding message part has been sent.
1852      *   The result code will be <code>Activity.RESULT_OK</code> for success,
1853      *   or one of these errors:<br>
1854      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
1855      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
1856      *   <code>RESULT_ERROR_NULL_PDU</code><br>
1857      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
1858      *   the extra "errorCode" containing a radio technology specific value,
1859      *   generally only useful for troubleshooting.<br>
1860      *   The per-application based SMS control checks sentIntent. If sentIntent
1861      *   is NULL the caller will be checked against all unknown applications,
1862      *   which cause smaller number of SMS to be sent in checking period.
1863      * @param deliveryIntents if not null, an <code>ArrayList</code> of
1864      *   <code>PendingIntent</code>s (one for each message part) that is
1865      *   broadcast when the corresponding message part has been delivered
1866      *   to the recipient.  The raw pdu of the status report is in the
1867      *   extended data ("pdu").
1868      *
1869      * @throws IllegalArgumentException if messageUri is empty
1870      * {@hide}
1871      */
sendStoredMultipartTextMessage(Uri messageUri, String scAddress, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)1872     public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress,
1873             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
1874         if (messageUri == null) {
1875             throw new IllegalArgumentException("Empty message URI");
1876         }
1877         try {
1878             ISms iccISms = getISmsServiceOrThrow();
1879             iccISms.sendStoredMultipartText(
1880                     getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
1881                     scAddress, sentIntents, deliveryIntents);
1882         } catch (RemoteException ex) {
1883             // ignore it
1884         }
1885     }
1886 
1887     /**
1888      * Send a system stored MMS message
1889      *
1890      * This is used for sending a previously sent, but failed-to-send, message or
1891      * for sending a text message that has been stored as a draft.
1892      *
1893      * @param messageUri the URI of the stored message
1894      * @param configOverrides the carrier-specific messaging configuration values to override for
1895      *  sending the message.
1896      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1897      *  broadcast when the message is successfully sent, or failed
1898      * @throws IllegalArgumentException if messageUri is empty
1899      * {@hide}
1900      */
sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides, PendingIntent sentIntent)1901     public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides,
1902             PendingIntent sentIntent) {
1903         if (messageUri == null) {
1904             throw new IllegalArgumentException("Empty message URI");
1905         }
1906         try {
1907             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1908             if (iMms != null) {
1909                 iMms.sendStoredMessage(
1910                         getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
1911                         configOverrides, sentIntent);
1912             }
1913         } catch (RemoteException ex) {
1914             // ignore it
1915         }
1916     }
1917 
1918     /**
1919      * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system
1920      *
1921      * When this flag is on, all SMS/MMS sent/received are stored by system automatically
1922      * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
1923      * automatically
1924      *
1925      * This flag can only be changed by default SMS apps
1926      *
1927      * @param enabled Whether to enable message auto persisting
1928      * {@hide}
1929      */
setAutoPersisting(boolean enabled)1930     public void setAutoPersisting(boolean enabled) {
1931         try {
1932             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1933             if (iMms != null) {
1934                 iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled);
1935             }
1936         } catch (RemoteException ex) {
1937             // ignore it
1938         }
1939     }
1940 
1941     /**
1942      * Get the value of the flag to automatically write sent/received SMS/MMS messages into system
1943      *
1944      * When this flag is on, all SMS/MMS sent/received are stored by system automatically
1945      * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
1946      * automatically
1947      *
1948      * @return the current value of the auto persist flag
1949      * {@hide}
1950      */
getAutoPersisting()1951     public boolean getAutoPersisting() {
1952         try {
1953             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1954             if (iMms != null) {
1955                 return iMms.getAutoPersisting();
1956             }
1957         } catch (RemoteException ex) {
1958             // ignore it
1959         }
1960         return false;
1961     }
1962 
1963     /**
1964      * Get carrier-dependent configuration values.
1965      *
1966      * @return bundle key/values pairs of configuration values
1967      */
getCarrierConfigValues()1968     public Bundle getCarrierConfigValues() {
1969         try {
1970             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1971             if (iMms != null) {
1972                 return iMms.getCarrierConfigValues(getSubscriptionId());
1973             }
1974         } catch (RemoteException ex) {
1975             // ignore it
1976         }
1977         return null;
1978     }
1979 
1980     /**
1981      * Create a single use app specific incoming SMS request for the the calling package.
1982      *
1983      * This method returns a token that if included in a subsequent incoming SMS message will cause
1984      * {@code intent} to be sent with the SMS data.
1985      *
1986      * The token is only good for one use, after an SMS has been received containing the token all
1987      * subsequent SMS messages with the token will be routed as normal.
1988      *
1989      * An app can only have one request at a time, if the app already has a request pending it will
1990      * be replaced with a new request.
1991      *
1992      * @return Token to include in an SMS message. The token will be 11 characters long.
1993      * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent
1994      */
createAppSpecificSmsToken(PendingIntent intent)1995     public String createAppSpecificSmsToken(PendingIntent intent) {
1996         try {
1997             ISms iccSms = getISmsServiceOrThrow();
1998             return iccSms.createAppSpecificSmsToken(getSubscriptionId(),
1999                     ActivityThread.currentPackageName(), intent);
2000 
2001         } catch (RemoteException ex) {
2002             ex.rethrowFromSystemServer();
2003             return null;
2004         }
2005     }
2006 
2007     /**
2008      * Filters a bundle to only contain MMS config variables.
2009      *
2010      * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS
2011      * config and unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the
2012      * supplied bundle.
2013      *
2014      * @param config a Bundle that contains MMS config variables and possibly more.
2015      * @return a new Bundle that only contains the MMS_CONFIG_* keys defined above.
2016      * @hide
2017      */
getMmsConfig(BaseBundle config)2018     public static Bundle getMmsConfig(BaseBundle config) {
2019         Bundle filtered = new Bundle();
2020         filtered.putBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID,
2021                 config.getBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID));
2022         filtered.putBoolean(MMS_CONFIG_MMS_ENABLED, config.getBoolean(MMS_CONFIG_MMS_ENABLED));
2023         filtered.putBoolean(MMS_CONFIG_GROUP_MMS_ENABLED,
2024                 config.getBoolean(MMS_CONFIG_GROUP_MMS_ENABLED));
2025         filtered.putBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED,
2026                 config.getBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED));
2027         filtered.putBoolean(MMS_CONFIG_ALIAS_ENABLED, config.getBoolean(MMS_CONFIG_ALIAS_ENABLED));
2028         filtered.putBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO,
2029                 config.getBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO));
2030         filtered.putBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED,
2031                 config.getBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED));
2032         filtered.putBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED,
2033                 config.getBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED));
2034         filtered.putBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
2035                 config.getBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION));
2036         filtered.putBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES,
2037                 config.getBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES));
2038         filtered.putBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED,
2039                 config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED));
2040         filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED,
2041                 config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED));
2042         filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION,
2043                 config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION));
2044         filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE));
2045         filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH));
2046         filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT));
2047         filtered.putInt(MMS_CONFIG_RECIPIENT_LIMIT, config.getInt(MMS_CONFIG_RECIPIENT_LIMIT));
2048         filtered.putInt(MMS_CONFIG_ALIAS_MIN_CHARS, config.getInt(MMS_CONFIG_ALIAS_MIN_CHARS));
2049         filtered.putInt(MMS_CONFIG_ALIAS_MAX_CHARS, config.getInt(MMS_CONFIG_ALIAS_MAX_CHARS));
2050         filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD,
2051                 config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD));
2052         filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD,
2053                 config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD));
2054         filtered.putInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE,
2055                 config.getInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE));
2056         filtered.putInt(MMS_CONFIG_SUBJECT_MAX_LENGTH,
2057                 config.getInt(MMS_CONFIG_SUBJECT_MAX_LENGTH));
2058         filtered.putInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT,
2059                 config.getInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
2060         filtered.putString(MMS_CONFIG_UA_PROF_TAG_NAME,
2061                 config.getString(MMS_CONFIG_UA_PROF_TAG_NAME));
2062         filtered.putString(MMS_CONFIG_USER_AGENT, config.getString(MMS_CONFIG_USER_AGENT));
2063         filtered.putString(MMS_CONFIG_UA_PROF_URL, config.getString(MMS_CONFIG_UA_PROF_URL));
2064         filtered.putString(MMS_CONFIG_HTTP_PARAMS, config.getString(MMS_CONFIG_HTTP_PARAMS));
2065         filtered.putString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER,
2066                 config.getString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER));
2067         filtered.putString(MMS_CONFIG_NAI_SUFFIX, config.getString(MMS_CONFIG_NAI_SUFFIX));
2068         filtered.putBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS,
2069                 config.getBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS));
2070         filtered.putBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER,
2071                 config.getBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER));
2072         return filtered;
2073     }
2074 
2075 }
2076