SmsManager.java revision a2091571054b8fcf38ed112dfaac6240b6ade301
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 SmsManager associated with the default subId. The instance will always be
453     * associated with the default subId, even if the default subId is changed.
454     *
455     * @return the SmsManager associated with the default subId
456     */
457    public static SmsManager getDefault() {
458        return sInstance;
459    }
460
461    /**
462     * Get the the instance of the SmsManager associated with a particular subId
463     *
464     * @param subId a SMS subscription id, typically accessed using
465     *   {@link android.telephony.SubscriptionManager}
466     * @return the instance of the SmsManager associated with subId
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 {@link android.telephony.SubscriptionManager#INVALID_SUB_ID}
488     * if the default subId cannot be determined.
489     *
490     * @return associated subId
491     */
492    public long getSubId() {
493        if (mSubId == DEFAULT_SUB_ID) {
494            return getDefaultSmsSubId();
495        }
496        return mSubId;
497    }
498
499    /**
500     * Returns the ISms service, or throws an UnsupportedOperationException if
501     * the service does not exist.
502     */
503    private static ISms getISmsServiceOrThrow() {
504        ISms iccISms = getISmsService();
505        if (iccISms == null) {
506            throw new UnsupportedOperationException("Sms is not supported");
507        }
508        return iccISms;
509    }
510
511    private static ISms getISmsService() {
512        return ISms.Stub.asInterface(ServiceManager.getService("isms"));
513    }
514
515    /**
516     * Copy a raw SMS PDU to the ICC.
517     * ICC (Integrated Circuit Card) is the card of the device.
518     * For example, this can be the SIM or USIM for GSM.
519     *
520     * @param smsc the SMSC for this message, or NULL for the default SMSC
521     * @param pdu the raw PDU to store
522     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
523     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
524     * @return true for success
525     *
526     * @throws IllegalArgumentException if pdu is NULL
527     * {@hide}
528     */
529    public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
530        boolean success = false;
531
532        if (null == pdu) {
533            throw new IllegalArgumentException("pdu is NULL");
534        }
535        try {
536            ISms iccISms = getISmsService();
537            if (iccISms != null) {
538                success = iccISms.copyMessageToIccEf(ActivityThread.currentPackageName(),
539                        status, pdu, smsc);
540            }
541        } catch (RemoteException ex) {
542            // ignore it
543        }
544
545        return success;
546    }
547
548    /**
549     * Delete the specified message from the ICC.
550     * ICC (Integrated Circuit Card) is the card of the device.
551     * For example, this can be the SIM or USIM for GSM.
552     *
553     * @param messageIndex is the record index of the message on ICC
554     * @return true for success
555     *
556     * {@hide}
557     */
558    public boolean
559    deleteMessageFromIcc(int messageIndex) {
560        boolean success = false;
561        byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1];
562        Arrays.fill(pdu, (byte)0xff);
563
564        try {
565            ISms iccISms = getISmsService();
566            if (iccISms != null) {
567                success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(),
568                        messageIndex, STATUS_ON_ICC_FREE, pdu);
569            }
570        } catch (RemoteException ex) {
571            // ignore it
572        }
573
574        return success;
575    }
576
577    /**
578     * Update the specified message on the ICC.
579     * ICC (Integrated Circuit Card) is the card of the device.
580     * For example, this can be the SIM or USIM for GSM.
581     *
582     * @param messageIndex record index of message to update
583     * @param newStatus new message status (STATUS_ON_ICC_READ,
584     *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
585     *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
586     * @param pdu the raw PDU to store
587     * @return true for success
588     *
589     * {@hide}
590     */
591    public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
592        boolean success = false;
593
594        try {
595            ISms iccISms = getISmsService();
596            if (iccISms != null) {
597                success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(),
598                        messageIndex, newStatus, pdu);
599            }
600        } catch (RemoteException ex) {
601            // ignore it
602        }
603
604        return success;
605    }
606
607    /**
608     * Retrieves all messages currently stored on ICC.
609     * ICC (Integrated Circuit Card) is the card of the device.
610     * For example, this can be the SIM or USIM for GSM.
611     *
612     * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
613     *
614     * {@hide}
615     */
616    public static ArrayList<SmsMessage> getAllMessagesFromIcc() {
617        List<SmsRawData> records = null;
618
619        try {
620            ISms iccISms = getISmsService();
621            if (iccISms != null) {
622                records = iccISms.getAllMessagesFromIccEf(ActivityThread.currentPackageName());
623            }
624        } catch (RemoteException ex) {
625            // ignore it
626        }
627
628        return createMessageListFromRawRecords(records);
629    }
630
631    /**
632     * Enable reception of cell broadcast (SMS-CB) messages with the given
633     * message identifier. Note that if two different clients enable the same
634     * message identifier, they must both disable it for the device to stop
635     * receiving those messages. All received messages will be broadcast in an
636     * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
637     * Note: This call is blocking, callers may want to avoid calling it from
638     * the main thread of an application.
639     *
640     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
641     * or C.R1001-G (3GPP2)
642     * @return true if successful, false otherwise
643     * @see #disableCellBroadcast(int)
644     *
645     * {@hide}
646     */
647    public boolean enableCellBroadcast(int messageIdentifier) {
648        boolean success = false;
649
650        try {
651            ISms iccISms = getISmsService();
652            if (iccISms != null) {
653                success = iccISms.enableCellBroadcast(messageIdentifier);
654            }
655        } catch (RemoteException ex) {
656            // ignore it
657        }
658
659        return success;
660    }
661
662    /**
663     * Disable reception of cell broadcast (SMS-CB) messages with the given
664     * message identifier. Note that if two different clients enable the same
665     * message identifier, they must both disable it for the device to stop
666     * receiving those messages.
667     * Note: This call is blocking, callers may want to avoid calling it from
668     * the main thread of an application.
669     *
670     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
671     * or C.R1001-G (3GPP2)
672     * @return true if successful, false otherwise
673     *
674     * @see #enableCellBroadcast(int)
675     *
676     * {@hide}
677     */
678    public boolean disableCellBroadcast(int messageIdentifier) {
679        boolean success = false;
680
681        try {
682            ISms iccISms = getISmsService();
683            if (iccISms != null) {
684                success = iccISms.disableCellBroadcast(messageIdentifier);
685            }
686        } catch (RemoteException ex) {
687            // ignore it
688        }
689
690        return success;
691    }
692
693    /**
694     * Enable reception of cell broadcast (SMS-CB) messages with the given
695     * message identifier range. Note that if two different clients enable the same
696     * message identifier, they must both disable it for the device to stop
697     * receiving those messages. All received messages will be broadcast in an
698     * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
699     * Note: This call is blocking, callers may want to avoid calling it from
700     * the main thread of an application.
701     *
702     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
703     * or C.R1001-G (3GPP2)
704     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
705     * or C.R1001-G (3GPP2)
706     * @return true if successful, false otherwise
707     * @see #disableCellBroadcastRange(int, int)
708     *
709     * @throws IllegalArgumentException if endMessageId < startMessageId
710     * {@hide}
711     */
712    public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) {
713        boolean success = false;
714
715        if (endMessageId < startMessageId) {
716            throw new IllegalArgumentException("endMessageId < startMessageId");
717        }
718        try {
719            ISms iccISms = getISmsService();
720            if (iccISms != null) {
721                success = iccISms.enableCellBroadcastRange(startMessageId, endMessageId);
722            }
723        } catch (RemoteException ex) {
724            // ignore it
725        }
726
727        return success;
728    }
729
730    /**
731     * Disable reception of cell broadcast (SMS-CB) messages with the given
732     * message identifier range. Note that if two different clients enable the same
733     * message identifier, they must both disable it for the device to stop
734     * receiving those messages.
735     * Note: This call is blocking, callers may want to avoid calling it from
736     * the main thread of an application.
737     *
738     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
739     * or C.R1001-G (3GPP2)
740     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
741     * or C.R1001-G (3GPP2)
742     * @return true if successful, false otherwise
743     *
744     * @see #enableCellBroadcastRange(int, int)
745     *
746     * @throws IllegalArgumentException if endMessageId < startMessageId
747     * {@hide}
748     */
749    public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) {
750        boolean success = false;
751
752        if (endMessageId < startMessageId) {
753            throw new IllegalArgumentException("endMessageId < startMessageId");
754        }
755        try {
756            ISms iccISms = getISmsService();
757            if (iccISms != null) {
758                success = iccISms.disableCellBroadcastRange(startMessageId, endMessageId);
759            }
760        } catch (RemoteException ex) {
761            // ignore it
762        }
763
764        return success;
765    }
766
767    /**
768     * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
769     * records returned by <code>getAllMessagesFromIcc()</code>
770     *
771     * @param records SMS EF records, returned by
772     *   <code>getAllMessagesFromIcc</code>
773     * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
774     */
775    private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
776        ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
777        if (records != null) {
778            int count = records.size();
779            for (int i = 0; i < count; i++) {
780                SmsRawData data = records.get(i);
781                // List contains all records, including "free" records (null)
782                if (data != null) {
783                    SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
784                    if (sms != null) {
785                        messages.add(sms);
786                    }
787                }
788            }
789        }
790        return messages;
791    }
792
793    /**
794     * SMS over IMS is supported if IMS is registered and SMS is supported
795     * on IMS.
796     *
797     * @return true if SMS over IMS is supported, false otherwise
798     *
799     * @see #getImsSmsFormat()
800     *
801     * @hide
802     */
803    boolean isImsSmsSupported() {
804        boolean boSupported = false;
805        try {
806            ISms iccISms = getISmsService();
807            if (iccISms != null) {
808                boSupported = iccISms.isImsSmsSupported();
809            }
810        } catch (RemoteException ex) {
811            // ignore it
812        }
813        return boSupported;
814    }
815
816    /**
817     * Gets SMS format supported on IMS.  SMS over IMS format is
818     * either 3GPP or 3GPP2.
819     *
820     * @return SmsMessage.FORMAT_3GPP,
821     *         SmsMessage.FORMAT_3GPP2
822     *      or SmsMessage.FORMAT_UNKNOWN
823     *
824     * @see #isImsSmsSupported()
825     *
826     * @hide
827     */
828    String getImsSmsFormat() {
829        String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
830        try {
831            ISms iccISms = getISmsService();
832            if (iccISms != null) {
833                format = iccISms.getImsSmsFormat();
834            }
835        } catch (RemoteException ex) {
836            // ignore it
837        }
838        return format;
839    }
840
841    /**
842     * Get default sms subId
843     *
844     * @return the default SubId
845     * @hide
846     */
847    public static long getDefaultSmsSubId() {
848        return SubscriptionManager.getDefaultSmsSubId();
849    }
850
851    /**
852     * Get SMS prompt property,  enabled or not
853     *
854     * @return true if enabled, false otherwise
855     * @hide
856     */
857    public boolean isSMSPromptEnabled() {
858        ISms iccISms = null;
859        try {
860            iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
861            return iccISms.isSMSPromptEnabled();
862        } catch (RemoteException ex) {
863            return false;
864        } catch (NullPointerException ex) {
865            return false;
866        }
867    }
868
869    // see SmsMessage.getStatusOnIcc
870
871    /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
872    static public final int STATUS_ON_ICC_FREE      = 0;
873
874    /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
875    static public final int STATUS_ON_ICC_READ      = 1;
876
877    /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
878    static public final int STATUS_ON_ICC_UNREAD    = 3;
879
880    /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
881    static public final int STATUS_ON_ICC_SENT      = 5;
882
883    /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
884    static public final int STATUS_ON_ICC_UNSENT    = 7;
885
886    // SMS send failure result codes
887
888    /** Generic failure cause */
889    static public final int RESULT_ERROR_GENERIC_FAILURE    = 1;
890    /** Failed because radio was explicitly turned off */
891    static public final int RESULT_ERROR_RADIO_OFF          = 2;
892    /** Failed because no pdu provided */
893    static public final int RESULT_ERROR_NULL_PDU           = 3;
894    /** Failed because service is currently unavailable */
895    static public final int RESULT_ERROR_NO_SERVICE         = 4;
896    /** Failed because we reached the sending queue limit.  {@hide} */
897    static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
898    /** Failed because FDN is enabled. {@hide} */
899    static public final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
900
901    /**
902     * Send an MMS message
903     *
904     * @param contentUri the content Uri from which the message pdu will be read
905     * @param locationUrl the optional location url where message should be sent to
906     * @param configOverrides the carrier-specific messaging configuration values to override for
907     *  sending the message.
908     * @param sentIntent if not NULL this <code>PendingIntent</code> is
909     *  broadcast when the message is successfully sent, or failed
910     * @throws IllegalArgumentException if contentUri is empty
911     */
912    public void sendMultimediaMessage(Uri contentUri, String locationUrl,
913            Bundle configOverrides, PendingIntent sentIntent) {
914        if (contentUri == null) {
915            throw new IllegalArgumentException("Uri contentUri null");
916        }
917        try {
918            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
919            if (iMms == null) {
920                return;
921            }
922            iMms.sendMessage(getSubId(), ActivityThread.currentPackageName(), contentUri,
923                    locationUrl, configOverrides, sentIntent);
924        } catch (RemoteException e) {
925            // Ignore it
926        }
927    }
928
929    /**
930     * Download an MMS message from carrier by a given location URL
931     *
932     * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
933     *  from the MMS WAP push notification
934     * @param contentUri the content uri to which the downloaded pdu will be written
935     * @param configOverrides the carrier-specific messaging configuration values to override for
936     *  downloading the message.
937     * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
938     *  broadcast when the message is downloaded, or the download is failed
939     * @throws IllegalArgumentException if locationUrl or contentUri is empty
940     */
941    public void downloadMultimediaMessage(String locationUrl, Uri contentUri,
942            Bundle configOverrides, PendingIntent downloadedIntent) {
943        if (TextUtils.isEmpty(locationUrl)) {
944            throw new IllegalArgumentException("Empty MMS location URL");
945        }
946        if (contentUri == null) {
947            throw new IllegalArgumentException("Uri contentUri null");
948        }
949        try {
950            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
951            if (iMms == null) {
952                return;
953            }
954            iMms.downloadMessage(getSubId(), ActivityThread.currentPackageName(), locationUrl,
955                    contentUri, configOverrides, downloadedIntent);
956        } catch (RemoteException e) {
957            // Ignore it
958        }
959    }
960
961    // MMS send/download failure result codes
962    public static final int MMS_ERROR_UNSPECIFIED = 1;
963    public static final int MMS_ERROR_INVALID_APN = 2;
964    public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
965    public static final int MMS_ERROR_HTTP_FAILURE = 4;
966    public static final int MMS_ERROR_IO_ERROR = 5;
967
968    // Intent extra name for result data
969    public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
970
971    /**
972     * Update the status of a pending (send-by-IP) MMS message handled by the carrier app.
973     * If the carrier app fails to send this message, it would be resent via carrier network.
974     *
975     * The caller should have carrier privileges.
976     * @see android.telephony.TelephonyManager.hasCarrierPrivileges
977     *
978     * @param messageRef the reference number of the MMS message.
979     * @param success True if and only if the message was sent successfully. If its value is
980     *  false, this message should be resent via carrier network
981     */
982    public void updateMmsSendStatus(int messageRef, boolean success) {
983        try {
984            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
985            if (iMms == null) {
986                return;
987            }
988            iMms.updateMmsSendStatus(messageRef, success);
989        } catch (RemoteException ex) {
990            // ignore it
991        }
992    }
993
994    /**
995     * Update the status of a pending (download-by-IP) MMS message handled by the carrier app.
996     * If the carrier app fails to download this message, it would be re-downloaded via carrier
997     * network.
998     *
999     * The caller should have carrier privileges.
1000     * @see android.telephony.TelephonyManager.hasCarrierPrivileges
1001     *
1002     * @param messageRef the reference number of the MMS message.
1003     * @param pdu non-empty if downloaded successfully, otherwise, it is empty and the message
1004     *  will be downloaded via carrier network
1005     */
1006    public void updateMmsDownloadStatus(int messageRef, byte[] pdu) {
1007        try {
1008            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1009            if (iMms == null) {
1010                return;
1011            }
1012            iMms.updateMmsDownloadStatus(messageRef, pdu);
1013        } catch (RemoteException ex) {
1014            // ignore it
1015        }
1016    }
1017
1018    /**
1019     * Import a text message into system's SMS store
1020     *
1021     * Only default SMS apps can import SMS
1022     *
1023     * @param address the destination(source) address of the sent(received) message
1024     * @param type the type of the message
1025     * @param text the message text
1026     * @param timestampMillis the message timestamp in milliseconds
1027     * @param seen if the message is seen
1028     * @param read if the message is read
1029     * @return the message URI, null if failed
1030     * @hide
1031     */
1032    public Uri importTextMessage(String address, int type, String text, long timestampMillis,
1033            boolean seen, boolean read) {
1034        try {
1035            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1036            if (iMms != null) {
1037                return iMms.importTextMessage(ActivityThread.currentPackageName(),
1038                        address, type, text, timestampMillis, seen, read);
1039            }
1040        } catch (RemoteException ex) {
1041            // ignore it
1042        }
1043        return null;
1044    }
1045
1046    /** Represents the received SMS message for importing {@hide} */
1047    public static final int SMS_TYPE_INCOMING = 0;
1048    /** Represents the sent SMS message for importing {@hide} */
1049    public static final int SMS_TYPE_OUTGOING = 1;
1050
1051    /**
1052     * Import a multimedia message into system's MMS store. Only the following PDU type is
1053     * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind
1054     *
1055     * Only default SMS apps can import MMS
1056     *
1057     * @param contentUri the content uri from which to read the PDU of the message to import
1058     * @param messageId the optional message id. Use null if not specifying
1059     * @param timestampSecs the optional message timestamp. Use -1 if not specifying
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     * @throws IllegalArgumentException if pdu is empty
1064     * {@hide}
1065     */
1066    public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs,
1067            boolean seen, boolean read) {
1068        if (contentUri == null) {
1069            throw new IllegalArgumentException("Uri contentUri null");
1070        }
1071        try {
1072            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1073            if (iMms != null) {
1074                return iMms.importMultimediaMessage(ActivityThread.currentPackageName(),
1075                        contentUri, messageId, timestampSecs, seen, read);
1076            }
1077        } catch (RemoteException ex) {
1078            // ignore it
1079        }
1080        return null;
1081    }
1082
1083    /**
1084     * Delete a system stored SMS or MMS message
1085     *
1086     * Only default SMS apps can delete system stored SMS and MMS messages
1087     *
1088     * @param messageUri the URI of the stored message
1089     * @return true if deletion is successful, false otherwise
1090     * @throws IllegalArgumentException if messageUri is empty
1091     * {@hide}
1092     */
1093    public boolean deleteStoredMessage(Uri messageUri) {
1094        if (messageUri == null) {
1095            throw new IllegalArgumentException("Empty message URI");
1096        }
1097        try {
1098            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1099            if (iMms != null) {
1100                return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri);
1101            }
1102        } catch (RemoteException ex) {
1103            // ignore it
1104        }
1105        return false;
1106    }
1107
1108    /**
1109     * Delete a system stored SMS or MMS thread
1110     *
1111     * Only default SMS apps can delete system stored SMS and MMS conversations
1112     *
1113     * @param conversationId the ID of the message conversation
1114     * @return true if deletion is successful, false otherwise
1115     * {@hide}
1116     */
1117    public boolean deleteStoredConversation(long conversationId) {
1118        try {
1119            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1120            if (iMms != null) {
1121                return iMms.deleteStoredConversation(
1122                        ActivityThread.currentPackageName(), conversationId);
1123            }
1124        } catch (RemoteException ex) {
1125            // ignore it
1126        }
1127        return false;
1128    }
1129
1130    /**
1131     * Update the status properties of a system stored SMS or MMS message, e.g.
1132     * the read status of a message, etc.
1133     *
1134     * @param messageUri the URI of the stored message
1135     * @param statusValues a list of status properties in key-value pairs to update
1136     * @return true if update is successful, false otherwise
1137     * @throws IllegalArgumentException if messageUri is empty
1138     * {@hide}
1139     */
1140    public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) {
1141        if (messageUri == null) {
1142            throw new IllegalArgumentException("Empty message URI");
1143        }
1144        try {
1145            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1146            if (iMms != null) {
1147                return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(),
1148                        messageUri, statusValues);
1149            }
1150        } catch (RemoteException ex) {
1151            // ignore it
1152        }
1153        return false;
1154    }
1155
1156    /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */
1157    public static final String MESSAGE_STATUS_SEEN = "seen";
1158    /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */
1159    public static final String MESSAGE_STATUS_READ = "read";
1160
1161    /**
1162     * Archive or unarchive a stored conversation
1163     *
1164     * @param conversationId the ID of the message conversation
1165     * @param archived true to archive the conversation, false to unarchive
1166     * @return true if update is successful, false otherwise
1167     * {@hide}
1168     */
1169    public boolean archiveStoredConversation(long conversationId, boolean archived) {
1170        try {
1171            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1172            if (iMms != null) {
1173                return iMms.archiveStoredConversation(ActivityThread.currentPackageName(),
1174                        conversationId, archived);
1175            }
1176        } catch (RemoteException ex) {
1177            // ignore it
1178        }
1179        return false;
1180    }
1181
1182    /**
1183     * Add a text message draft to system SMS store
1184     *
1185     * Only default SMS apps can add SMS draft
1186     *
1187     * @param address the destination address of message
1188     * @param text the body of the message to send
1189     * @return the URI of the stored draft message
1190     * {@hide}
1191     */
1192    public Uri addTextMessageDraft(String address, String text) {
1193        try {
1194            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1195            if (iMms != null) {
1196                return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text);
1197            }
1198        } catch (RemoteException ex) {
1199            // ignore it
1200        }
1201        return null;
1202    }
1203
1204    /**
1205     * Add a multimedia message draft to system MMS store
1206     *
1207     * Only default SMS apps can add MMS draft
1208     *
1209     * @param contentUri the content uri from which to read the PDU data of the draft MMS
1210     * @return the URI of the stored draft message
1211     * @throws IllegalArgumentException if pdu is empty
1212     * {@hide}
1213     */
1214    public Uri addMultimediaMessageDraft(Uri contentUri) {
1215        if (contentUri == null) {
1216            throw new IllegalArgumentException("Uri contentUri null");
1217        }
1218        try {
1219            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1220            if (iMms != null) {
1221                return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(),
1222                        contentUri);
1223            }
1224        } catch (RemoteException ex) {
1225            // ignore it
1226        }
1227        return null;
1228    }
1229
1230    /**
1231     * Send a system stored text message.
1232     *
1233     * You can only send a failed text message or a draft text message.
1234     *
1235     * @param messageUri the URI of the stored message
1236     * @param scAddress is the service center address or null to use the current default SMSC
1237     * @param sentIntent if not NULL this <code>PendingIntent</code> is
1238     *  broadcast when the message is successfully sent, or failed.
1239     *  The result code will be <code>Activity.RESULT_OK</code> for success,
1240     *  or one of these errors:<br>
1241     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
1242     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
1243     *  <code>RESULT_ERROR_NULL_PDU</code><br>
1244     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
1245     *  the extra "errorCode" containing a radio technology specific value,
1246     *  generally only useful for troubleshooting.<br>
1247     *  The per-application based SMS control checks sentIntent. If sentIntent
1248     *  is NULL the caller will be checked against all unknown applications,
1249     *  which cause smaller number of SMS to be sent in checking period.
1250     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
1251     *  broadcast when the message is delivered to the recipient.  The
1252     *  raw pdu of the status report is in the extended data ("pdu").
1253     *
1254     * @throws IllegalArgumentException if messageUri is empty
1255     * {@hide}
1256     */
1257    public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent,
1258            PendingIntent deliveryIntent) {
1259        if (messageUri == null) {
1260            throw new IllegalArgumentException("Empty message URI");
1261        }
1262        try {
1263            ISms iccISms = getISmsServiceOrThrow();
1264            iccISms.sendStoredText(getSubId(), ActivityThread.currentPackageName(), messageUri,
1265                    scAddress, sentIntent, deliveryIntent);
1266        } catch (RemoteException ex) {
1267            // ignore it
1268        }
1269    }
1270
1271    /**
1272     * Send a system stored multi-part text message.
1273     *
1274     * You can only send a failed text message or a draft text message.
1275     * The provided <code>PendingIntent</code> lists should match the part number of the
1276     * divided text of the stored message by using <code>divideMessage</code>
1277     *
1278     * @param messageUri the URI of the stored message
1279     * @param scAddress is the service center address or null to use
1280     *   the current default SMSC
1281     * @param sentIntents if not null, an <code>ArrayList</code> of
1282     *   <code>PendingIntent</code>s (one for each message part) that is
1283     *   broadcast when the corresponding message part has been sent.
1284     *   The result code will be <code>Activity.RESULT_OK</code> for success,
1285     *   or one of these errors:<br>
1286     *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
1287     *   <code>RESULT_ERROR_RADIO_OFF</code><br>
1288     *   <code>RESULT_ERROR_NULL_PDU</code><br>
1289     *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
1290     *   the extra "errorCode" containing a radio technology specific value,
1291     *   generally only useful for troubleshooting.<br>
1292     *   The per-application based SMS control checks sentIntent. If sentIntent
1293     *   is NULL the caller will be checked against all unknown applications,
1294     *   which cause smaller number of SMS to be sent in checking period.
1295     * @param deliveryIntents if not null, an <code>ArrayList</code> of
1296     *   <code>PendingIntent</code>s (one for each message part) that is
1297     *   broadcast when the corresponding message part has been delivered
1298     *   to the recipient.  The raw pdu of the status report is in the
1299     *   extended data ("pdu").
1300     *
1301     * @throws IllegalArgumentException if messageUri is empty
1302     * {@hide}
1303     */
1304    public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress,
1305            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
1306        if (messageUri == null) {
1307            throw new IllegalArgumentException("Empty message URI");
1308        }
1309        try {
1310            ISms iccISms = getISmsServiceOrThrow();
1311            iccISms.sendStoredMultipartText(getSubId(), ActivityThread.currentPackageName(), messageUri,
1312                    scAddress, sentIntents, deliveryIntents);
1313        } catch (RemoteException ex) {
1314            // ignore it
1315        }
1316    }
1317
1318    /**
1319     * Send a system stored MMS message
1320     *
1321     * This is used for sending a previously sent, but failed-to-send, message or
1322     * for sending a text message that has been stored as a draft.
1323     *
1324     * @param messageUri the URI of the stored message
1325     * @param configOverrides the carrier-specific messaging configuration values to override for
1326     *  sending the message.
1327     * @param sentIntent if not NULL this <code>PendingIntent</code> is
1328     *  broadcast when the message is successfully sent, or failed
1329     * @throws IllegalArgumentException if messageUri is empty
1330     * {@hide}
1331     */
1332    public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides,
1333            PendingIntent sentIntent) {
1334        if (messageUri == null) {
1335            throw new IllegalArgumentException("Empty message URI");
1336        }
1337        try {
1338            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1339            if (iMms != null) {
1340                iMms.sendStoredMessage(getSubId(), ActivityThread.currentPackageName(), messageUri,
1341                        configOverrides, sentIntent);
1342            }
1343        } catch (RemoteException ex) {
1344            // ignore it
1345        }
1346    }
1347
1348    /**
1349     * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system
1350     *
1351     * When this flag is on, all SMS/MMS sent/received are stored by system automatically
1352     * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
1353     * automatically
1354     *
1355     * This flag can only be changed by default SMS apps
1356     *
1357     * @param enabled Whether to enable message auto persisting
1358     * {@hide}
1359     */
1360    public void setAutoPersisting(boolean enabled) {
1361        try {
1362            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1363            if (iMms != null) {
1364                iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled);
1365            }
1366        } catch (RemoteException ex) {
1367            // ignore it
1368        }
1369    }
1370
1371    /**
1372     * Get the value of the flag to automatically write sent/received SMS/MMS messages into system
1373     *
1374     * When this flag is on, all SMS/MMS sent/received are stored by system automatically
1375     * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
1376     * automatically
1377     *
1378     * @return the current value of the auto persist flag
1379     * {@hide}
1380     */
1381    public boolean getAutoPersisting() {
1382        try {
1383            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1384            if (iMms != null) {
1385                return iMms.getAutoPersisting();
1386            }
1387        } catch (RemoteException ex) {
1388            // ignore it
1389        }
1390        return false;
1391    }
1392
1393    /**
1394     * Get carrier-dependent configuration values.
1395     *
1396     * @return bundle key/values pairs of configuration values
1397     */
1398    public Bundle getCarrierConfigValues() {
1399        try {
1400            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1401            if (iMms != null) {
1402                return iMms.getCarrierConfigValues(getSubId());
1403            }
1404        } catch (RemoteException ex) {
1405            // ignore it
1406        }
1407        return null;
1408    }
1409
1410}
1411