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