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