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