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