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