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