SmsManager.java revision 7320aa58e7fcbe113ec85e6ae7d41858af2e3270
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.os.RemoteException;
22import android.os.ServiceManager;
23import android.text.TextUtils;
24import android.util.Log;
25
26import com.android.internal.telephony.ISms;
27import com.android.internal.telephony.SmsRawData;
28import com.android.internal.telephony.IMms;
29import com.android.internal.telephony.uicc.IccConstants;
30
31import java.util.ArrayList;
32import java.util.Arrays;
33import java.util.List;
34
35/*
36 * TODO(code review): Curious question... Why are a lot of these
37 * methods not declared as static, since they do not seem to require
38 * any local object state?  Presumably this cannot be changed without
39 * interfering with the API...
40 */
41
42/**
43 * Manages SMS operations such as sending data, text, and pdu SMS messages.
44 * Get this object by calling the static method {@link #getDefault()}.
45 *
46 * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19)
47 * and higher, see {@link android.provider.Telephony}.
48 */
49public final class SmsManager {
50    /** Singleton object constructed during class initialization. */
51    private static final SmsManager sInstance = new SmsManager();
52    private static final int DEFAULT_SUB = 0;
53
54    /**
55     * Send a text based SMS.
56     *
57     * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
58     * {@link android.Manifest.permission#SEND_SMS} permission.</p>
59     *
60     * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
61     * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
62     * writes messages sent using this method to the SMS Provider (the default SMS app is always
63     * responsible for writing its sent messages to the SMS Provider). For information about
64     * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
65     *
66     *
67     * @param destinationAddress the address to send the message to
68     * @param scAddress is the service center address or null to use
69     *  the current default SMSC
70     * @param text the body of the message to send
71     * @param sentIntent if not NULL this <code>PendingIntent</code> is
72     *  broadcast when the message is successfully sent, or failed.
73     *  The result code will be <code>Activity.RESULT_OK</code> for success,
74     *  or one of these errors:<br>
75     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
76     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
77     *  <code>RESULT_ERROR_NULL_PDU</code><br>
78     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
79     *  the extra "errorCode" containing a radio technology specific value,
80     *  generally only useful for troubleshooting.<br>
81     *  The per-application based SMS control checks sentIntent. If sentIntent
82     *  is NULL the caller will be checked against all unknown applications,
83     *  which cause smaller number of SMS to be sent in checking period.
84     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
85     *  broadcast when the message is delivered to the recipient.  The
86     *  raw pdu of the status report is in the extended data ("pdu").
87     *
88     * @throws IllegalArgumentException if destinationAddress or text are empty
89     */
90    public void sendTextMessage(
91            String destinationAddress, String scAddress, String text,
92            PendingIntent sentIntent, PendingIntent deliveryIntent) {
93        sendTextMessage(getPreferredSmsSubscription(), destinationAddress, scAddress, text,
94           sentIntent, deliveryIntent);
95    }
96
97    /**
98     * Send a text based SMS.
99     *
100     * @param destinationAddress the address to send the message to
101     * @param scAddress is the service center address or null to use
102     *  the current default SMSC
103     * @param text the body of the message to send
104     * @param sentIntent if not NULL this <code>PendingIntent</code> is
105     *  broadcast when the message is successfully sent, or failed.
106     *  The result code will be <code>Activity.RESULT_OK</code> for success,
107     *  or one of these errors:<br>
108     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
109     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
110     *  <code>RESULT_ERROR_NULL_PDU</code><br>
111     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
112     *  the extra "errorCode" containing a radio technology specific value,
113     *  generally only useful for troubleshooting.<br>
114     *  The per-application based SMS control checks sentIntent. If sentIntent
115     *  is NULL the caller will be checked against all unknown applications,
116     *  which cause smaller number of SMS to be sent in checking period.
117     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
118     *  broadcast when the message is delivered to the recipient.  The
119     *  raw pdu of the status report is in the extended data ("pdu").
120     * @param subId on which the SMS has to be sent.
121     *
122     * @throws IllegalArgumentException if destinationAddress or text are empty
123     *
124     */
125    /** @hide */
126    public void sendTextMessage(
127            long subId, String destinationAddress, String scAddress, String text,
128            PendingIntent sentIntent, PendingIntent deliveryIntent) {
129        if (TextUtils.isEmpty(destinationAddress)) {
130            throw new IllegalArgumentException("Invalid destinationAddress");
131        }
132
133        if (TextUtils.isEmpty(text)) {
134            throw new IllegalArgumentException("Invalid message body");
135        }
136
137        try {
138            ISms iccISms = getISmsServiceOrThrow();
139            iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress,
140                    scAddress, text, sentIntent, deliveryIntent);
141        } catch (RemoteException ex) {
142            // ignore it
143        }
144    }
145
146    /**
147     * TODO Move this to new CarrierSmsManager class.
148     *
149     * Inject an SMS PDU into the android application framework.
150     *
151     * @param pdu is the byte array of pdu to be injected into android application framework
152     * @param format is the format of SMS pdu (3gpp or 3gpp2)
153     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
154     *  broadcast when the message is successfully received by the
155     *  android application framework. This intent is broadcasted at
156     *  the same time an SMS received from radio is acknowledged back.
157     *
158     *  @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2.
159     *  {@hide}
160     */
161    public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
162        if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) {
163            // Format must be either 3gpp or 3gpp2.
164            throw new IllegalArgumentException(
165                    "Invalid pdu format. format must be either 3gpp or 3gpp2");
166        }
167        try {
168            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
169            if (iccISms != null) {
170                iccISms.injectSmsPdu(pdu, format, receivedIntent);
171            }
172        } catch (RemoteException ex) {
173          // ignore it
174        }
175    }
176
177    /**
178     * Divide a message text into several fragments, none bigger than
179     * the maximum SMS message size.
180     *
181     * @param text the original message.  Must not be null.
182     * @return an <code>ArrayList</code> of strings that, in order,
183     *   comprise the original message
184     *
185     * @throws IllegalArgumentException if text is null
186     */
187    public ArrayList<String> divideMessage(String text) {
188        if (null == text) {
189            throw new IllegalArgumentException("text is null");
190        }
191        return SmsMessage.fragmentText(text);
192    }
193
194    /**
195     * Send a multi-part text based SMS.  The callee should have already
196     * divided the message into correctly sized parts by calling
197     * <code>divideMessage</code>.
198     *
199     * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
200     * {@link android.Manifest.permission#SEND_SMS} permission.</p>
201     *
202     * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
203     * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
204     * writes messages sent using this method to the SMS Provider (the default SMS app is always
205     * responsible for writing its sent messages to the SMS Provider). For information about
206     * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
207     *
208     * @param destinationAddress the address to send the message to
209     * @param scAddress is the service center address or null to use
210     *   the current default SMSC
211     * @param parts an <code>ArrayList</code> of strings that, in order,
212     *   comprise the original message
213     * @param sentIntents if not null, an <code>ArrayList</code> of
214     *   <code>PendingIntent</code>s (one for each message part) that is
215     *   broadcast when the corresponding message part has been sent.
216     *   The result code will be <code>Activity.RESULT_OK</code> for success,
217     *   or one of these errors:<br>
218     *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
219     *   <code>RESULT_ERROR_RADIO_OFF</code><br>
220     *   <code>RESULT_ERROR_NULL_PDU</code><br>
221     *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
222     *   the extra "errorCode" containing a radio technology specific value,
223     *   generally only useful for troubleshooting.<br>
224     *   The per-application based SMS control checks sentIntent. If sentIntent
225     *   is NULL the caller will be checked against all unknown applications,
226     *   which cause smaller number of SMS to be sent in checking period.
227     * @param deliveryIntents if not null, an <code>ArrayList</code> of
228     *   <code>PendingIntent</code>s (one for each message part) that is
229     *   broadcast when the corresponding message part has been delivered
230     *   to the recipient.  The raw pdu of the status report is in the
231     *   extended data ("pdu").
232     *
233     * @throws IllegalArgumentException if destinationAddress or data are empty
234     */
235    public void sendMultipartTextMessage(
236            String destinationAddress, String scAddress, ArrayList<String> parts,
237            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
238        sendMultipartTextMessage(getPreferredSmsSubscription(), destinationAddress, scAddress, parts, sentIntents,
239            deliveryIntents);
240    }
241
242    /**
243     * Send a multi-part text based SMS.  The callee should have already
244     * divided the message into correctly sized parts by calling
245     * <code>divideMessage</code>.
246     *
247     * @param destinationAddress the address to send the message to
248     * @param scAddress is the service center address or null to use
249     *   the current default SMSC
250     * @param parts an <code>ArrayList</code> of strings that, in order,
251     *   comprise the original message
252     * @param sentIntents if not null, an <code>ArrayList</code> of
253     *   <code>PendingIntent</code>s (one for each message part) that is
254     *   broadcast when the corresponding message part has been sent.
255     *   The result code will be <code>Activity.RESULT_OK</code> for success,
256     *   or one of these errors:<br>
257     *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
258     *   <code>RESULT_ERROR_RADIO_OFF</code><br>
259     *   <code>RESULT_ERROR_NULL_PDU</code><br>
260     *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
261     *   the extra "errorCode" containing a radio technology specific value,
262     *   generally only useful for troubleshooting.<br>
263     *   The per-application based SMS control checks sentIntent. If sentIntent
264     *   is NULL the caller will be checked against all unknown applications,
265     *   which cause smaller number of SMS to be sent in checking period.
266     * @param deliveryIntents if not null, an <code>ArrayList</code> of
267     *   <code>PendingIntent</code>s (one for each message part) that is
268     *   broadcast when the corresponding message part has been delivered
269     *   to the recipient.  The raw pdu of the status report is in the
270     *   extended data ("pdu").
271     *   @param subId on which the SMS has to be sent.
272     *
273     * @throws IllegalArgumentException if destinationAddress or data are empty
274     */
275    /** @hide */
276    public void sendMultipartTextMessage(long subId, String destinationAddress, String scAddress,
277            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
278            ArrayList<PendingIntent> deliveryIntents) {
279        if (TextUtils.isEmpty(destinationAddress)) {
280            throw new IllegalArgumentException("Invalid destinationAddress");
281        }
282        if (parts == null || parts.size() < 1) {
283            throw new IllegalArgumentException("Invalid message body");
284        }
285
286        if (parts.size() > 1) {
287            try {
288                ISms iccISms = getISmsServiceOrThrow();
289                iccISms.sendMultipartText(ActivityThread.currentPackageName(),
290                        destinationAddress, scAddress, parts,
291                        sentIntents, deliveryIntents);
292            } catch (RemoteException ex) {
293                // ignore it
294            }
295        } else {
296            PendingIntent sentIntent = null;
297            PendingIntent deliveryIntent = null;
298            if (sentIntents != null && sentIntents.size() > 0) {
299                sentIntent = sentIntents.get(0);
300            }
301            if (deliveryIntents != null && deliveryIntents.size() > 0) {
302                deliveryIntent = deliveryIntents.get(0);
303            }
304            sendTextMessage(destinationAddress, scAddress, parts.get(0),
305                    sentIntent, deliveryIntent);
306        }
307    }
308
309    /**
310     * Send a data based SMS to a specific application port.
311     *
312     * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
313     * {@link android.Manifest.permission#SEND_SMS} permission.</p>
314     *
315     * @param destinationAddress the address to send the message to
316     * @param scAddress is the service center address or null to use
317     *  the current default SMSC
318     * @param destinationPort the port to deliver the message to
319     * @param data the body of the message to send
320     * @param sentIntent if not NULL this <code>PendingIntent</code> is
321     *  broadcast when the message is successfully sent, or failed.
322     *  The result code will be <code>Activity.RESULT_OK</code> for success,
323     *  or one of these errors:<br>
324     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
325     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
326     *  <code>RESULT_ERROR_NULL_PDU</code><br>
327     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
328     *  the extra "errorCode" containing a radio technology specific value,
329     *  generally only useful for troubleshooting.<br>
330     *  The per-application based SMS control checks sentIntent. If sentIntent
331     *  is NULL the caller will be checked against all unknown applications,
332     *  which cause smaller number of SMS to be sent in checking period.
333     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
334     *  broadcast when the message is delivered to the recipient.  The
335     *  raw pdu of the status report is in the extended data ("pdu").
336     *
337     * @throws IllegalArgumentException if destinationAddress or data are empty
338     */
339    public void sendDataMessage(
340            String destinationAddress, String scAddress, short destinationPort,
341            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
342        sendDataMessage(getPreferredSmsSubscription(),
343            destinationAddress, scAddress, destinationPort,
344            data, sentIntent, deliveryIntent);
345    }
346
347    /**
348     * Send a data based SMS to a specific application port.
349     *
350     * @param destinationAddress the address to send the message to
351     * @param scAddress is the service center address or null to use
352     *  the current default SMSC
353     * @param destinationPort the port to deliver the message to
354     * @param data the body of the message to send
355     * @param sentIntent if not NULL this <code>PendingIntent</code> is
356     *  broadcast when the message is successfully sent, or failed.
357     *  The result code will be <code>Activity.RESULT_OK</code> for success,
358     *  or one of these errors:<br>
359     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
360     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
361     *  <code>RESULT_ERROR_NULL_PDU</code><br>
362     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
363     *  the extra "errorCode" containing a radio technology specific value,
364     *  generally only useful for troubleshooting.<br>
365     *  The per-application based SMS control checks sentIntent. If sentIntent
366     *  is NULL the caller will be checked against all unknown applications,
367     *  which cause smaller number of SMS to be sent in checking period.
368     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
369     *  broadcast when the message is delivered to the recipient.  The
370     *  raw pdu of the status report is in the extended data ("pdu").
371     *  @param subId on which the SMS has to be sent.
372     *
373     * @throws IllegalArgumentException if destinationAddress or data are empty
374     */
375    /** @hide */
376    public void sendDataMessage(long subId,
377            String destinationAddress, String scAddress, short destinationPort,
378            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
379        if (TextUtils.isEmpty(destinationAddress)) {
380            throw new IllegalArgumentException("Invalid destinationAddress");
381        }
382
383        if (data == null || data.length == 0) {
384            throw new IllegalArgumentException("Invalid message data");
385        }
386
387        try {
388            ISms iccISms = getISmsServiceOrThrow();
389            iccISms.sendData(ActivityThread.currentPackageName(),
390                    destinationAddress, scAddress, destinationPort & 0xFFFF,
391                    data, sentIntent, deliveryIntent);
392        } catch (RemoteException ex) {
393            // ignore it
394        }
395    }
396
397    /**
398     * Get the default instance of the SmsManager
399     *
400     * @return the default instance of the SmsManager
401     */
402    public static SmsManager getDefault() {
403        return sInstance;
404    }
405
406    private SmsManager() {
407        //nothing
408    }
409
410    /**
411     * Returns the ISms service, or throws an UnsupportedOperationException if
412     * the service does not exist.
413     */
414    private static ISms getISmsServiceOrThrow() {
415        ISms iccISms = getISmsService();
416        if (iccISms == null) {
417            throw new UnsupportedOperationException("Sms is not supported");
418        }
419        return iccISms;
420    }
421
422    private static ISms getISmsService() {
423        return ISms.Stub.asInterface(ServiceManager.getService("isms"));
424    }
425
426    /**
427     * Copy a raw SMS PDU to the ICC.
428     * ICC (Integrated Circuit Card) is the card of the device.
429     * For example, this can be the SIM or USIM for GSM.
430     *
431     * @param smsc the SMSC for this message, or NULL for the default SMSC
432     * @param pdu the raw PDU to store
433     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
434     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
435     * @return true for success
436     *
437     * @throws IllegalArgumentException if pdu is NULL
438     * {@hide}
439     */
440    public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
441        return copyMessageToIcc(getPreferredSmsSubscription(), smsc, pdu, status);
442    }
443
444    /**
445     * Copy a raw SMS PDU to the ICC on  subId.
446     * ICC (Integrated Circuit Card) is the card of the device.
447     * For example, this can be the SIM or USIM for GSM.
448     *
449     * @param smsc the SMSC for this message, or NULL for the default SMSC
450     * @param pdu the raw PDU to store
451     * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
452     *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
453     * @param subId from which SMS has to be copied.
454     * @return true for success
455     *
456     * @throws IllegalArgumentException if pdu is NULL
457     * {@hide}
458     */
459
460    /** @hide */
461    public boolean copyMessageToIcc(long subId, byte[] smsc, byte[] pdu, int status) {
462        boolean success = false;
463
464        if (null == pdu) {
465            throw new IllegalArgumentException("pdu is NULL");
466        }
467        try {
468            ISms iccISms = getISmsService();
469            if (iccISms != null) {
470                success = iccISms.copyMessageToIccEf(ActivityThread.currentPackageName(),
471                        status, pdu, smsc);
472            }
473        } catch (RemoteException ex) {
474            // ignore it
475        }
476
477        return success;
478    }
479
480    /**
481     * Delete the specified message from the ICC.
482     * ICC (Integrated Circuit Card) is the card of the device.
483     * For example, this can be the SIM or USIM for GSM.
484     *
485     * @param messageIndex is the record index of the message on ICC
486     * @return true for success
487     *
488     * {@hide}
489     */
490    public boolean
491    deleteMessageFromIcc(int messageIndex) {
492        return deleteMessageFromIcc(getPreferredSmsSubscription(), messageIndex);
493    }
494
495    /**
496     * Delete the specified message from the ICC on  subId.
497     * ICC (Integrated Circuit Card) is the card of the device.
498     * For example, this can be the SIM or USIM for GSM.
499     *
500     * @param messageIndex is the record index of the message on ICC
501     * @param subId from which SMS has to be deleted.
502     * @return true for success
503     *
504     */
505    /** @hide */
506    public boolean
507    deleteMessageFromIcc(long subId, int messageIndex) {
508        boolean success = false;
509        byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1];
510        Arrays.fill(pdu, (byte)0xff);
511
512        try {
513            ISms iccISms = getISmsService();
514            if (iccISms != null) {
515                success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(),
516                        messageIndex, STATUS_ON_ICC_FREE, pdu);
517            }
518        } catch (RemoteException ex) {
519            // ignore it
520        }
521
522        return success;
523    }
524
525    /**
526     * Update the specified message on the ICC.
527     * ICC (Integrated Circuit Card) is the card of the device.
528     * For example, this can be the SIM or USIM for GSM.
529     *
530     * @param messageIndex record index of message to update
531     * @param newStatus new message status (STATUS_ON_ICC_READ,
532     *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
533     *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
534     * @param pdu the raw PDU to store
535     * @return true for success
536     *
537     * {@hide}
538     */
539    public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
540        return updateMessageOnIcc(getPreferredSmsSubscription(), messageIndex, newStatus, pdu);
541    }
542
543    /**
544     * Update the specified message on the ICC on  subId.
545     * ICC (Integrated Circuit Card) is the card of the device.
546     * For example, this can be the SIM or USIM for GSM.
547     *
548     * @param messageIndex record index of message to update
549     * @param newStatus new message status (STATUS_ON_ICC_READ,
550     *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
551     *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
552     * @param pdu the raw PDU to store
553     * @param subId on which the SMS had to be updated.
554     * @return true for success
555     *
556     */
557    /** @hide */
558    public boolean updateMessageOnIcc(long subId, int messageIndex, int newStatus,
559                           byte[] pdu)   {
560        boolean success = false;
561
562        try {
563            ISms iccISms = getISmsService();
564            if (iccISms != null) {
565                success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(),
566                        messageIndex, newStatus, pdu);
567            }
568        } catch (RemoteException ex) {
569            // ignore it
570        }
571
572        return success;
573    }
574
575    /**
576     * Retrieves all messages currently stored on ICC.
577     * ICC (Integrated Circuit Card) is the card of the device.
578     * For example, this can be the SIM or USIM for GSM.
579     *
580     * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
581     *
582     * {@hide}
583     */
584    public static ArrayList<SmsMessage> getAllMessagesFromIcc() {
585        return getAllMessagesFromIcc(getPreferredSmsSubscription());
586    }
587
588    /**
589     * Retrieves all messages currently stored on ICC on the default
590     * subId.
591     * ICC (Integrated Circuit Card) is the card of the device.
592     * For example, this can be the SIM or USIM for GSM.
593     *
594     * @param subId from which the messages had to be retrieved.
595     * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
596     *
597     */
598    /** @hide */
599    public static ArrayList<SmsMessage> getAllMessagesFromIcc(long subId) {
600        List<SmsRawData> records = null;
601
602        try {
603            ISms iccISms = getISmsService();
604            if (iccISms != null) {
605                records = iccISms.getAllMessagesFromIccEf(ActivityThread.currentPackageName());
606            }
607        } catch (RemoteException ex) {
608            // ignore it
609        }
610
611        return createMessageListFromRawRecords(records);
612    }
613
614    /**
615     * Enable reception of cell broadcast (SMS-CB) messages with the given
616     * message identifier. Note that if two different clients enable the same
617     * message identifier, they must both disable it for the device to stop
618     * receiving those messages. All received messages will be broadcast in an
619     * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
620     * Note: This call is blocking, callers may want to avoid calling it from
621     * the main thread of an application.
622     *
623     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
624     * or C.R1001-G (3GPP2)
625     * @return true if successful, false otherwise
626     * @see #disableCellBroadcast(int)
627     *
628     * {@hide}
629     */
630    public boolean enableCellBroadcast(int messageIdentifier) {
631        return enableCellBroadcast(getPreferredSmsSubscription(), messageIdentifier);
632    }
633
634    /**
635     * Enable reception of cell broadcast (SMS-CB) messages with the given
636     * message identifier on a particular subId.
637     * Note that if two different clients enable the same
638     * message identifier, they must both disable it for the device to stop
639     * receiving those messages. All received messages will be broadcast in an
640     * intent with the action "android.provider.telephony.SMS_CB_RECEIVED".
641     * Note: This call is blocking, callers may want to avoid calling it from
642     * the main thread of an application.
643     *
644     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
645     * or C.R1001-G (3GPP2)
646     * @param subId for which the broadcast has to be enabled
647     * @return true if successful, false otherwise
648     * @see #disableCellBroadcast(int)
649     *
650     */
651     /** @hide */
652    public boolean enableCellBroadcast(long subId, int messageIdentifier) {
653        boolean success = false;
654
655        try {
656            ISms iccISms = getISmsService();
657            if (iccISms != null) {
658                success = iccISms.enableCellBroadcast(messageIdentifier);
659            }
660        } catch (RemoteException ex) {
661            // ignore it
662        }
663
664        return success;
665    }
666
667    /**
668     * Disable reception of cell broadcast (SMS-CB) messages with the given
669     * message identifier. Note that if two different clients enable the same
670     * message identifier, they must both disable it for the device to stop
671     * receiving those messages.
672     * Note: This call is blocking, callers may want to avoid calling it from
673     * the main thread of an application.
674     *
675     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
676     * or C.R1001-G (3GPP2)
677     * @return true if successful, false otherwise
678     *
679     * @see #enableCellBroadcast(int)
680     *
681     * {@hide}
682     */
683    public boolean disableCellBroadcast(int messageIdentifier) {
684        return disableCellBroadcast(getPreferredSmsSubscription(), messageIdentifier);
685    }
686
687    /**
688     * Disable reception of cell broadcast (SMS-CB) messages with the given
689     * message identifier on a particular subId.
690     * Note that if two different clients enable the same
691     * message identifier, they must both disable it for the device to stop
692     * receiving those messages.
693     * Note: This call is blocking, callers may want to avoid calling it from
694     * the main thread of an application.
695     *
696     * @param messageIdentifier Message identifier as specified in TS 23.041
697     * @param subId for which the broadcast has to be disabled
698     * @return true if successful, false otherwise
699     *
700     * @see #enableCellBroadcast(int)
701     *
702     */
703    /** @hide */
704    public boolean disableCellBroadcast(long subId, int messageIdentifier) {
705        boolean success = false;
706
707        try {
708            ISms iccISms = getISmsService();
709            if (iccISms != null) {
710                success = iccISms.disableCellBroadcast(messageIdentifier);
711            }
712        } catch (RemoteException ex) {
713            // ignore it
714        }
715
716        return success;
717    }
718
719    /**
720     * Enable reception of cell broadcast (SMS-CB) messages with the given
721     * message identifier range. Note that if two different clients enable the same
722     * message identifier, they must both disable it for the device to stop
723     * receiving those messages. All received messages will be broadcast in an
724     * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
725     * Note: This call is blocking, callers may want to avoid calling it from
726     * the main thread of an application.
727     *
728     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
729     * or C.R1001-G (3GPP2)
730     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
731     * or C.R1001-G (3GPP2)
732     * @return true if successful, false otherwise
733     * @see #disableCellBroadcastRange(int, int)
734     *
735     * @throws IllegalArgumentException if endMessageId < startMessageId
736     * {@hide}
737     */
738    public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) {
739        return enableCellBroadcastRange(getPreferredSmsSubscription(), startMessageId,
740                endMessageId);
741    }
742
743    /**
744     * Enable reception of cell broadcast (SMS-CB) messages with the given
745     * message identifier range on a particular subId.
746     * Note that if two different clients enable the same
747     * message identifier, they must both disable it for the device to stop
748     * receiving those messages. All received messages will be broadcast in an
749     * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
750     * Note: This call is blocking, callers may want to avoid calling it from
751     * the main thread of an application.
752     *
753     * @param startMessageId first message identifier as specified in TS 23.041
754     * @param endMessageId last message identifier as specified in TS 23.041
755     * @return true if successful, false otherwise
756     * @see #disableCellBroadcastRange(int, int)
757     * @throws IllegalArgumentException if endMessageId < startMessageId
758     *
759     */
760    /** @hide */
761    public boolean enableCellBroadcastRange(long subId, int startMessageId,
762            int endMessageId) {
763        boolean success = false;
764
765        if (endMessageId < startMessageId) {
766            throw new IllegalArgumentException("endMessageId < startMessageId");
767        }
768        try {
769            ISms iccISms = getISmsService();
770            if (iccISms != null) {
771                success = iccISms.enableCellBroadcastRange(startMessageId, endMessageId);
772            }
773        } catch (RemoteException ex) {
774            // ignore it
775        }
776
777        return success;
778    }
779
780    /**
781     * Disable reception of cell broadcast (SMS-CB) messages with the given
782     * message identifier range. Note that if two different clients enable the same
783     * message identifier, they must both disable it for the device to stop
784     * receiving those messages.
785     * Note: This call is blocking, callers may want to avoid calling it from
786     * the main thread of an application.
787     *
788     * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
789     * or C.R1001-G (3GPP2)
790     * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
791     * or C.R1001-G (3GPP2)
792     * @return true if successful, false otherwise
793     *
794     * @see #enableCellBroadcastRange(int, int)
795     *
796     * @throws IllegalArgumentException if endMessageId < startMessageId
797     * {@hide}
798     */
799    public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) {
800        return disableCellBroadcastRange(getPreferredSmsSubscription(), startMessageId,
801                endMessageId);
802    }
803
804    /**
805     * Disable reception of cdma broadcast messages with the given
806     * message identifier range on a particular subId.
807     * Note that if two different clients enable the same
808     * message identifier range, they must both disable it for the device to stop
809     * receiving those messages.
810     * Note: This call is blocking, callers may want to avoid calling it from
811     * the main thread of an application.
812     *
813     * @param startMessageId first message identifier as specified in TS 23.041
814     * @param endMessageId last message identifier as specified in TS 23.041
815     * @return true if successful, false otherwise
816     *
817     * @see #enableCellBroadcastRange(int, int)
818     * @throws IllegalArgumentException if endMessageId < startMessageId
819     *
820     */
821    /** @hide */
822    public boolean disableCellBroadcastRange(long subId, int startMessageId,
823            int endMessageId) {
824        boolean success = false;
825
826        if (endMessageId < startMessageId) {
827            throw new IllegalArgumentException("endMessageId < startMessageId");
828        }
829        try {
830            ISms iccISms = getISmsService();
831            if (iccISms != null) {
832                success = iccISms.disableCellBroadcastRange(startMessageId, endMessageId);
833            }
834        } catch (RemoteException ex) {
835            // ignore it
836        }
837
838        return success;
839    }
840
841    /**
842     * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
843     * records returned by <code>getAllMessagesFromIcc()</code>
844     *
845     * @param records SMS EF records, returned by
846     *   <code>getAllMessagesFromIcc</code>
847     * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
848     */
849    private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
850        ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
851        if (records != null) {
852            int count = records.size();
853            for (int i = 0; i < count; i++) {
854                SmsRawData data = records.get(i);
855                // List contains all records, including "free" records (null)
856                if (data != null) {
857                    SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
858                    if (sms != null) {
859                        messages.add(sms);
860                    }
861                }
862            }
863        }
864        return messages;
865    }
866
867    /**
868     * SMS over IMS is supported if IMS is registered and SMS is supported
869     * on IMS.
870     *
871     * @return true if SMS over IMS is supported, false otherwise
872     *
873     * @see #getImsSmsFormat()
874     *
875     * @hide
876     */
877    boolean isImsSmsSupported() {
878        return isImsSmsSupported(getPreferredSmsSubscription());
879    }
880
881    /** @hide */
882    boolean isImsSmsSupported(long subId) {
883        boolean boSupported = false;
884        try {
885            ISms iccISms = getISmsService();
886            if (iccISms != null) {
887                boSupported = iccISms.isImsSmsSupported();
888            }
889        } catch (RemoteException ex) {
890            // ignore it
891        }
892        return boSupported;
893    }
894
895    /**
896     * Gets SMS format supported on IMS.  SMS over IMS format is
897     * either 3GPP or 3GPP2.
898     *
899     * @return SmsMessage.FORMAT_3GPP,
900     *         SmsMessage.FORMAT_3GPP2
901     *      or SmsMessage.FORMAT_UNKNOWN
902     *
903     * @see #isImsSmsSupported()
904     *
905     * @hide
906     */
907    String getImsSmsFormat() {
908        return getImsSmsFormat(getPreferredSmsSubscription());
909    }
910
911    /** @hide */
912    String getImsSmsFormat(long subId) {
913        String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
914        try {
915            ISms iccISms = getISmsService();
916            if (iccISms != null) {
917                format = iccISms.getImsSmsFormat();
918            }
919        } catch (RemoteException ex) {
920            // ignore it
921        }
922        return format;
923    }
924
925    /**
926     * Get the preferred sms subId
927     *
928     * @return the preferred subId
929     * @hide
930     */
931    public static long getPreferredSmsSubscription() {
932        ISms iccISms = null;
933        try {
934            iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
935            return (long) iccISms.getPreferredSmsSubscription();
936        } catch (RemoteException ex) {
937            return DEFAULT_SUB;
938        } catch (NullPointerException ex) {
939            return DEFAULT_SUB;
940        }
941    }
942
943    /**
944     * Get SMS prompt property,  enabled or not
945     *
946     * @return true if enabled, false otherwise
947     * @hide
948     */
949    public boolean isSMSPromptEnabled() {
950        ISms iccISms = null;
951        try {
952            iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
953            return iccISms.isSMSPromptEnabled();
954        } catch (RemoteException ex) {
955            return false;
956        } catch (NullPointerException ex) {
957            return false;
958        }
959    }
960
961    // see SmsMessage.getStatusOnIcc
962
963    /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
964    static public final int STATUS_ON_ICC_FREE      = 0;
965
966    /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
967    static public final int STATUS_ON_ICC_READ      = 1;
968
969    /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
970    static public final int STATUS_ON_ICC_UNREAD    = 3;
971
972    /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
973    static public final int STATUS_ON_ICC_SENT      = 5;
974
975    /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
976    static public final int STATUS_ON_ICC_UNSENT    = 7;
977
978    // SMS send failure result codes
979
980    /** Generic failure cause */
981    static public final int RESULT_ERROR_GENERIC_FAILURE    = 1;
982    /** Failed because radio was explicitly turned off */
983    static public final int RESULT_ERROR_RADIO_OFF          = 2;
984    /** Failed because no pdu provided */
985    static public final int RESULT_ERROR_NULL_PDU           = 3;
986    /** Failed because service is currently unavailable */
987    static public final int RESULT_ERROR_NO_SERVICE         = 4;
988    /** Failed because we reached the sending queue limit.  {@hide} */
989    static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
990    /** Failed because FDN is enabled. {@hide} */
991    static public final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
992
993    /**
994     * Send an MMS message
995     *
996     * @param pdu the MMS message encoded in standard MMS PDU format
997     * @param locationUrl the optional location url where message should be sent to
998     * @param sentIntent if not NULL this <code>PendingIntent</code> is
999     *  broadcast when the message is successfully sent, or failed
1000     * @hide
1001     */
1002    public void sendMultimediaMessage(byte[] pdu, String locationUrl, PendingIntent sentIntent) {
1003        if (pdu == null || pdu.length == 0) {
1004            throw new IllegalArgumentException("Empty or zero length PDU");
1005        }
1006        try {
1007            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1008            if (iMms == null) {
1009                return;
1010            }
1011            iMms.sendMessage(ActivityThread.currentPackageName(), pdu, locationUrl, sentIntent);
1012        } catch (RemoteException e) {
1013            // Ignore it
1014        }
1015    }
1016
1017    /**
1018     * Download an MMS message from carrier by a given location URL
1019     *
1020     * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
1021     *  from the MMS WAP push notification
1022     * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
1023     *  broadcast when the message is downloaded, or the download is failed
1024     * @hide
1025     */
1026    public void downloadMultimediaMessage(String locationUrl, PendingIntent downloadedIntent) {
1027        if (TextUtils.isEmpty(locationUrl)) {
1028            throw new IllegalArgumentException("Empty MMS location URL");
1029        }
1030        try {
1031            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
1032            if (iMms == null) {
1033                return;
1034            }
1035            iMms.downloadMessage(ActivityThread.currentPackageName(), locationUrl,
1036                    downloadedIntent);
1037        } catch (RemoteException e) {
1038            // Ignore it
1039        }
1040    }
1041
1042    // MMS send/download failure result codes
1043    /**@hide*/
1044    public static final int MMS_ERROR_UNSPECIFIED = 1;
1045    /**@hide*/
1046    public static final int MMS_ERROR_INVALID_APN = 2;
1047    /**@hide*/
1048    public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
1049    /**@hide*/
1050    public static final int MMS_ERROR_HTTP_FAILURE = 4;
1051
1052    // Intent extra name for result data
1053    /**@hide*/
1054    public static final String MMS_EXTRA_DATA = "data";
1055
1056}
1057