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