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