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