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