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