Home | History | Annotate | Download | only in telephony
      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 
     17 package android.telephony;
     18 
     19 import android.app.ActivityThread;
     20 import android.app.PendingIntent;
     21 import android.os.RemoteException;
     22 import android.os.ServiceManager;
     23 import android.text.TextUtils;
     24 
     25 import com.android.internal.telephony.ISms;
     26 import com.android.internal.telephony.SmsRawData;
     27 import com.android.internal.telephony.uicc.IccConstants;
     28 
     29 import java.util.ArrayList;
     30 import java.util.Arrays;
     31 import java.util.List;
     32 
     33 /*
     34  * TODO(code review): Curious question... Why are a lot of these
     35  * methods not declared as static, since they do not seem to require
     36  * any local object state?  Presumably this cannot be changed without
     37  * interfering with the API...
     38  */
     39 
     40 /**
     41  * Manages SMS operations such as sending data, text, and pdu SMS messages.
     42  * Get this object by calling the static method {@link #getDefault()}.
     43  *
     44  * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19)
     45  * and higher, see {@link android.provider.Telephony}.
     46  */
     47 public final class SmsManager {
     48     /** Singleton object constructed during class initialization. */
     49     private static final SmsManager sInstance = new SmsManager();
     50 
     51     /**
     52      * Send a text based SMS.
     53      *
     54      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
     55      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
     56      *
     57      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
     58      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
     59      * writes messages sent using this method to the SMS Provider (the default SMS app is always
     60      * responsible for writing its sent messages to the SMS Provider). For information about
     61      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
     62      *
     63      *
     64      * @param destinationAddress the address to send the message to
     65      * @param scAddress is the service center address or null to use
     66      *  the current default SMSC
     67      * @param text the body of the message to send
     68      * @param sentIntent if not NULL this <code>PendingIntent</code> is
     69      *  broadcast when the message is successfully sent, or failed.
     70      *  The result code will be <code>Activity.RESULT_OK</code> for success,
     71      *  or one of these errors:<br>
     72      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
     73      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
     74      *  <code>RESULT_ERROR_NULL_PDU</code><br>
     75      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
     76      *  the extra "errorCode" containing a radio technology specific value,
     77      *  generally only useful for troubleshooting.<br>
     78      *  The per-application based SMS control checks sentIntent. If sentIntent
     79      *  is NULL the caller will be checked against all unknown applications,
     80      *  which cause smaller number of SMS to be sent in checking period.
     81      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
     82      *  broadcast when the message is delivered to the recipient.  The
     83      *  raw pdu of the status report is in the extended data ("pdu").
     84      *
     85      * @throws IllegalArgumentException if destinationAddress or text are empty
     86      */
     87     public void sendTextMessage(
     88             String destinationAddress, String scAddress, String text,
     89             PendingIntent sentIntent, PendingIntent deliveryIntent) {
     90         if (TextUtils.isEmpty(destinationAddress)) {
     91             throw new IllegalArgumentException("Invalid destinationAddress");
     92         }
     93 
     94         if (TextUtils.isEmpty(text)) {
     95             throw new IllegalArgumentException("Invalid message body");
     96         }
     97 
     98         try {
     99             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    100             if (iccISms != null) {
    101                 iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress,
    102                         scAddress, text, sentIntent, deliveryIntent);
    103             }
    104         } catch (RemoteException ex) {
    105             // ignore it
    106         }
    107     }
    108 
    109     /**
    110      * Divide a message text into several fragments, none bigger than
    111      * the maximum SMS message size.
    112      *
    113      * @param text the original message.  Must not be null.
    114      * @return an <code>ArrayList</code> of strings that, in order,
    115      *   comprise the original message
    116      *
    117      * @throws IllegalArgumentException if text is null
    118      */
    119     public ArrayList<String> divideMessage(String text) {
    120         if (null == text) {
    121             throw new IllegalArgumentException("text is null");
    122         }
    123         return SmsMessage.fragmentText(text);
    124     }
    125 
    126     /**
    127      * Send a multi-part text based SMS.  The callee should have already
    128      * divided the message into correctly sized parts by calling
    129      * <code>divideMessage</code>.
    130      *
    131      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
    132      * {@link android.Manifest.permission#SEND_SMS} permission.</p>
    133      *
    134      * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
    135      * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
    136      * writes messages sent using this method to the SMS Provider (the default SMS app is always
    137      * responsible for writing its sent messages to the SMS Provider). For information about
    138      * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
    139      *
    140      * @param destinationAddress the address to send the message to
    141      * @param scAddress is the service center address or null to use
    142      *   the current default SMSC
    143      * @param parts an <code>ArrayList</code> of strings that, in order,
    144      *   comprise the original message
    145      * @param sentIntents if not null, an <code>ArrayList</code> of
    146      *   <code>PendingIntent</code>s (one for each message part) that is
    147      *   broadcast when the corresponding message part has been sent.
    148      *   The result code will be <code>Activity.RESULT_OK</code> for success,
    149      *   or one of these errors:<br>
    150      *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
    151      *   <code>RESULT_ERROR_RADIO_OFF</code><br>
    152      *   <code>RESULT_ERROR_NULL_PDU</code><br>
    153      *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
    154      *   the extra "errorCode" containing a radio technology specific value,
    155      *   generally only useful for troubleshooting.<br>
    156      *   The per-application based SMS control checks sentIntent. If sentIntent
    157      *   is NULL the caller will be checked against all unknown applications,
    158      *   which cause smaller number of SMS to be sent in checking period.
    159      * @param deliveryIntents if not null, an <code>ArrayList</code> of
    160      *   <code>PendingIntent</code>s (one for each message part) that is
    161      *   broadcast when the corresponding message part has been delivered
    162      *   to the recipient.  The raw pdu of the status report is in the
    163      *   extended data ("pdu").
    164      *
    165      * @throws IllegalArgumentException if destinationAddress or data are empty
    166      */
    167     public void sendMultipartTextMessage(
    168             String destinationAddress, String scAddress, ArrayList<String> parts,
    169             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
    170         if (TextUtils.isEmpty(destinationAddress)) {
    171             throw new IllegalArgumentException("Invalid destinationAddress");
    172         }
    173         if (parts == null || parts.size() < 1) {
    174             throw new IllegalArgumentException("Invalid message body");
    175         }
    176 
    177         if (parts.size() > 1) {
    178             try {
    179                 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    180                 if (iccISms != null) {
    181                     iccISms.sendMultipartText(ActivityThread.currentPackageName(),
    182                             destinationAddress, scAddress, parts,
    183                             sentIntents, deliveryIntents);
    184                 }
    185             } catch (RemoteException ex) {
    186                 // ignore it
    187             }
    188         } else {
    189             PendingIntent sentIntent = null;
    190             PendingIntent deliveryIntent = null;
    191             if (sentIntents != null && sentIntents.size() > 0) {
    192                 sentIntent = sentIntents.get(0);
    193             }
    194             if (deliveryIntents != null && deliveryIntents.size() > 0) {
    195                 deliveryIntent = deliveryIntents.get(0);
    196             }
    197             sendTextMessage(destinationAddress, scAddress, parts.get(0),
    198                     sentIntent, deliveryIntent);
    199         }
    200     }
    201 
    202     /**
    203      * Send a data based SMS to a specific application port.
    204      *
    205      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
    206      * {@link android.Manifest.permission#SEND_SMS} permission.</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 destinationPort the port to deliver the message to
    212      * @param data the body of the message to send
    213      * @param sentIntent if not NULL this <code>PendingIntent</code> is
    214      *  broadcast when the message is successfully sent, or failed.
    215      *  The result code will be <code>Activity.RESULT_OK</code> for success,
    216      *  or one of these errors:<br>
    217      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
    218      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
    219      *  <code>RESULT_ERROR_NULL_PDU</code><br>
    220      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
    221      *  the extra "errorCode" containing a radio technology specific value,
    222      *  generally only useful for troubleshooting.<br>
    223      *  The per-application based SMS control checks sentIntent. If sentIntent
    224      *  is NULL the caller will be checked against all unknown applications,
    225      *  which cause smaller number of SMS to be sent in checking period.
    226      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
    227      *  broadcast when the message is delivered to the recipient.  The
    228      *  raw pdu of the status report is in the extended data ("pdu").
    229      *
    230      * @throws IllegalArgumentException if destinationAddress or data are empty
    231      */
    232     public void sendDataMessage(
    233             String destinationAddress, String scAddress, short destinationPort,
    234             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
    235         if (TextUtils.isEmpty(destinationAddress)) {
    236             throw new IllegalArgumentException("Invalid destinationAddress");
    237         }
    238 
    239         if (data == null || data.length == 0) {
    240             throw new IllegalArgumentException("Invalid message data");
    241         }
    242 
    243         try {
    244             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    245             if (iccISms != null) {
    246                 iccISms.sendData(ActivityThread.currentPackageName(),
    247                         destinationAddress, scAddress, destinationPort & 0xFFFF,
    248                         data, sentIntent, deliveryIntent);
    249             }
    250         } catch (RemoteException ex) {
    251             // ignore it
    252         }
    253     }
    254 
    255     /**
    256      * Get the default instance of the SmsManager
    257      *
    258      * @return the default instance of the SmsManager
    259      */
    260     public static SmsManager getDefault() {
    261         return sInstance;
    262     }
    263 
    264     private SmsManager() {
    265         //nothing
    266     }
    267 
    268     /**
    269      * Copy a raw SMS PDU to the ICC.
    270      * ICC (Integrated Circuit Card) is the card of the device.
    271      * For example, this can be the SIM or USIM for GSM.
    272      *
    273      * @param smsc the SMSC for this message, or NULL for the default SMSC
    274      * @param pdu the raw PDU to store
    275      * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
    276      *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
    277      * @return true for success
    278      *
    279      * @throws IllegalArgumentException if pdu is NULL
    280      * {@hide}
    281      */
    282     public boolean copyMessageToIcc(byte[] smsc, byte[] pdu, int status) {
    283         boolean success = false;
    284 
    285         if (null == pdu) {
    286             throw new IllegalArgumentException("pdu is NULL");
    287         }
    288         try {
    289             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    290             if (iccISms != null) {
    291                 success = iccISms.copyMessageToIccEf(ActivityThread.currentPackageName(),
    292                         status, pdu, smsc);
    293             }
    294         } catch (RemoteException ex) {
    295             // ignore it
    296         }
    297 
    298         return success;
    299     }
    300 
    301     /**
    302      * Delete the specified message from the ICC.
    303      * ICC (Integrated Circuit Card) is the card of the device.
    304      * For example, this can be the SIM or USIM for GSM.
    305      *
    306      * @param messageIndex is the record index of the message on ICC
    307      * @return true for success
    308      *
    309      * {@hide}
    310      */
    311     public boolean
    312     deleteMessageFromIcc(int messageIndex) {
    313         boolean success = false;
    314         byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1];
    315         Arrays.fill(pdu, (byte)0xff);
    316 
    317         try {
    318             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    319             if (iccISms != null) {
    320                 success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(),
    321                         messageIndex, STATUS_ON_ICC_FREE, pdu);
    322             }
    323         } catch (RemoteException ex) {
    324             // ignore it
    325         }
    326 
    327         return success;
    328     }
    329 
    330     /**
    331      * Update the specified message on the ICC.
    332      * ICC (Integrated Circuit Card) is the card of the device.
    333      * For example, this can be the SIM or USIM for GSM.
    334      *
    335      * @param messageIndex record index of message to update
    336      * @param newStatus new message status (STATUS_ON_ICC_READ,
    337      *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
    338      *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
    339      * @param pdu the raw PDU to store
    340      * @return true for success
    341      *
    342      * {@hide}
    343      */
    344     public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
    345         boolean success = false;
    346 
    347         try {
    348             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    349             if (iccISms != null) {
    350                 success = iccISms.updateMessageOnIccEf(ActivityThread.currentPackageName(),
    351                         messageIndex, newStatus, pdu);
    352             }
    353         } catch (RemoteException ex) {
    354             // ignore it
    355         }
    356 
    357         return success;
    358     }
    359 
    360     /**
    361      * Retrieves all messages currently stored on ICC.
    362      * ICC (Integrated Circuit Card) is the card of the device.
    363      * For example, this can be the SIM or USIM for GSM.
    364      *
    365      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
    366      *
    367      * {@hide}
    368      */
    369     public static ArrayList<SmsMessage> getAllMessagesFromIcc() {
    370         List<SmsRawData> records = null;
    371 
    372         try {
    373             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    374             if (iccISms != null) {
    375                 records = iccISms.getAllMessagesFromIccEf(ActivityThread.currentPackageName());
    376             }
    377         } catch (RemoteException ex) {
    378             // ignore it
    379         }
    380 
    381         return createMessageListFromRawRecords(records);
    382     }
    383 
    384     /**
    385      * Enable reception of cell broadcast (SMS-CB) messages with the given
    386      * message identifier. Note that if two different clients enable the same
    387      * message identifier, they must both disable it for the device to stop
    388      * receiving those messages. All received messages will be broadcast in an
    389      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
    390      * Note: This call is blocking, callers may want to avoid calling it from
    391      * the main thread of an application.
    392      *
    393      * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
    394      * or C.R1001-G (3GPP2)
    395      * @return true if successful, false otherwise
    396      * @see #disableCellBroadcast(int)
    397      *
    398      * {@hide}
    399      */
    400     public boolean enableCellBroadcast(int messageIdentifier) {
    401         boolean success = false;
    402 
    403         try {
    404             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    405             if (iccISms != null) {
    406                 success = iccISms.enableCellBroadcast(messageIdentifier);
    407             }
    408         } catch (RemoteException ex) {
    409             // ignore it
    410         }
    411 
    412         return success;
    413     }
    414 
    415     /**
    416      * Disable reception of cell broadcast (SMS-CB) messages with the given
    417      * message identifier. Note that if two different clients enable the same
    418      * message identifier, they must both disable it for the device to stop
    419      * receiving those messages.
    420      * Note: This call is blocking, callers may want to avoid calling it from
    421      * the main thread of an application.
    422      *
    423      * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
    424      * or C.R1001-G (3GPP2)
    425      * @return true if successful, false otherwise
    426      *
    427      * @see #enableCellBroadcast(int)
    428      *
    429      * {@hide}
    430      */
    431     public boolean disableCellBroadcast(int messageIdentifier) {
    432         boolean success = false;
    433 
    434         try {
    435             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    436             if (iccISms != null) {
    437                 success = iccISms.disableCellBroadcast(messageIdentifier);
    438             }
    439         } catch (RemoteException ex) {
    440             // ignore it
    441         }
    442 
    443         return success;
    444     }
    445 
    446     /**
    447      * Enable reception of cell broadcast (SMS-CB) messages with the given
    448      * message identifier range. Note that if two different clients enable the same
    449      * message identifier, they must both disable it for the device to stop
    450      * receiving those messages. All received messages will be broadcast in an
    451      * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
    452      * Note: This call is blocking, callers may want to avoid calling it from
    453      * the main thread of an application.
    454      *
    455      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
    456      * or C.R1001-G (3GPP2)
    457      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
    458      * or C.R1001-G (3GPP2)
    459      * @return true if successful, false otherwise
    460      * @see #disableCellBroadcastRange(int, int)
    461      *
    462      * @throws IllegalArgumentException if endMessageId < startMessageId
    463      * {@hide}
    464      */
    465     public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) {
    466         boolean success = false;
    467 
    468         if (endMessageId < startMessageId) {
    469             throw new IllegalArgumentException("endMessageId < startMessageId");
    470         }
    471         try {
    472             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    473             if (iccISms != null) {
    474                 success = iccISms.enableCellBroadcastRange(startMessageId, endMessageId);
    475             }
    476         } catch (RemoteException ex) {
    477             // ignore it
    478         }
    479 
    480         return success;
    481     }
    482 
    483     /**
    484      * Disable reception of cell broadcast (SMS-CB) messages with the given
    485      * message identifier range. Note that if two different clients enable the same
    486      * message identifier, they must both disable it for the device to stop
    487      * receiving those messages.
    488      * Note: This call is blocking, callers may want to avoid calling it from
    489      * the main thread of an application.
    490      *
    491      * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
    492      * or C.R1001-G (3GPP2)
    493      * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
    494      * or C.R1001-G (3GPP2)
    495      * @return true if successful, false otherwise
    496      *
    497      * @see #enableCellBroadcastRange(int, int)
    498      *
    499      * @throws IllegalArgumentException if endMessageId < startMessageId
    500      * {@hide}
    501      */
    502     public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) {
    503         boolean success = false;
    504 
    505         if (endMessageId < startMessageId) {
    506             throw new IllegalArgumentException("endMessageId < startMessageId");
    507         }
    508         try {
    509             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    510             if (iccISms != null) {
    511                 success = iccISms.disableCellBroadcastRange(startMessageId, endMessageId);
    512             }
    513         } catch (RemoteException ex) {
    514             // ignore it
    515         }
    516 
    517         return success;
    518     }
    519 
    520     /**
    521      * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
    522      * records returned by <code>getAllMessagesFromIcc()</code>
    523      *
    524      * @param records SMS EF records, returned by
    525      *   <code>getAllMessagesFromIcc</code>
    526      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
    527      */
    528     private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
    529         ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
    530         if (records != null) {
    531             int count = records.size();
    532             for (int i = 0; i < count; i++) {
    533                 SmsRawData data = records.get(i);
    534                 // List contains all records, including "free" records (null)
    535                 if (data != null) {
    536                     SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
    537                     if (sms != null) {
    538                         messages.add(sms);
    539                     }
    540                 }
    541             }
    542         }
    543         return messages;
    544     }
    545 
    546     /**
    547      * SMS over IMS is supported if IMS is registered and SMS is supported
    548      * on IMS.
    549      *
    550      * @return true if SMS over IMS is supported, false otherwise
    551      *
    552      * @see #getImsSmsFormat()
    553      *
    554      * @hide
    555      */
    556     boolean isImsSmsSupported() {
    557         boolean boSupported = false;
    558         try {
    559             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    560             if (iccISms != null) {
    561                 boSupported = iccISms.isImsSmsSupported();
    562             }
    563         } catch (RemoteException ex) {
    564             // ignore it
    565         }
    566         return boSupported;
    567     }
    568 
    569     /**
    570      * Gets SMS format supported on IMS.  SMS over IMS format is
    571      * either 3GPP or 3GPP2.
    572      *
    573      * @return SmsMessage.FORMAT_3GPP,
    574      *         SmsMessage.FORMAT_3GPP2
    575      *      or SmsMessage.FORMAT_UNKNOWN
    576      *
    577      * @see #isImsSmsSupported()
    578      *
    579      * @hide
    580      */
    581     String getImsSmsFormat() {
    582         String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
    583         try {
    584             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
    585             if (iccISms != null) {
    586                 format = iccISms.getImsSmsFormat();
    587             }
    588         } catch (RemoteException ex) {
    589             // ignore it
    590         }
    591         return format;
    592     }
    593 
    594     // see SmsMessage.getStatusOnIcc
    595 
    596     /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
    597     static public final int STATUS_ON_ICC_FREE      = 0;
    598 
    599     /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
    600     static public final int STATUS_ON_ICC_READ      = 1;
    601 
    602     /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
    603     static public final int STATUS_ON_ICC_UNREAD    = 3;
    604 
    605     /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
    606     static public final int STATUS_ON_ICC_SENT      = 5;
    607 
    608     /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
    609     static public final int STATUS_ON_ICC_UNSENT    = 7;
    610 
    611     // SMS send failure result codes
    612 
    613     /** Generic failure cause */
    614     static public final int RESULT_ERROR_GENERIC_FAILURE    = 1;
    615     /** Failed because radio was explicitly turned off */
    616     static public final int RESULT_ERROR_RADIO_OFF          = 2;
    617     /** Failed because no pdu provided */
    618     static public final int RESULT_ERROR_NULL_PDU           = 3;
    619     /** Failed because service is currently unavailable */
    620     static public final int RESULT_ERROR_NO_SERVICE         = 4;
    621     /** Failed because we reached the sending queue limit.  {@hide} */
    622     static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
    623     /** Failed because FDN is enabled. {@hide} */
    624     static public final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
    625 }
    626