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