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