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