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