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