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