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