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