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.app.ActivityThread;
20 import android.app.PendingIntent;
21 import android.content.ActivityNotFoundException;
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.net.Uri;
26 import android.os.Bundle;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.text.TextUtils;
30 import android.util.ArrayMap;
31 import android.util.Log;
32 
33 import com.android.internal.telephony.ISms;
34 import com.android.internal.telephony.SmsRawData;
35 import com.android.internal.telephony.IMms;
36 import com.android.internal.telephony.uicc.IccConstants;
37 
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.Map;
42 
43 /*
44  * TODO(code review): Curious question... Why are a lot of these
45  * methods not declared as static, since they do not seem to require
46  * any local object state?  Presumably this cannot be changed without
47  * interfering with the API...
48  */
49 
50 /**
51  * Manages SMS operations such as sending data, text, and pdu SMS messages.
52  * Get this object by calling the static method {@link #getDefault()}.
53  *
54  * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19)
55  * and higher, see {@link android.provider.Telephony}.
56  */
57 public final class SmsManager {
58     private static final String TAG = "SmsManager";
59     /**
60      * A psuedo-subId that represents the default subId at any given time. The actual subId it
61      * represents changes as the default subId is changed.
62      */
63     private static final int DEFAULT_SUBSCRIPTION_ID = -1002;
64 
65     /** Singleton object constructed during class initialization. */
66     private static final SmsManager sInstance = new SmsManager(DEFAULT_SUBSCRIPTION_ID);
67     private static final Object sLockObject = new Object();
68 
69     /** @hide */
70     public static final int CELL_BROADCAST_RAN_TYPE_GSM = 0;
71     /** @hide */
72     public static final int CELL_BROADCAST_RAN_TYPE_CDMA = 1;
73 
74     private static final Map<Integer, SmsManager> sSubInstances =
75             new ArrayMap<Integer, SmsManager>();
76 
77     /** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */
78     private int mSubId;
79 
80     /*
81      * Key for the various carrier-dependent configuration values.
82      * Some of the values are used by the system in processing SMS or MMS messages. Others
83      * are provided for the convenience of SMS applications.
84      */
85 
86     /**
87      * Whether to append transaction id to MMS WAP Push M-Notification.ind's content location URI
88      * when constructing the download URL of a new MMS (boolean type)
89      */
90     public static final String MMS_CONFIG_APPEND_TRANSACTION_ID = "enabledTransID";
91     /**
92      * Whether MMS is enabled for the current carrier (boolean type)
93      */
94     public static final String MMS_CONFIG_MMS_ENABLED = "enabledMMS";
95     /**
96      * Whether group MMS is enabled for the current carrier (boolean type)
97      */
98     public static final String MMS_CONFIG_GROUP_MMS_ENABLED = "enableGroupMms";
99     /**
100      * If this is enabled, M-NotifyResp.ind should be sent to the WAP Push content location
101      * instead of the default MMSC (boolean type)
102      */
103     public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED = "enabledNotifyWapMMSC";
104     /**
105      * Whether alias is enabled (boolean type)
106      */
107     public static final String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
108     /**
109      * Whether audio is allowed to be attached for MMS messages (boolean type)
110      */
111     public static final String MMS_CONFIG_ALLOW_ATTACH_AUDIO = "allowAttachAudio";
112     /**
113      * Whether multipart SMS is enabled (boolean type)
114      */
115     public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED = "enableMultipartSMS";
116     /**
117      * Whether SMS delivery report is enabled (boolean type)
118      */
119     public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED = "enableSMSDeliveryReports";
120     /**
121      * Whether content-disposition field should be expected in an MMS PDU (boolean type)
122      */
123     public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION =
124             "supportMmsContentDisposition";
125     /**
126      * Whether multipart SMS should be sent as separate messages
127      */
128     public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES =
129             "sendMultipartSmsAsSeparateMessages";
130     /**
131      * Whether MMS read report is enabled (boolean type)
132      */
133     public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED = "enableMMSReadReports";
134     /**
135      * Whether MMS delivery report is enabled (boolean type)
136      */
137     public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED = "enableMMSDeliveryReports";
138     /**
139      * Max MMS message size in bytes (int type)
140      */
141     public static final String MMS_CONFIG_MAX_MESSAGE_SIZE = "maxMessageSize";
142     /**
143      * Max MMS image width (int type)
144      */
145     public static final String MMS_CONFIG_MAX_IMAGE_WIDTH = "maxImageWidth";
146     /**
147      * Max MMS image height (int type)
148      */
149     public static final String MMS_CONFIG_MAX_IMAGE_HEIGHT = "maxImageHeight";
150     /**
151      * Limit of recipients of MMS messages (int type)
152      */
153     public static final String MMS_CONFIG_RECIPIENT_LIMIT = "recipientLimit";
154     /**
155      * Min alias character count (int type)
156      */
157     public static final String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars";
158     /**
159      * Max alias character count (int type)
160      */
161     public static final String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars";
162     /**
163      * When the number of parts of a multipart SMS reaches this threshold, it should be
164      * converted into an MMS (int type)
165      */
166     public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD = "smsToMmsTextThreshold";
167     /**
168      * Some carriers require SMS to be converted into MMS when text length reaches this threshold
169      * (int type)
170      */
171     public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD =
172             "smsToMmsTextLengthThreshold";
173     /**
174      * Max message text size (int type)
175      */
176     public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE = "maxMessageTextSize";
177     /**
178      * Max message subject length (int type)
179      */
180     public static final String MMS_CONFIG_SUBJECT_MAX_LENGTH = "maxSubjectLength";
181     /**
182      * MMS HTTP socket timeout in milliseconds (int type)
183      */
184     public static final String MMS_CONFIG_HTTP_SOCKET_TIMEOUT = "httpSocketTimeout";
185     /**
186      * The name of the UA Prof URL HTTP header for MMS HTTP request (String type)
187      */
188     public static final String MMS_CONFIG_UA_PROF_TAG_NAME = "uaProfTagName";
189     /**
190      * The User-Agent header value for MMS HTTP request (String type)
191      */
192     public static final String MMS_CONFIG_USER_AGENT = "userAgent";
193     /**
194      * The UA Profile URL header value for MMS HTTP request (String type)
195      */
196     public static final String MMS_CONFIG_UA_PROF_URL = "uaProfUrl";
197     /**
198      * A list of HTTP headers to add to MMS HTTP request, separated by "|" (String type)
199      */
200     public static final String MMS_CONFIG_HTTP_PARAMS = "httpParams";
201     /**
202      * Email gateway number (String type)
203      */
204     public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER = "emailGatewayNumber";
205     /**
206      * The suffix to append to the NAI header value for MMS HTTP request (String type)
207      */
208     public static final String MMS_CONFIG_NAI_SUFFIX = "naiSuffix";
209     /**
210      * If true, show the cell broadcast (amber alert) in the SMS settings. Some carriers
211      * don't want this shown. (Boolean type)
212      */
213     public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS =
214             "config_cellBroadcastAppLinks";
215     /*
216      * Forwarded constants from SimDialogActivity.
217      */
218     private static String DIALOG_TYPE_KEY = "dialog_type";
219     private static final int SMS_PICK = 2;
220 
221     /**
222      * Send a text based SMS.
223      *
224      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
225      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
226      *
227      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
228      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
229      * writes messages sent using this method to the SMS Provider (the default SMS app is always
230      * responsible for writing its sent messages to the SMS Provider). For information about
231      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
232      *
233      *
234      * @param destinationAddress the address to send the message to
235      * @param scAddress is the service center address or null to use
236      *  the current default SMSC
237      * @param text the body of the message to send
238      * @param sentIntent if not NULL this <code>PendingIntent</code> is
239      *  broadcast when the message is successfully sent, or failed.
240      *  The result code will be <code>Activity.RESULT_OK</code> for success,
241      *  or one of these errors:<br>
242      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
243      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
244      *  <code>RESULT_ERROR_NULL_PDU</code><br>
245      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
246      *  the extra "errorCode" containing a radio technology specific value,
247      *  generally only useful for troubleshooting.<br>
248      *  The per-application based SMS control checks sentIntent. If sentIntent
249      *  is NULL the caller will be checked against all unknown applications,
250      *  which cause smaller number of SMS to be sent in checking period.
251      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
252      *  broadcast when the message is delivered to the recipient.  The
253      *  raw pdu of the status report is in the extended data ("pdu").
254      *
255      * @throws IllegalArgumentException if destinationAddress or text are empty
256      */
sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)257     public void sendTextMessage(
258             String destinationAddress, String scAddress, String text,
259             PendingIntent sentIntent, PendingIntent deliveryIntent) {
260         if (TextUtils.isEmpty(destinationAddress)) {
261             throw new IllegalArgumentException("Invalid destinationAddress");
262         }
263 
264         if (TextUtils.isEmpty(text)) {
265             throw new IllegalArgumentException("Invalid message body");
266         }
267 
268         try {
269             ISms iccISms = getISmsServiceOrThrow();
270             iccISms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
271                     destinationAddress,
272                     scAddress, text, sentIntent, deliveryIntent);
273         } catch (RemoteException ex) {
274             // ignore it
275         }
276     }
277 
278     /**
279      * Inject an SMS PDU into the android application framework.
280      *
281      * The caller should have carrier privileges.
282      * @see android.telephony.TelephonyManager.hasCarrierPrivileges
283      *
284      * @param pdu is the byte array of pdu to be injected into android application framework
285      * @param format is the format of SMS pdu (3gpp or 3gpp2)
286      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
287      *  broadcast when the message is successfully received by the
288      *  android application framework, or failed. This intent is broadcasted at
289      *  the same time an SMS received from radio is acknowledged back.
290      *  The result code will be <code>RESULT_SMS_HANDLED</code> for success, or
291      *  <code>RESULT_SMS_GENERIC_ERROR</code> for error.
292      *
293      * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2.
294      */
injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent)295     public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
296         if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) {
297             // Format must be either 3gpp or 3gpp2.
298             throw new IllegalArgumentException(
299                     "Invalid pdu format. format must be either 3gpp or 3gpp2");
300         }
301         try {
302             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
303             if (iccISms != null) {
304                 iccISms.injectSmsPdu(pdu, format, receivedIntent);
305             }
306         } catch (RemoteException ex) {
307           // ignore it
308         }
309     }
310 
311     /**
312      * Divide a message text into several fragments, none bigger than
313      * the maximum SMS message size.
314      *
315      * @param text the original message.  Must not be null.
316      * @return an <code>ArrayList</code> of strings that, in order,
317      *   comprise the original message
318      *
319      * @throws IllegalArgumentException if text is null
320      */
divideMessage(String text)321     public ArrayList<String> divideMessage(String text) {
322         if (null == text) {
323             throw new IllegalArgumentException("text is null");
324         }
325         return SmsMessage.fragmentText(text);
326     }
327 
328     /**
329      * Send a multi-part text based SMS.  The callee should have already
330      * divided the message into correctly sized parts by calling
331      * <code>divideMessage</code>.
332      *
333      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
334      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
335      *
336      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
337      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
338      * writes messages sent using this method to the SMS Provider (the default SMS app is always
339      * responsible for writing its sent messages to the SMS Provider). For information about
340      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
341      *
342      * @param destinationAddress the address to send the message to
343      * @param scAddress is the service center address or null to use
344      *   the current default SMSC
345      * @param parts an <code>ArrayList</code> of strings that, in order,
346      *   comprise the original message
347      * @param sentIntents if not null, an <code>ArrayList</code> of
348      *   <code>PendingIntent</code>s (one for each message part) that is
349      *   broadcast when the corresponding message part has been sent.
350      *   The result code will be <code>Activity.RESULT_OK</code> for success,
351      *   or one of these errors:<br>
352      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
353      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
354      *   <code>RESULT_ERROR_NULL_PDU</code><br>
355      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
356      *   the extra "errorCode" containing a radio technology specific value,
357      *   generally only useful for troubleshooting.<br>
358      *   The per-application based SMS control checks sentIntent. If sentIntent
359      *   is NULL the caller will be checked against all unknown applications,
360      *   which cause smaller number of SMS to be sent in checking period.
361      * @param deliveryIntents if not null, an <code>ArrayList</code> of
362      *   <code>PendingIntent</code>s (one for each message part) that is
363      *   broadcast when the corresponding message part has been delivered
364      *   to the recipient.  The raw pdu of the status report is in the
365      *   extended data ("pdu").
366      *
367      * @throws IllegalArgumentException if destinationAddress or data are empty
368      */
sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)369     public void sendMultipartTextMessage(
370             String destinationAddress, String scAddress, ArrayList<String> parts,
371             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
372         if (TextUtils.isEmpty(destinationAddress)) {
373             throw new IllegalArgumentException("Invalid destinationAddress");
374         }
375         if (parts == null || parts.size() < 1) {
376             throw new IllegalArgumentException("Invalid message body");
377         }
378 
379         if (parts.size() > 1) {
380             try {
381                 ISms iccISms = getISmsServiceOrThrow();
382                 iccISms.sendMultipartTextForSubscriber(getSubscriptionId(),
383                         ActivityThread.currentPackageName(),
384                         destinationAddress, scAddress, parts,
385                         sentIntents, deliveryIntents);
386             } catch (RemoteException ex) {
387                 // ignore it
388             }
389         } else {
390             PendingIntent sentIntent = null;
391             PendingIntent deliveryIntent = null;
392             if (sentIntents != null && sentIntents.size() > 0) {
393                 sentIntent = sentIntents.get(0);
394             }
395             if (deliveryIntents != null && deliveryIntents.size() > 0) {
396                 deliveryIntent = deliveryIntents.get(0);
397             }
398             sendTextMessage(destinationAddress, scAddress, parts.get(0),
399                     sentIntent, deliveryIntent);
400         }
401     }
402 
403     /**
404      * Send a data based SMS to a specific application port.
405      *
406      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
407      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
408      *
409      * @param destinationAddress the address to send the message to
410      * @param scAddress is the service center address or null to use
411      *  the current default SMSC
412      * @param destinationPort the port to deliver the message to
413      * @param data the body of the message to send
414      * @param sentIntent if not NULL this <code>PendingIntent</code> is
415      *  broadcast when the message is successfully sent, or failed.
416      *  The result code will be <code>Activity.RESULT_OK</code> for success,
417      *  or one of these errors:<br>
418      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
419      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
420      *  <code>RESULT_ERROR_NULL_PDU</code><br>
421      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
422      *  the extra "errorCode" containing a radio technology specific value,
423      *  generally only useful for troubleshooting.<br>
424      *  The per-application based SMS control checks sentIntent. If sentIntent
425      *  is NULL the caller will be checked against all unknown applications,
426      *  which cause smaller number of SMS to be sent in checking period.
427      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
428      *  broadcast when the message is delivered to the recipient.  The
429      *  raw pdu of the status report is in the extended data ("pdu").
430      *
431      * @throws IllegalArgumentException if destinationAddress or data are empty
432      */
sendDataMessage( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)433     public void sendDataMessage(
434             String destinationAddress, String scAddress, short destinationPort,
435             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
436         if (TextUtils.isEmpty(destinationAddress)) {
437             throw new IllegalArgumentException("Invalid destinationAddress");
438         }
439 
440         if (data == null || data.length == 0) {
441             throw new IllegalArgumentException("Invalid message data");
442         }
443 
444         try {
445             ISms iccISms = getISmsServiceOrThrow();
446             iccISms.sendDataForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
447                     destinationAddress, scAddress, destinationPort & 0xFFFF,
448                     data, sentIntent, deliveryIntent);
449         } catch (RemoteException ex) {
450             // ignore it
451         }
452     }
453 
454     /**
455      * Get the SmsManager associated with the default subscription id. The instance will always be
456      * associated with the default subscription id, even if the default subscription id is changed.
457      *
458      * @return the SmsManager associated with the default subscription id
459      */
getDefault()460     public static SmsManager getDefault() {
461         return sInstance;
462     }
463 
464     /**
465      * Get the the instance of the SmsManager associated with a particular subscription id
466      *
467      * @param subId an SMS subscription id, typically accessed using
468      *   {@link android.telephony.SubscriptionManager}
469      * @return the instance of the SmsManager associated with subId
470      */
getSmsManagerForSubscriptionId(int subId)471     public static SmsManager getSmsManagerForSubscriptionId(int subId) {
472         // TODO(shri): Add javadoc link once SubscriptionManager is made public api
473         synchronized(sLockObject) {
474             SmsManager smsManager = sSubInstances.get(subId);
475             if (smsManager == null) {
476                 smsManager = new SmsManager(subId);
477                 sSubInstances.put(subId, smsManager);
478             }
479             return smsManager;
480         }
481     }
482 
SmsManager(int subId)483     private SmsManager(int subId) {
484         mSubId = subId;
485     }
486 
487     /**
488      * Get the associated subscription id. If the instance was returned by {@link #getDefault()},
489      * then this method may return different values at different points in time (if the user
490      * changes the default subscription id). It will return < 0 if the default subscription id
491      * cannot be determined.
492      *
493      * Additionally, to support legacy applications that are not multi-SIM aware,
494      * if the following are true:
495      *     - We are using a multi-SIM device
496      *     - A default SMS SIM has not been selected
497      *     - At least one SIM subscription is available
498      * then ask the user to set the default SMS SIM.
499      *
500      * @return associated subscription id
501      */
getSubscriptionId()502     public int getSubscriptionId() {
503         final int subId = (mSubId == DEFAULT_SUBSCRIPTION_ID)
504                 ? getDefaultSmsSubscriptionId() : mSubId;
505         boolean isSmsSimPickActivityNeeded = false;
506         final Context context = ActivityThread.currentApplication().getApplicationContext();
507         try {
508             ISms iccISms = getISmsService();
509             if (iccISms != null) {
510                 isSmsSimPickActivityNeeded = iccISms.isSmsSimPickActivityNeeded(subId);
511             }
512         } catch (RemoteException ex) {
513             Log.e(TAG, "Exception in getSubscriptionId");
514         }
515 
516         if (isSmsSimPickActivityNeeded) {
517             Log.d(TAG, "getSubscriptionId isSmsSimPickActivityNeeded is true");
518             // ask the user for a default SMS SIM.
519             Intent intent = new Intent();
520             intent.setClassName("com.android.settings",
521                     "com.android.settings.sim.SimDialogActivity");
522             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
523             intent.putExtra(DIALOG_TYPE_KEY, SMS_PICK);
524             try {
525                 context.startActivity(intent);
526             } catch (ActivityNotFoundException anfe) {
527                 // If Settings is not installed, only log the error as we do not want to break
528                 // legacy applications.
529                 Log.e(TAG, "Unable to launch Settings application.");
530             }
531         }
532 
533         return subId;
534     }
535 
536     /**
537      * Returns the ISms service, or throws an UnsupportedOperationException if
538      * the service does not exist.
539      */
getISmsServiceOrThrow()540     private static ISms getISmsServiceOrThrow() {
541         ISms iccISms = getISmsService();
542         if (iccISms == null) {
543             throw new UnsupportedOperationException("Sms is not supported");
544         }
545         return iccISms;
546     }
547 
getISmsService()548     private static ISms getISmsService() {
549         return ISms.Stub.asInterface(ServiceManager.getService("isms"));
550     }
551 
552     /**
553      * Copy a raw SMS PDU to the ICC.
554      * ICC (Integrated Circuit Card) is the card of the device.
555      * For example, this can be the SIM or USIM for GSM.
556      *
557      * @param smsc the SMSC for this message, or NULL for the default SMSC
558      * @param pdu the raw PDU to store
559      * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
560      *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
561      * @return true for success
562      *
563      * @throws IllegalArgumentException if pdu is NULL
564      * {@hide}
565      */
copyMessageToIcc(byte[] smsc, byte[] pdu,int status)566     public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
567         boolean success = false;
568 
569         if (null == pdu) {
570             throw new IllegalArgumentException("pdu is NULL");
571         }
572         try {
573             ISms iccISms = getISmsService();
574             if (iccISms != null) {
575                 success = iccISms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
576                         ActivityThread.currentPackageName(),
577                         status, pdu, smsc);
578             }
579         } catch (RemoteException ex) {
580             // ignore it
581         }
582 
583         return success;
584     }
585 
586     /**
587      * Delete the specified message from the ICC.
588      * ICC (Integrated Circuit Card) is the card of the device.
589      * For example, this can be the SIM or USIM for GSM.
590      *
591      * @param messageIndex is the record index of the message on ICC
592      * @return true for success
593      *
594      * {@hide}
595      */
596     public boolean
deleteMessageFromIcc(int messageIndex)597     deleteMessageFromIcc(int messageIndex) {
598         boolean success = false;
599         byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1];
600         Arrays.fill(pdu, (byte)0xff);
601 
602         try {
603             ISms iccISms = getISmsService();
604             if (iccISms != null) {
605                 success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
606                         ActivityThread.currentPackageName(),
607                         messageIndex, STATUS_ON_ICC_FREE, pdu);
608             }
609         } catch (RemoteException ex) {
610             // ignore it
611         }
612 
613         return success;
614     }
615 
616     /**
617      * Update the specified message on the ICC.
618      * ICC (Integrated Circuit Card) is the card of the device.
619      * For example, this can be the SIM or USIM for GSM.
620      *
621      * @param messageIndex record index of message to update
622      * @param newStatus new message status (STATUS_ON_ICC_READ,
623      *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
624      *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
625      * @param pdu the raw PDU to store
626      * @return true for success
627      *
628      * {@hide}
629      */
updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu)630     public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
631         boolean success = false;
632 
633         try {
634             ISms iccISms = getISmsService();
635             if (iccISms != null) {
636                 success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
637                         ActivityThread.currentPackageName(),
638                         messageIndex, newStatus, pdu);
639             }
640         } catch (RemoteException ex) {
641             // ignore it
642         }
643 
644         return success;
645     }
646 
647     /**
648      * Retrieves all messages currently stored on ICC.
649      * ICC (Integrated Circuit Card) is the card of the device.
650      * For example, this can be the SIM or USIM for GSM.
651      *
652      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
653      *
654      * {@hide}
655      */
getAllMessagesFromIcc()656     public ArrayList<SmsMessage> getAllMessagesFromIcc() {
657         List<SmsRawData> records = null;
658 
659         try {
660             ISms iccISms = getISmsService();
661             if (iccISms != null) {
662                 records = iccISms.getAllMessagesFromIccEfForSubscriber(
663                         getSubscriptionId(),
664                         ActivityThread.currentPackageName());
665             }
666         } catch (RemoteException ex) {
667             // ignore it
668         }
669 
670         return createMessageListFromRawRecords(records);
671     }
672 
673     /**
674      * Enable reception of cell broadcast (SMS-CB) messages with the given
675      * message identifier and RAN type. The RAN type specify this message ID
676      * belong to 3GPP (GSM) or 3GPP2(CDMA).Note that if two different clients
677      * enable the same message identifier, they must both disable it for the device to stop
678      * receiving those messages. All received messages will be broadcast in an
679      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
680      * Note: This call is blocking, callers may want to avoid calling it from
681      * the main thread of an application.
682      *
683      * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
684      * or C.R1001-G (3GPP2)
685      * @param ranType as defined in class SmsManager, the value can be one of these:
686      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
687      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
688      * @return true if successful, false otherwise
689      * @see #disableCellBroadcast(int, int)
690      *
691      * {@hide}
692      */
enableCellBroadcast(int messageIdentifier, int ranType)693     public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
694         boolean success = false;
695 
696         try {
697             ISms iccISms = getISmsService();
698             if (iccISms != null) {
699                 success = iccISms.enableCellBroadcastForSubscriber(
700                         getSubscriptionId(), messageIdentifier, ranType);
701             }
702         } catch (RemoteException ex) {
703             // ignore it
704         }
705 
706         return success;
707     }
708 
709     /**
710      * Disable reception of cell broadcast (SMS-CB) messages with the given
711      * message identifier and RAN type. The RAN type specify this message ID
712      * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
713      * enable the same message identifier, they must both disable it for the
714      * device to stop receiving those messages.
715      * Note: This call is blocking, callers may want to avoid calling it from
716      * the main thread of an application.
717      *
718      * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
719      * or C.R1001-G (3GPP2)
720      * @param ranType as defined in class SmsManager, the value can be one of these:
721      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
722      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
723      * @return true if successful, false otherwise
724      *
725      * @see #enableCellBroadcast(int, int)
726      *
727      * {@hide}
728      */
disableCellBroadcast(int messageIdentifier, int ranType)729     public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
730         boolean success = false;
731 
732         try {
733             ISms iccISms = getISmsService();
734             if (iccISms != null) {
735                 success = iccISms.disableCellBroadcastForSubscriber(
736                         getSubscriptionId(), messageIdentifier, ranType);
737             }
738         } catch (RemoteException ex) {
739             // ignore it
740         }
741 
742         return success;
743     }
744 
745     /**
746      * Enable reception of cell broadcast (SMS-CB) messages with the given
747      * message identifier range and RAN type. The RAN type specify this message ID
748      * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable
749      * the same message identifier, they must both disable it for the device to stop
750      * receiving those messages. All received messages will be broadcast in an
751      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
752      * Note: This call is blocking, callers may want to avoid calling it from
753      * the main thread of an application.
754      *
755      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
756      * or C.R1001-G (3GPP2)
757      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
758      * or C.R1001-G (3GPP2)
759      * @param ranType as defined in class SmsManager, the value can be one of these:
760      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
761      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
762      * @return true if successful, false otherwise
763      * @see #disableCellBroadcastRange(int, int, int)
764      *
765      * @throws IllegalArgumentException if endMessageId < startMessageId
766      * {@hide}
767      */
enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)768     public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
769         boolean success = false;
770 
771         if (endMessageId < startMessageId) {
772             throw new IllegalArgumentException("endMessageId < startMessageId");
773         }
774         try {
775             ISms iccISms = getISmsService();
776             if (iccISms != null) {
777                 success = iccISms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
778                         startMessageId, endMessageId, ranType);
779             }
780         } catch (RemoteException ex) {
781             // ignore it
782         }
783 
784         return success;
785     }
786 
787     /**
788      * Disable reception of cell broadcast (SMS-CB) messages with the given
789      * message identifier range and RAN type. The RAN type specify this message
790      * ID range belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different
791      * clients enable the same message identifier, they must both disable it for
792      * the device to stop receiving those messages.
793      * Note: This call is blocking, callers may want to avoid calling it from
794      * the main thread of an application.
795      *
796      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
797      * or C.R1001-G (3GPP2)
798      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
799      * or C.R1001-G (3GPP2)
800      * @param ranType as defined in class SmsManager, the value can be one of these:
801      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
802      *    android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
803      * @return true if successful, false otherwise
804      *
805      * @see #enableCellBroadcastRange(int, int, int)
806      *
807      * @throws IllegalArgumentException if endMessageId < startMessageId
808      * {@hide}
809      */
disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType)810     public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
811         boolean success = false;
812 
813         if (endMessageId < startMessageId) {
814             throw new IllegalArgumentException("endMessageId < startMessageId");
815         }
816         try {
817             ISms iccISms = getISmsService();
818             if (iccISms != null) {
819                 success = iccISms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
820                         startMessageId, endMessageId, ranType);
821             }
822         } catch (RemoteException ex) {
823             // ignore it
824         }
825 
826         return success;
827     }
828 
829     /**
830      * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
831      * records returned by <code>getAllMessagesFromIcc()</code>
832      *
833      * @param records SMS EF records, returned by
834      *   <code>getAllMessagesFromIcc</code>
835      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
836      */
createMessageListFromRawRecords(List<SmsRawData> records)837     private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
838         ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
839         if (records != null) {
840             int count = records.size();
841             for (int i = 0; i < count; i++) {
842                 SmsRawData data = records.get(i);
843                 // List contains all records, including "free" records (null)
844                 if (data != null) {
845                     SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
846                     if (sms != null) {
847                         messages.add(sms);
848                     }
849                 }
850             }
851         }
852         return messages;
853     }
854 
855     /**
856      * SMS over IMS is supported if IMS is registered and SMS is supported
857      * on IMS.
858      *
859      * @return true if SMS over IMS is supported, false otherwise
860      *
861      * @see #getImsSmsFormat()
862      *
863      * @hide
864      */
isImsSmsSupported()865     public boolean isImsSmsSupported() {
866         boolean boSupported = false;
867         try {
868             ISms iccISms = getISmsService();
869             if (iccISms != null) {
870                 boSupported = iccISms.isImsSmsSupportedForSubscriber(getSubscriptionId());
871             }
872         } catch (RemoteException ex) {
873             // ignore it
874         }
875         return boSupported;
876     }
877 
878     /**
879      * Gets SMS format supported on IMS.  SMS over IMS format is
880      * either 3GPP or 3GPP2.
881      *
882      * @return SmsMessage.FORMAT_3GPP,
883      *         SmsMessage.FORMAT_3GPP2
884      *      or SmsMessage.FORMAT_UNKNOWN
885      *
886      * @see #isImsSmsSupported()
887      *
888      * @hide
889      */
getImsSmsFormat()890     public String getImsSmsFormat() {
891         String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
892         try {
893             ISms iccISms = getISmsService();
894             if (iccISms != null) {
895                 format = iccISms.getImsSmsFormatForSubscriber(getSubscriptionId());
896             }
897         } catch (RemoteException ex) {
898             // ignore it
899         }
900         return format;
901     }
902 
903     /**
904      * Get default sms subscription id
905      *
906      * @return the default SMS subscription id
907      */
getDefaultSmsSubscriptionId()908     public static int getDefaultSmsSubscriptionId() {
909         ISms iccISms = null;
910         try {
911             iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
912             return iccISms.getPreferredSmsSubscription();
913         } catch (RemoteException ex) {
914             return -1;
915         } catch (NullPointerException ex) {
916             return -1;
917         }
918     }
919 
920     /**
921      * Get SMS prompt property,  enabled or not
922      *
923      * @return true if enabled, false otherwise
924      * @hide
925      */
isSMSPromptEnabled()926     public boolean isSMSPromptEnabled() {
927         ISms iccISms = null;
928         try {
929             iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
930             return iccISms.isSMSPromptEnabled();
931         } catch (RemoteException ex) {
932             return false;
933         } catch (NullPointerException ex) {
934             return false;
935         }
936     }
937 
938     // see SmsMessage.getStatusOnIcc
939 
940     /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
941     static public final int STATUS_ON_ICC_FREE      = 0;
942 
943     /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
944     static public final int STATUS_ON_ICC_READ      = 1;
945 
946     /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
947     static public final int STATUS_ON_ICC_UNREAD    = 3;
948 
949     /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
950     static public final int STATUS_ON_ICC_SENT      = 5;
951 
952     /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
953     static public final int STATUS_ON_ICC_UNSENT    = 7;
954 
955     // SMS send failure result codes
956 
957     /** Generic failure cause */
958     static public final int RESULT_ERROR_GENERIC_FAILURE    = 1;
959     /** Failed because radio was explicitly turned off */
960     static public final int RESULT_ERROR_RADIO_OFF          = 2;
961     /** Failed because no pdu provided */
962     static public final int RESULT_ERROR_NULL_PDU           = 3;
963     /** Failed because service is currently unavailable */
964     static public final int RESULT_ERROR_NO_SERVICE         = 4;
965     /** Failed because we reached the sending queue limit.  {@hide} */
966     static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
967     /** Failed because FDN is enabled. {@hide} */
968     static public final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
969 
970     static private final String PHONE_PACKAGE_NAME = "com.android.phone";
971 
972     /**
973      * Send an MMS message
974      *
975      * @param context application context
976      * @param contentUri the content Uri from which the message pdu will be read
977      * @param locationUrl the optional location url where message should be sent to
978      * @param configOverrides the carrier-specific messaging configuration values to override for
979      *  sending the message.
980      * @param sentIntent if not NULL this <code>PendingIntent</code> is
981      *  broadcast when the message is successfully sent, or failed
982      * @throws IllegalArgumentException if contentUri is empty
983      */
sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent)984     public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
985             Bundle configOverrides, PendingIntent sentIntent) {
986         if (contentUri == null) {
987             throw new IllegalArgumentException("Uri contentUri null");
988         }
989         try {
990             final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
991             if (iMms == null) {
992                 return;
993             }
994 
995             iMms.sendMessage(getSubscriptionId(), ActivityThread.currentPackageName(), contentUri,
996                     locationUrl, configOverrides, sentIntent);
997         } catch (RemoteException e) {
998             // Ignore it
999         }
1000     }
1001 
1002     /**
1003      * Download an MMS message from carrier by a given location URL
1004      *
1005      * @param context application context
1006      * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
1007      *  from the MMS WAP push notification
1008      * @param contentUri the content uri to which the downloaded pdu will be written
1009      * @param configOverrides the carrier-specific messaging configuration values to override for
1010      *  downloading the message.
1011      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
1012      *  broadcast when the message is downloaded, or the download is failed
1013      * @throws IllegalArgumentException if locationUrl or contentUri is empty
1014      */
downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent)1015     public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
1016             Bundle configOverrides, PendingIntent downloadedIntent) {
1017         if (TextUtils.isEmpty(locationUrl)) {
1018             throw new IllegalArgumentException("Empty MMS location URL");
1019         }
1020         if (contentUri == null) {
1021             throw new IllegalArgumentException("Uri contentUri null");
1022         }
1023         try {
1024             final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1025             if (iMms == null) {
1026                 return;
1027             }
1028             iMms.downloadMessage(
1029                     getSubscriptionId(), ActivityThread.currentPackageName(), locationUrl,
1030                     contentUri, configOverrides, downloadedIntent);
1031         } catch (RemoteException e) {
1032             // Ignore it
1033         }
1034     }
1035 
1036     // MMS send/download failure result codes
1037     public static final int MMS_ERROR_UNSPECIFIED = 1;
1038     public static final int MMS_ERROR_INVALID_APN = 2;
1039     public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
1040     public static final int MMS_ERROR_HTTP_FAILURE = 4;
1041     public static final int MMS_ERROR_IO_ERROR = 5;
1042     public static final int MMS_ERROR_RETRY = 6;
1043     public static final int MMS_ERROR_CONFIGURATION_ERROR = 7;
1044     public static final int MMS_ERROR_NO_DATA_NETWORK = 8;
1045 
1046     /** Intent extra name for MMS sending result data in byte array type */
1047     public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
1048     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
1049     public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
1050 
1051     /**
1052      * Import a text message into system's SMS store
1053      *
1054      * Only default SMS apps can import SMS
1055      *
1056      * @param address the destination(source) address of the sent(received) message
1057      * @param type the type of the message
1058      * @param text the message text
1059      * @param timestampMillis the message timestamp in milliseconds
1060      * @param seen if the message is seen
1061      * @param read if the message is read
1062      * @return the message URI, null if failed
1063      * @hide
1064      */
importTextMessage(String address, int type, String text, long timestampMillis, boolean seen, boolean read)1065     public Uri importTextMessage(String address, int type, String text, long timestampMillis,
1066             boolean seen, boolean read) {
1067         try {
1068             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1069             if (iMms != null) {
1070                 return iMms.importTextMessage(ActivityThread.currentPackageName(),
1071                         address, type, text, timestampMillis, seen, read);
1072             }
1073         } catch (RemoteException ex) {
1074             // ignore it
1075         }
1076         return null;
1077     }
1078 
1079     /** Represents the received SMS message for importing {@hide} */
1080     public static final int SMS_TYPE_INCOMING = 0;
1081     /** Represents the sent SMS message for importing {@hide} */
1082     public static final int SMS_TYPE_OUTGOING = 1;
1083 
1084     /**
1085      * Import a multimedia message into system's MMS store. Only the following PDU type is
1086      * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind
1087      *
1088      * Only default SMS apps can import MMS
1089      *
1090      * @param contentUri the content uri from which to read the PDU of the message to import
1091      * @param messageId the optional message id. Use null if not specifying
1092      * @param timestampSecs the optional message timestamp. Use -1 if not specifying
1093      * @param seen if the message is seen
1094      * @param read if the message is read
1095      * @return the message URI, null if failed
1096      * @throws IllegalArgumentException if pdu is empty
1097      * {@hide}
1098      */
importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs, boolean seen, boolean read)1099     public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs,
1100             boolean seen, boolean read) {
1101         if (contentUri == null) {
1102             throw new IllegalArgumentException("Uri contentUri null");
1103         }
1104         try {
1105             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1106             if (iMms != null) {
1107                 return iMms.importMultimediaMessage(ActivityThread.currentPackageName(),
1108                         contentUri, messageId, timestampSecs, seen, read);
1109             }
1110         } catch (RemoteException ex) {
1111             // ignore it
1112         }
1113         return null;
1114     }
1115 
1116     /**
1117      * Delete a system stored SMS or MMS message
1118      *
1119      * Only default SMS apps can delete system stored SMS and MMS messages
1120      *
1121      * @param messageUri the URI of the stored message
1122      * @return true if deletion is successful, false otherwise
1123      * @throws IllegalArgumentException if messageUri is empty
1124      * {@hide}
1125      */
deleteStoredMessage(Uri messageUri)1126     public boolean deleteStoredMessage(Uri messageUri) {
1127         if (messageUri == null) {
1128             throw new IllegalArgumentException("Empty message URI");
1129         }
1130         try {
1131             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1132             if (iMms != null) {
1133                 return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri);
1134             }
1135         } catch (RemoteException ex) {
1136             // ignore it
1137         }
1138         return false;
1139     }
1140 
1141     /**
1142      * Delete a system stored SMS or MMS thread
1143      *
1144      * Only default SMS apps can delete system stored SMS and MMS conversations
1145      *
1146      * @param conversationId the ID of the message conversation
1147      * @return true if deletion is successful, false otherwise
1148      * {@hide}
1149      */
deleteStoredConversation(long conversationId)1150     public boolean deleteStoredConversation(long conversationId) {
1151         try {
1152             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1153             if (iMms != null) {
1154                 return iMms.deleteStoredConversation(
1155                         ActivityThread.currentPackageName(), conversationId);
1156             }
1157         } catch (RemoteException ex) {
1158             // ignore it
1159         }
1160         return false;
1161     }
1162 
1163     /**
1164      * Update the status properties of a system stored SMS or MMS message, e.g.
1165      * the read status of a message, etc.
1166      *
1167      * @param messageUri the URI of the stored message
1168      * @param statusValues a list of status properties in key-value pairs to update
1169      * @return true if update is successful, false otherwise
1170      * @throws IllegalArgumentException if messageUri is empty
1171      * {@hide}
1172      */
updateStoredMessageStatus(Uri messageUri, ContentValues statusValues)1173     public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) {
1174         if (messageUri == null) {
1175             throw new IllegalArgumentException("Empty message URI");
1176         }
1177         try {
1178             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1179             if (iMms != null) {
1180                 return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(),
1181                         messageUri, statusValues);
1182             }
1183         } catch (RemoteException ex) {
1184             // ignore it
1185         }
1186         return false;
1187     }
1188 
1189     /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */
1190     public static final String MESSAGE_STATUS_SEEN = "seen";
1191     /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */
1192     public static final String MESSAGE_STATUS_READ = "read";
1193 
1194     /**
1195      * Archive or unarchive a stored conversation
1196      *
1197      * @param conversationId the ID of the message conversation
1198      * @param archived true to archive the conversation, false to unarchive
1199      * @return true if update is successful, false otherwise
1200      * {@hide}
1201      */
archiveStoredConversation(long conversationId, boolean archived)1202     public boolean archiveStoredConversation(long conversationId, boolean archived) {
1203         try {
1204             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1205             if (iMms != null) {
1206                 return iMms.archiveStoredConversation(ActivityThread.currentPackageName(),
1207                         conversationId, archived);
1208             }
1209         } catch (RemoteException ex) {
1210             // ignore it
1211         }
1212         return false;
1213     }
1214 
1215     /**
1216      * Add a text message draft to system SMS store
1217      *
1218      * Only default SMS apps can add SMS draft
1219      *
1220      * @param address the destination address of message
1221      * @param text the body of the message to send
1222      * @return the URI of the stored draft message
1223      * {@hide}
1224      */
addTextMessageDraft(String address, String text)1225     public Uri addTextMessageDraft(String address, String text) {
1226         try {
1227             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1228             if (iMms != null) {
1229                 return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text);
1230             }
1231         } catch (RemoteException ex) {
1232             // ignore it
1233         }
1234         return null;
1235     }
1236 
1237     /**
1238      * Add a multimedia message draft to system MMS store
1239      *
1240      * Only default SMS apps can add MMS draft
1241      *
1242      * @param contentUri the content uri from which to read the PDU data of the draft MMS
1243      * @return the URI of the stored draft message
1244      * @throws IllegalArgumentException if pdu is empty
1245      * {@hide}
1246      */
addMultimediaMessageDraft(Uri contentUri)1247     public Uri addMultimediaMessageDraft(Uri contentUri) {
1248         if (contentUri == null) {
1249             throw new IllegalArgumentException("Uri contentUri null");
1250         }
1251         try {
1252             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1253             if (iMms != null) {
1254                 return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(),
1255                         contentUri);
1256             }
1257         } catch (RemoteException ex) {
1258             // ignore it
1259         }
1260         return null;
1261     }
1262 
1263     /**
1264      * Send a system stored text message.
1265      *
1266      * You can only send a failed text message or a draft text message.
1267      *
1268      * @param messageUri the URI of the stored message
1269      * @param scAddress is the service center address or null to use the current default SMSC
1270      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1271      *  broadcast when the message is successfully sent, or failed.
1272      *  The result code will be <code>Activity.RESULT_OK</code> for success,
1273      *  or one of these errors:<br>
1274      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
1275      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
1276      *  <code>RESULT_ERROR_NULL_PDU</code><br>
1277      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
1278      *  the extra "errorCode" containing a radio technology specific value,
1279      *  generally only useful for troubleshooting.<br>
1280      *  The per-application based SMS control checks sentIntent. If sentIntent
1281      *  is NULL the caller will be checked against all unknown applications,
1282      *  which cause smaller number of SMS to be sent in checking period.
1283      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
1284      *  broadcast when the message is delivered to the recipient.  The
1285      *  raw pdu of the status report is in the extended data ("pdu").
1286      *
1287      * @throws IllegalArgumentException if messageUri is empty
1288      * {@hide}
1289      */
sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent, PendingIntent deliveryIntent)1290     public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent,
1291             PendingIntent deliveryIntent) {
1292         if (messageUri == null) {
1293             throw new IllegalArgumentException("Empty message URI");
1294         }
1295         try {
1296             ISms iccISms = getISmsServiceOrThrow();
1297             iccISms.sendStoredText(
1298                     getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
1299                     scAddress, sentIntent, deliveryIntent);
1300         } catch (RemoteException ex) {
1301             // ignore it
1302         }
1303     }
1304 
1305     /**
1306      * Send a system stored multi-part text message.
1307      *
1308      * You can only send a failed text message or a draft text message.
1309      * The provided <code>PendingIntent</code> lists should match the part number of the
1310      * divided text of the stored message by using <code>divideMessage</code>
1311      *
1312      * @param messageUri the URI of the stored message
1313      * @param scAddress is the service center address or null to use
1314      *   the current default SMSC
1315      * @param sentIntents if not null, an <code>ArrayList</code> of
1316      *   <code>PendingIntent</code>s (one for each message part) that is
1317      *   broadcast when the corresponding message part has been sent.
1318      *   The result code will be <code>Activity.RESULT_OK</code> for success,
1319      *   or one of these errors:<br>
1320      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
1321      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
1322      *   <code>RESULT_ERROR_NULL_PDU</code><br>
1323      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
1324      *   the extra "errorCode" containing a radio technology specific value,
1325      *   generally only useful for troubleshooting.<br>
1326      *   The per-application based SMS control checks sentIntent. If sentIntent
1327      *   is NULL the caller will be checked against all unknown applications,
1328      *   which cause smaller number of SMS to be sent in checking period.
1329      * @param deliveryIntents if not null, an <code>ArrayList</code> of
1330      *   <code>PendingIntent</code>s (one for each message part) that is
1331      *   broadcast when the corresponding message part has been delivered
1332      *   to the recipient.  The raw pdu of the status report is in the
1333      *   extended data ("pdu").
1334      *
1335      * @throws IllegalArgumentException if messageUri is empty
1336      * {@hide}
1337      */
sendStoredMultipartTextMessage(Uri messageUri, String scAddress, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)1338     public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress,
1339             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
1340         if (messageUri == null) {
1341             throw new IllegalArgumentException("Empty message URI");
1342         }
1343         try {
1344             ISms iccISms = getISmsServiceOrThrow();
1345             iccISms.sendStoredMultipartText(
1346                     getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
1347                     scAddress, sentIntents, deliveryIntents);
1348         } catch (RemoteException ex) {
1349             // ignore it
1350         }
1351     }
1352 
1353     /**
1354      * Send a system stored MMS message
1355      *
1356      * This is used for sending a previously sent, but failed-to-send, message or
1357      * for sending a text message that has been stored as a draft.
1358      *
1359      * @param messageUri the URI of the stored message
1360      * @param configOverrides the carrier-specific messaging configuration values to override for
1361      *  sending the message.
1362      * @param sentIntent if not NULL this <code>PendingIntent</code> is
1363      *  broadcast when the message is successfully sent, or failed
1364      * @throws IllegalArgumentException if messageUri is empty
1365      * {@hide}
1366      */
sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides, PendingIntent sentIntent)1367     public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides,
1368             PendingIntent sentIntent) {
1369         if (messageUri == null) {
1370             throw new IllegalArgumentException("Empty message URI");
1371         }
1372         try {
1373             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1374             if (iMms != null) {
1375                 iMms.sendStoredMessage(
1376                         getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
1377                         configOverrides, sentIntent);
1378             }
1379         } catch (RemoteException ex) {
1380             // ignore it
1381         }
1382     }
1383 
1384     /**
1385      * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system
1386      *
1387      * When this flag is on, all SMS/MMS sent/received are stored by system automatically
1388      * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
1389      * automatically
1390      *
1391      * This flag can only be changed by default SMS apps
1392      *
1393      * @param enabled Whether to enable message auto persisting
1394      * {@hide}
1395      */
setAutoPersisting(boolean enabled)1396     public void setAutoPersisting(boolean enabled) {
1397         try {
1398             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1399             if (iMms != null) {
1400                 iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled);
1401             }
1402         } catch (RemoteException ex) {
1403             // ignore it
1404         }
1405     }
1406 
1407     /**
1408      * Get the value of the flag to automatically write sent/received SMS/MMS messages into system
1409      *
1410      * When this flag is on, all SMS/MMS sent/received are stored by system automatically
1411      * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
1412      * automatically
1413      *
1414      * @return the current value of the auto persist flag
1415      * {@hide}
1416      */
getAutoPersisting()1417     public boolean getAutoPersisting() {
1418         try {
1419             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1420             if (iMms != null) {
1421                 return iMms.getAutoPersisting();
1422             }
1423         } catch (RemoteException ex) {
1424             // ignore it
1425         }
1426         return false;
1427     }
1428 
1429     /**
1430      * Get carrier-dependent configuration values.
1431      *
1432      * @return bundle key/values pairs of configuration values
1433      */
getCarrierConfigValues()1434     public Bundle getCarrierConfigValues() {
1435         try {
1436             IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1437             if (iMms != null) {
1438                 return iMms.getCarrierConfigValues(getSubscriptionId());
1439             }
1440         } catch (RemoteException ex) {
1441             // ignore it
1442         }
1443         return null;
1444     }
1445 
1446 }
1447