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 com.android.internal.telephony;
     18 
     19 import android.Manifest;
     20 import android.app.AppOpsManager;
     21 import android.app.PendingIntent;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.database.Cursor;
     25 import android.database.sqlite.SQLiteException;
     26 import android.net.Uri;
     27 import android.os.AsyncResult;
     28 import android.os.Binder;
     29 import android.os.Handler;
     30 import android.os.Message;
     31 import android.os.UserManager;
     32 import android.provider.Telephony;
     33 import android.telephony.Rlog;
     34 import android.telephony.SmsManager;
     35 import android.telephony.SmsMessage;
     36 import android.util.Log;
     37 
     38 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
     39 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
     40 import com.android.internal.telephony.uicc.IccConstants;
     41 import com.android.internal.telephony.uicc.IccFileHandler;
     42 import com.android.internal.telephony.uicc.UiccController;
     43 import com.android.internal.telephony.SmsNumberUtils;
     44 import com.android.internal.util.HexDump;
     45 
     46 import java.util.ArrayList;
     47 import java.util.Arrays;
     48 import java.util.List;
     49 
     50 import static android.telephony.SmsManager.STATUS_ON_ICC_FREE;
     51 import static android.telephony.SmsManager.STATUS_ON_ICC_READ;
     52 import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD;
     53 
     54 import android.telephony.TelephonyManager;
     55 
     56 /**
     57  * IccSmsInterfaceManager to provide an inter-process communication to
     58  * access Sms in Icc.
     59  */
     60 public class IccSmsInterfaceManager {
     61     static final String LOG_TAG = "IccSmsInterfaceManager";
     62     static final boolean DBG = true;
     63 
     64     protected final Object mLock = new Object();
     65     protected boolean mSuccess;
     66     private List<SmsRawData> mSms;
     67 
     68     private CellBroadcastRangeManager mCellBroadcastRangeManager =
     69             new CellBroadcastRangeManager();
     70     private CdmaBroadcastRangeManager mCdmaBroadcastRangeManager =
     71             new CdmaBroadcastRangeManager();
     72 
     73     private static final int EVENT_LOAD_DONE = 1;
     74     private static final int EVENT_UPDATE_DONE = 2;
     75     protected static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3;
     76     protected static final int EVENT_SET_BROADCAST_CONFIG_DONE = 4;
     77     private static final int SMS_CB_CODE_SCHEME_MIN = 0;
     78     private static final int SMS_CB_CODE_SCHEME_MAX = 255;
     79 
     80     protected PhoneBase mPhone;
     81     final protected Context mContext;
     82     final protected AppOpsManager mAppOps;
     83     final private UserManager mUserManager;
     84     protected SMSDispatcher mDispatcher;
     85 
     86     protected Handler mHandler = new Handler() {
     87         @Override
     88         public void handleMessage(Message msg) {
     89             AsyncResult ar;
     90 
     91             switch (msg.what) {
     92                 case EVENT_UPDATE_DONE:
     93                     ar = (AsyncResult) msg.obj;
     94                     synchronized (mLock) {
     95                         mSuccess = (ar.exception == null);
     96                         mLock.notifyAll();
     97                     }
     98                     break;
     99                 case EVENT_LOAD_DONE:
    100                     ar = (AsyncResult)msg.obj;
    101                     synchronized (mLock) {
    102                         if (ar.exception == null) {
    103                             mSms = buildValidRawData((ArrayList<byte[]>) ar.result);
    104                             //Mark SMS as read after importing it from card.
    105                             markMessagesAsRead((ArrayList<byte[]>) ar.result);
    106                         } else {
    107                             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
    108                                 log("Cannot load Sms records");
    109                             }
    110                             if (mSms != null)
    111                                 mSms.clear();
    112                         }
    113                         mLock.notifyAll();
    114                     }
    115                     break;
    116                 case EVENT_SET_BROADCAST_ACTIVATION_DONE:
    117                 case EVENT_SET_BROADCAST_CONFIG_DONE:
    118                     ar = (AsyncResult) msg.obj;
    119                     synchronized (mLock) {
    120                         mSuccess = (ar.exception == null);
    121                         mLock.notifyAll();
    122                     }
    123                     break;
    124             }
    125         }
    126     };
    127 
    128     protected IccSmsInterfaceManager(PhoneBase phone) {
    129         mPhone = phone;
    130         mContext = phone.getContext();
    131         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
    132         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    133         mDispatcher = new ImsSMSDispatcher(phone,
    134                 phone.mSmsStorageMonitor, phone.mSmsUsageMonitor);
    135     }
    136 
    137     protected void markMessagesAsRead(ArrayList<byte[]> messages) {
    138         if (messages == null) {
    139             return;
    140         }
    141 
    142         //IccFileHandler can be null, if icc card is absent.
    143         IccFileHandler fh = mPhone.getIccFileHandler();
    144         if (fh == null) {
    145             //shouldn't really happen, as messages are marked as read, only
    146             //after importing it from icc.
    147             if (Rlog.isLoggable("SMS", Log.DEBUG)) {
    148                 log("markMessagesAsRead - aborting, no icc card present.");
    149             }
    150             return;
    151         }
    152 
    153         int count = messages.size();
    154 
    155         for (int i = 0; i < count; i++) {
    156              byte[] ba = messages.get(i);
    157              if (ba[0] == STATUS_ON_ICC_UNREAD) {
    158                  int n = ba.length;
    159                  byte[] nba = new byte[n - 1];
    160                  System.arraycopy(ba, 1, nba, 0, n - 1);
    161                  byte[] record = makeSmsRecordData(STATUS_ON_ICC_READ, nba);
    162                  fh.updateEFLinearFixed(IccConstants.EF_SMS, i + 1, record, null, null);
    163                  if (Rlog.isLoggable("SMS", Log.DEBUG)) {
    164                      log("SMS " + (i + 1) + " marked as read");
    165                  }
    166              }
    167         }
    168     }
    169 
    170     protected void updatePhoneObject(PhoneBase phone) {
    171         mPhone = phone;
    172         mDispatcher.updatePhoneObject(phone);
    173     }
    174 
    175     protected void enforceReceiveAndSend(String message) {
    176         mContext.enforceCallingOrSelfPermission(
    177                 Manifest.permission.RECEIVE_SMS, message);
    178         mContext.enforceCallingOrSelfPermission(
    179                 Manifest.permission.SEND_SMS, message);
    180     }
    181 
    182     /**
    183      * Update the specified message on the Icc.
    184      *
    185      * @param index record index of message to update
    186      * @param status new message status (STATUS_ON_ICC_READ,
    187      *                  STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
    188      *                  STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
    189      * @param pdu the raw PDU to store
    190      * @return success or not
    191      *
    192      */
    193 
    194     public boolean
    195     updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu) {
    196         if (DBG) log("updateMessageOnIccEf: index=" + index +
    197                 " status=" + status + " ==> " +
    198                 "("+ Arrays.toString(pdu) + ")");
    199         enforceReceiveAndSend("Updating message on Icc");
    200         if (mAppOps.noteOp(AppOpsManager.OP_WRITE_ICC_SMS, Binder.getCallingUid(),
    201                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
    202             return false;
    203         }
    204         synchronized(mLock) {
    205             mSuccess = false;
    206             Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
    207 
    208             if (status == STATUS_ON_ICC_FREE) {
    209                 // RIL_REQUEST_DELETE_SMS_ON_SIM vs RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM
    210                 // Special case FREE: call deleteSmsOnSim/Ruim instead of
    211                 // manipulating the record
    212                 // Will eventually fail if icc card is not present.
    213                 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
    214                     mPhone.mCi.deleteSmsOnSim(index, response);
    215                 } else {
    216                     mPhone.mCi.deleteSmsOnRuim(index, response);
    217                 }
    218             } else {
    219                 //IccFilehandler can be null if ICC card is not present.
    220                 IccFileHandler fh = mPhone.getIccFileHandler();
    221                 if (fh == null) {
    222                     response.recycle();
    223                     return mSuccess; /* is false */
    224                 }
    225                 byte[] record = makeSmsRecordData(status, pdu);
    226                 fh.updateEFLinearFixed(
    227                         IccConstants.EF_SMS,
    228                         index, record, null, response);
    229             }
    230             try {
    231                 mLock.wait();
    232             } catch (InterruptedException e) {
    233                 log("interrupted while trying to update by index");
    234             }
    235         }
    236         return mSuccess;
    237     }
    238 
    239     /**
    240      * Copy a raw SMS PDU to the Icc.
    241      *
    242      * @param pdu the raw PDU to store
    243      * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
    244      *               STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
    245      * @return success or not
    246      *
    247      */
    248     public boolean copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc) {
    249         //NOTE smsc not used in RUIM
    250         if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " +
    251                 "pdu=("+ Arrays.toString(pdu) +
    252                 "), smsc=(" + Arrays.toString(smsc) +")");
    253         enforceReceiveAndSend("Copying message to Icc");
    254         if (mAppOps.noteOp(AppOpsManager.OP_WRITE_ICC_SMS, Binder.getCallingUid(),
    255                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
    256             return false;
    257         }
    258         synchronized(mLock) {
    259             mSuccess = false;
    260             Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
    261 
    262             //RIL_REQUEST_WRITE_SMS_TO_SIM vs RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM
    263             if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
    264                 mPhone.mCi.writeSmsToSim(status, IccUtils.bytesToHexString(smsc),
    265                         IccUtils.bytesToHexString(pdu), response);
    266             } else {
    267                 mPhone.mCi.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu),
    268                         response);
    269             }
    270 
    271             try {
    272                 mLock.wait();
    273             } catch (InterruptedException e) {
    274                 log("interrupted while trying to update by index");
    275             }
    276         }
    277         return mSuccess;
    278     }
    279 
    280     /**
    281      * Retrieves all messages currently stored on Icc.
    282      *
    283      * @return list of SmsRawData of all sms on Icc
    284      */
    285 
    286     public List<SmsRawData> getAllMessagesFromIccEf(String callingPackage) {
    287         if (DBG) log("getAllMessagesFromEF");
    288 
    289         mContext.enforceCallingOrSelfPermission(
    290                 Manifest.permission.RECEIVE_SMS,
    291                 "Reading messages from Icc");
    292         if (mAppOps.noteOp(AppOpsManager.OP_READ_ICC_SMS, Binder.getCallingUid(),
    293                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
    294             return new ArrayList<SmsRawData>();
    295         }
    296         synchronized(mLock) {
    297 
    298             IccFileHandler fh = mPhone.getIccFileHandler();
    299             if (fh == null) {
    300                 Rlog.e(LOG_TAG, "Cannot load Sms records. No icc card?");
    301                 if (mSms != null) {
    302                     mSms.clear();
    303                     return mSms;
    304                 }
    305             }
    306 
    307             Message response = mHandler.obtainMessage(EVENT_LOAD_DONE);
    308             fh.loadEFLinearFixedAll(IccConstants.EF_SMS, response);
    309 
    310             try {
    311                 mLock.wait();
    312             } catch (InterruptedException e) {
    313                 log("interrupted while trying to load from the Icc");
    314             }
    315         }
    316         return mSms;
    317     }
    318 
    319     /**
    320      * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}.
    321      * This method checks if the calling package or itself has the permission to send the data sms.
    322      */
    323     public void sendDataWithSelfPermissions(String callingPackage, String destAddr, String scAddr,
    324             int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
    325         mPhone.getContext().enforceCallingOrSelfPermission(
    326                 Manifest.permission.SEND_SMS,
    327                 "Sending SMS message");
    328         sendDataInternal(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
    329                 deliveryIntent);
    330     }
    331 
    332     /**
    333      * A permissions check before passing to {@link IccSmsInterfaceManager#sendDataInternal}.
    334      * This method checks only if the calling package has the permission to send the data sms.
    335      */
    336     public void sendData(String callingPackage, String destAddr, String scAddr, int destPort,
    337             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
    338         mPhone.getContext().enforceCallingPermission(
    339                 Manifest.permission.SEND_SMS,
    340                 "Sending SMS message");
    341         sendDataInternal(callingPackage, destAddr, scAddr, destPort, data, sentIntent,
    342                 deliveryIntent);
    343     }
    344 
    345     /**
    346      * Send a data based SMS to a specific application port.
    347      *
    348      * @param destAddr the address to send the message to
    349      * @param scAddr is the service center address or null to use
    350      *  the current default SMSC
    351      * @param destPort the port to deliver the message to
    352      * @param data the body of the message to send
    353      * @param sentIntent if not NULL this <code>PendingIntent</code> is
    354      *  broadcast when the message is successfully sent, or failed.
    355      *  The result code will be <code>Activity.RESULT_OK<code> for success,
    356      *  or one of these errors:<br>
    357      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
    358      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
    359      *  <code>RESULT_ERROR_NULL_PDU</code><br>
    360      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
    361      *  the extra "errorCode" containing a radio technology specific value,
    362      *  generally only useful for troubleshooting.<br>
    363      *  The per-application based SMS control checks sentIntent. If sentIntent
    364      *  is NULL the caller will be checked against all unknown applications,
    365      *  which cause smaller number of SMS to be sent in checking period.
    366      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
    367      *  broadcast when the message is delivered to the recipient.  The
    368      *  raw pdu of the status report is in the extended data ("pdu").
    369      */
    370 
    371     private void sendDataInternal(String callingPackage, String destAddr, String scAddr,
    372             int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
    373         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
    374             log("sendData: destAddr=" + destAddr + " scAddr=" + scAddr + " destPort=" +
    375                 destPort + " data='"+ HexDump.toHexString(data)  + "' sentIntent=" +
    376                 sentIntent + " deliveryIntent=" + deliveryIntent);
    377         }
    378         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
    379                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
    380             return;
    381         }
    382         destAddr = filterDestAddress(destAddr);
    383         mDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent);
    384     }
    385 
    386     /**
    387      * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
    388      * This method checks only if the calling package has the permission to send the sms.
    389      */
    390     public void sendText(String callingPackage, String destAddr, String scAddr,
    391             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
    392             boolean persistMessageForNonDefaultSmsApp) {
    393         mPhone.getContext().enforceCallingPermission(
    394                 Manifest.permission.SEND_SMS,
    395                 "Sending SMS message");
    396         sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
    397             persistMessageForNonDefaultSmsApp);
    398     }
    399 
    400     /**
    401      * A permissions check before passing to {@link IccSmsInterfaceManager#sendTextInternal}.
    402      * This method checks if the calling package or itself has the permission to send the sms.
    403      */
    404     public void sendTextWithSelfPermissions(String callingPackage, String destAddr, String scAddr,
    405             String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
    406         mPhone.getContext().enforceCallingOrSelfPermission(
    407                 Manifest.permission.SEND_SMS,
    408                 "Sending SMS message");
    409         sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,
    410             true /* persistMessageForNonDefaultSmsApp */);
    411     }
    412 
    413     /**
    414      * Send a text based SMS.
    415      *
    416      * @param destAddr the address to send the message to
    417      * @param scAddr is the service center address or null to use
    418      *  the current default SMSC
    419      * @param text the body of the message to send
    420      * @param sentIntent if not NULL this <code>PendingIntent</code> is
    421      *  broadcast when the message is successfully sent, or failed.
    422      *  The result code will be <code>Activity.RESULT_OK<code> for success,
    423      *  or one of these errors:<br>
    424      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
    425      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
    426      *  <code>RESULT_ERROR_NULL_PDU</code><br>
    427      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
    428      *  the extra "errorCode" containing a radio technology specific value,
    429      *  generally only useful for troubleshooting.<br>
    430      *  The per-application based SMS control checks sentIntent. If sentIntent
    431      *  is NULL the caller will be checked against all unknown applications,
    432      *  which cause smaller number of SMS to be sent in checking period.
    433      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
    434      *  broadcast when the message is delivered to the recipient.  The
    435      *  raw pdu of the status report is in the extended data ("pdu").
    436      */
    437 
    438     private void sendTextInternal(String callingPackage, String destAddr, String scAddr,
    439             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
    440             boolean persistMessageForNonDefaultSmsApp) {
    441         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
    442             log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +
    443                 " text='"+ text + "' sentIntent=" +
    444                 sentIntent + " deliveryIntent=" + deliveryIntent);
    445         }
    446         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
    447                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
    448             return;
    449         }
    450         if (!persistMessageForNonDefaultSmsApp) {
    451             // Only allow carrier app to skip auto message persistence.
    452             enforceCarrierPrivilege();
    453         }
    454         destAddr = filterDestAddress(destAddr);
    455         mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
    456                 null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp);
    457     }
    458 
    459     /**
    460      * Inject an SMS PDU into the android application framework.
    461      *
    462      * @param pdu is the byte array of pdu to be injected into android application framework
    463      * @param format is the format of SMS pdu (3gpp or 3gpp2)
    464      * @param receivedIntent if not NULL this <code>PendingIntent</code> is
    465      *  broadcast when the message is successfully received by the
    466      *  android application framework. This intent is broadcasted at
    467      *  the same time an SMS received from radio is acknowledged back.
    468      */
    469     public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
    470         enforceCarrierPrivilege();
    471         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
    472             log("pdu: " + pdu +
    473                 "\n format=" + format +
    474                 "\n receivedIntent=" + receivedIntent);
    475         }
    476         mDispatcher.injectSmsPdu(pdu, format, receivedIntent);
    477     }
    478 
    479     /**
    480      * Send a multi-part text based SMS.
    481      *
    482      * @param destAddr the address to send the message to
    483      * @param scAddr is the service center address or null to use
    484      *   the current default SMSC
    485      * @param parts an <code>ArrayList</code> of strings that, in order,
    486      *   comprise the original message
    487      * @param sentIntents if not null, an <code>ArrayList</code> of
    488      *   <code>PendingIntent</code>s (one for each message part) that is
    489      *   broadcast when the corresponding message part has been sent.
    490      *   The result code will be <code>Activity.RESULT_OK<code> for success,
    491      *   or one of these errors:
    492      *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
    493      *   <code>RESULT_ERROR_RADIO_OFF</code>
    494      *   <code>RESULT_ERROR_NULL_PDU</code>.
    495      *  The per-application based SMS control checks sentIntent. If sentIntent
    496      *  is NULL the caller will be checked against all unknown applications,
    497      *  which cause smaller number of SMS to be sent in checking period.
    498      * @param deliveryIntents if not null, an <code>ArrayList</code> of
    499      *   <code>PendingIntent</code>s (one for each message part) that is
    500      *   broadcast when the corresponding message part has been delivered
    501      *   to the recipient.  The raw pdu of the status report is in the
    502      *   extended data ("pdu").
    503      */
    504 
    505     public void sendMultipartText(String callingPackage, String destAddr, String scAddr,
    506             List<String> parts, List<PendingIntent> sentIntents,
    507             List<PendingIntent> deliveryIntents, boolean persistMessageForNonDefaultSmsApp) {
    508         mPhone.getContext().enforceCallingPermission(
    509                 Manifest.permission.SEND_SMS,
    510                 "Sending SMS message");
    511         if (!persistMessageForNonDefaultSmsApp) {
    512             // Only allow carrier app to skip auto message persistence.
    513             enforceCarrierPrivilege();
    514         }
    515         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
    516             int i = 0;
    517             for (String part : parts) {
    518                 log("sendMultipartText: destAddr=" + destAddr + ", srAddr=" + scAddr +
    519                         ", part[" + (i++) + "]=" + part);
    520             }
    521         }
    522         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
    523                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
    524             return;
    525         }
    526 
    527         destAddr = filterDestAddress(destAddr);
    528 
    529         if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
    530             for (int i = 0; i < parts.size(); i++) {
    531                 // If EMS is not supported, we have to break down EMS into single segment SMS
    532                 // and add page info " x/y".
    533                 String singlePart = parts.get(i);
    534                 if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
    535                     singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
    536                 } else {
    537                     singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size());
    538                 }
    539 
    540                 PendingIntent singleSentIntent = null;
    541                 if (sentIntents != null && sentIntents.size() > i) {
    542                     singleSentIntent = sentIntents.get(i);
    543                 }
    544 
    545                 PendingIntent singleDeliveryIntent = null;
    546                 if (deliveryIntents != null && deliveryIntents.size() > i) {
    547                     singleDeliveryIntent = deliveryIntents.get(i);
    548                 }
    549 
    550                 mDispatcher.sendText(destAddr, scAddr, singlePart,
    551                         singleSentIntent, singleDeliveryIntent,
    552                         null/*messageUri*/, callingPackage,
    553                         persistMessageForNonDefaultSmsApp);
    554             }
    555             return;
    556         }
    557 
    558         mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts,
    559                 (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents,
    560                 null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp);
    561     }
    562 
    563 
    564     public int getPremiumSmsPermission(String packageName) {
    565         return mDispatcher.getPremiumSmsPermission(packageName);
    566     }
    567 
    568 
    569     public void setPremiumSmsPermission(String packageName, int permission) {
    570         mDispatcher.setPremiumSmsPermission(packageName, permission);
    571     }
    572 
    573     /**
    574      * create SmsRawData lists from all sms record byte[]
    575      * Use null to indicate "free" record
    576      *
    577      * @param messages List of message records from EF_SMS.
    578      * @return SmsRawData list of all in-used records
    579      */
    580     protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) {
    581         int count = messages.size();
    582         ArrayList<SmsRawData> ret;
    583 
    584         ret = new ArrayList<SmsRawData>(count);
    585 
    586         for (int i = 0; i < count; i++) {
    587             byte[] ba = messages.get(i);
    588             if (ba[0] == STATUS_ON_ICC_FREE) {
    589                 ret.add(null);
    590             } else {
    591                 ret.add(new SmsRawData(messages.get(i)));
    592             }
    593         }
    594 
    595         return ret;
    596     }
    597 
    598     /**
    599      * Generates an EF_SMS record from status and raw PDU.
    600      *
    601      * @param status Message status.  See TS 51.011 10.5.3.
    602      * @param pdu Raw message PDU.
    603      * @return byte array for the record.
    604      */
    605     protected byte[] makeSmsRecordData(int status, byte[] pdu) {
    606         byte[] data;
    607         if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
    608             data = new byte[IccConstants.SMS_RECORD_LENGTH];
    609         } else {
    610             data = new byte[IccConstants.CDMA_SMS_RECORD_LENGTH];
    611         }
    612 
    613         // Status bits for this record.  See TS 51.011 10.5.3
    614         data[0] = (byte)(status & 7);
    615 
    616         System.arraycopy(pdu, 0, data, 1, pdu.length);
    617 
    618         // Pad out with 0xFF's.
    619         for (int j = pdu.length+1; j < data.length; j++) {
    620             data[j] = -1;
    621         }
    622 
    623         return data;
    624     }
    625 
    626     public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
    627         return enableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType);
    628     }
    629 
    630     public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
    631         return disableCellBroadcastRange(messageIdentifier, messageIdentifier, ranType);
    632     }
    633 
    634     public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
    635         if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM) {
    636             return enableGsmBroadcastRange(startMessageId, endMessageId);
    637         } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA) {
    638             return enableCdmaBroadcastRange(startMessageId, endMessageId);
    639         } else {
    640             throw new IllegalArgumentException("Not a supportted RAN Type");
    641         }
    642     }
    643 
    644     public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
    645         if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_GSM ) {
    646             return disableGsmBroadcastRange(startMessageId, endMessageId);
    647         } else if (ranType == SmsManager.CELL_BROADCAST_RAN_TYPE_CDMA)  {
    648             return disableCdmaBroadcastRange(startMessageId, endMessageId);
    649         } else {
    650             throw new IllegalArgumentException("Not a supportted RAN Type");
    651         }
    652     }
    653 
    654     synchronized public boolean enableGsmBroadcastRange(int startMessageId, int endMessageId) {
    655         if (DBG) log("enableGsmBroadcastRange");
    656 
    657         Context context = mPhone.getContext();
    658 
    659         context.enforceCallingPermission(
    660                 "android.permission.RECEIVE_SMS",
    661                 "Enabling cell broadcast SMS");
    662 
    663         String client = context.getPackageManager().getNameForUid(
    664                 Binder.getCallingUid());
    665 
    666         if (!mCellBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
    667             log("Failed to add GSM cell broadcast subscription for MID range " + startMessageId
    668                     + " to " + endMessageId + " from client " + client);
    669             return false;
    670         }
    671 
    672         if (DBG)
    673             log("Added GSM cell broadcast subscription for MID range " + startMessageId
    674                     + " to " + endMessageId + " from client " + client);
    675 
    676         setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
    677 
    678         return true;
    679     }
    680 
    681     synchronized public boolean disableGsmBroadcastRange(int startMessageId, int endMessageId) {
    682         if (DBG) log("disableGsmBroadcastRange");
    683 
    684         Context context = mPhone.getContext();
    685 
    686         context.enforceCallingPermission(
    687                 "android.permission.RECEIVE_SMS",
    688                 "Disabling cell broadcast SMS");
    689 
    690         String client = context.getPackageManager().getNameForUid(
    691                 Binder.getCallingUid());
    692 
    693         if (!mCellBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
    694             log("Failed to remove GSM cell broadcast subscription for MID range " + startMessageId
    695                     + " to " + endMessageId + " from client " + client);
    696             return false;
    697         }
    698 
    699         if (DBG)
    700             log("Removed GSM cell broadcast subscription for MID range " + startMessageId
    701                     + " to " + endMessageId + " from client " + client);
    702 
    703         setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty());
    704 
    705         return true;
    706     }
    707 
    708     synchronized public boolean enableCdmaBroadcastRange(int startMessageId, int endMessageId) {
    709         if (DBG) log("enableCdmaBroadcastRange");
    710 
    711         Context context = mPhone.getContext();
    712 
    713         context.enforceCallingPermission(
    714                 "android.permission.RECEIVE_SMS",
    715                 "Enabling cdma broadcast SMS");
    716 
    717         String client = context.getPackageManager().getNameForUid(
    718                 Binder.getCallingUid());
    719 
    720         if (!mCdmaBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) {
    721             log("Failed to add cdma broadcast subscription for MID range " + startMessageId
    722                     + " to " + endMessageId + " from client " + client);
    723             return false;
    724         }
    725 
    726         if (DBG)
    727             log("Added cdma broadcast subscription for MID range " + startMessageId
    728                     + " to " + endMessageId + " from client " + client);
    729 
    730         setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty());
    731 
    732         return true;
    733     }
    734 
    735     synchronized public boolean disableCdmaBroadcastRange(int startMessageId, int endMessageId) {
    736         if (DBG) log("disableCdmaBroadcastRange");
    737 
    738         Context context = mPhone.getContext();
    739 
    740         context.enforceCallingPermission(
    741                 "android.permission.RECEIVE_SMS",
    742                 "Disabling cell broadcast SMS");
    743 
    744         String client = context.getPackageManager().getNameForUid(
    745                 Binder.getCallingUid());
    746 
    747         if (!mCdmaBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) {
    748             log("Failed to remove cdma broadcast subscription for MID range " + startMessageId
    749                     + " to " + endMessageId + " from client " + client);
    750             return false;
    751         }
    752 
    753         if (DBG)
    754             log("Removed cdma broadcast subscription for MID range " + startMessageId
    755                     + " to " + endMessageId + " from client " + client);
    756 
    757         setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty());
    758 
    759         return true;
    760     }
    761 
    762     class CellBroadcastRangeManager extends IntRangeManager {
    763         private ArrayList<SmsBroadcastConfigInfo> mConfigList =
    764                 new ArrayList<SmsBroadcastConfigInfo>();
    765 
    766         /**
    767          * Called when the list of enabled ranges has changed. This will be
    768          * followed by zero or more calls to {@link #addRange} followed by
    769          * a call to {@link #finishUpdate}.
    770          */
    771         protected void startUpdate() {
    772             mConfigList.clear();
    773         }
    774 
    775         /**
    776          * Called after {@link #startUpdate} to indicate a range of enabled
    777          * values.
    778          * @param startId the first id included in the range
    779          * @param endId the last id included in the range
    780          */
    781         protected void addRange(int startId, int endId, boolean selected) {
    782             mConfigList.add(new SmsBroadcastConfigInfo(startId, endId,
    783                         SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected));
    784         }
    785 
    786         /**
    787          * Called to indicate the end of a range update started by the
    788          * previous call to {@link #startUpdate}.
    789          * @return true if successful, false otherwise
    790          */
    791         protected boolean finishUpdate() {
    792             if (mConfigList.isEmpty()) {
    793                 return true;
    794             } else {
    795                 SmsBroadcastConfigInfo[] configs =
    796                         mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]);
    797                 return setCellBroadcastConfig(configs);
    798             }
    799         }
    800     }
    801 
    802     class CdmaBroadcastRangeManager extends IntRangeManager {
    803         private ArrayList<CdmaSmsBroadcastConfigInfo> mConfigList =
    804                 new ArrayList<CdmaSmsBroadcastConfigInfo>();
    805 
    806         /**
    807          * Called when the list of enabled ranges has changed. This will be
    808          * followed by zero or more calls to {@link #addRange} followed by a
    809          * call to {@link #finishUpdate}.
    810          */
    811         protected void startUpdate() {
    812             mConfigList.clear();
    813         }
    814 
    815         /**
    816          * Called after {@link #startUpdate} to indicate a range of enabled
    817          * values.
    818          * @param startId the first id included in the range
    819          * @param endId the last id included in the range
    820          */
    821         protected void addRange(int startId, int endId, boolean selected) {
    822             mConfigList.add(new CdmaSmsBroadcastConfigInfo(startId, endId,
    823                     1, selected));
    824         }
    825 
    826         /**
    827          * Called to indicate the end of a range update started by the previous
    828          * call to {@link #startUpdate}.
    829          * @return true if successful, false otherwise
    830          */
    831         protected boolean finishUpdate() {
    832             if (mConfigList.isEmpty()) {
    833                 return true;
    834             } else {
    835                 CdmaSmsBroadcastConfigInfo[] configs =
    836                         mConfigList.toArray(new CdmaSmsBroadcastConfigInfo[mConfigList.size()]);
    837                 return setCdmaBroadcastConfig(configs);
    838             }
    839         }
    840     }
    841 
    842     private boolean setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs) {
    843         if (DBG)
    844             log("Calling setGsmBroadcastConfig with " + configs.length + " configurations");
    845 
    846         synchronized (mLock) {
    847             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE);
    848 
    849             mSuccess = false;
    850             mPhone.mCi.setGsmBroadcastConfig(configs, response);
    851 
    852             try {
    853                 mLock.wait();
    854             } catch (InterruptedException e) {
    855                 log("interrupted while trying to set cell broadcast config");
    856             }
    857         }
    858 
    859         return mSuccess;
    860     }
    861 
    862     private boolean setCellBroadcastActivation(boolean activate) {
    863         if (DBG)
    864             log("Calling setCellBroadcastActivation(" + activate + ')');
    865 
    866         synchronized (mLock) {
    867             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
    868 
    869             mSuccess = false;
    870             mPhone.mCi.setGsmBroadcastActivation(activate, response);
    871 
    872             try {
    873                 mLock.wait();
    874             } catch (InterruptedException e) {
    875                 log("interrupted while trying to set cell broadcast activation");
    876             }
    877         }
    878 
    879         return mSuccess;
    880     }
    881 
    882     private boolean setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs) {
    883         if (DBG)
    884             log("Calling setCdmaBroadcastConfig with " + configs.length + " configurations");
    885 
    886         synchronized (mLock) {
    887             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE);
    888 
    889             mSuccess = false;
    890             mPhone.mCi.setCdmaBroadcastConfig(configs, response);
    891 
    892             try {
    893                 mLock.wait();
    894             } catch (InterruptedException e) {
    895                 log("interrupted while trying to set cdma broadcast config");
    896             }
    897         }
    898 
    899         return mSuccess;
    900     }
    901 
    902     private boolean setCdmaBroadcastActivation(boolean activate) {
    903         if (DBG)
    904             log("Calling setCdmaBroadcastActivation(" + activate + ")");
    905 
    906         synchronized (mLock) {
    907             Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE);
    908 
    909             mSuccess = false;
    910             mPhone.mCi.setCdmaBroadcastActivation(activate, response);
    911 
    912             try {
    913                 mLock.wait();
    914             } catch (InterruptedException e) {
    915                 log("interrupted while trying to set cdma broadcast activation");
    916             }
    917         }
    918 
    919         return mSuccess;
    920     }
    921 
    922     protected void log(String msg) {
    923         Log.d(LOG_TAG, "[IccSmsInterfaceManager] " + msg);
    924     }
    925 
    926     public boolean isImsSmsSupported() {
    927         return mDispatcher.isIms();
    928     }
    929 
    930     public String getImsSmsFormat() {
    931         return mDispatcher.getImsSmsFormat();
    932     }
    933 
    934     public void sendStoredText(String callingPkg, Uri messageUri, String scAddress,
    935             PendingIntent sentIntent, PendingIntent deliveryIntent) {
    936         mPhone.getContext().enforceCallingPermission(Manifest.permission.SEND_SMS,
    937                 "Sending SMS message");
    938         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
    939             log("sendStoredText: scAddr=" + scAddress + " messageUri=" + messageUri
    940                     + " sentIntent=" + sentIntent + " deliveryIntent=" + deliveryIntent);
    941         }
    942         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPkg)
    943                 != AppOpsManager.MODE_ALLOWED) {
    944             return;
    945         }
    946         final ContentResolver resolver = mPhone.getContext().getContentResolver();
    947         if (!isFailedOrDraft(resolver, messageUri)) {
    948             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredText: not FAILED or DRAFT message");
    949             returnUnspecifiedFailure(sentIntent);
    950             return;
    951         }
    952         final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
    953         if (textAndAddress == null) {
    954             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredText: can not load text");
    955             returnUnspecifiedFailure(sentIntent);
    956             return;
    957         }
    958         textAndAddress[1] = filterDestAddress(textAndAddress[1]);
    959         mDispatcher.sendText(textAndAddress[1], scAddress, textAndAddress[0],
    960                 sentIntent, deliveryIntent, messageUri, callingPkg,
    961                 true /* persistMessageForNonDefaultSmsApp */);
    962     }
    963 
    964     public void sendStoredMultipartText(String callingPkg, Uri messageUri, String scAddress,
    965             List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
    966         mPhone.getContext().enforceCallingPermission(Manifest.permission.SEND_SMS,
    967                 "Sending SMS message");
    968         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPkg)
    969                 != AppOpsManager.MODE_ALLOWED) {
    970             return;
    971         }
    972         final ContentResolver resolver = mPhone.getContext().getContentResolver();
    973         if (!isFailedOrDraft(resolver, messageUri)) {
    974             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: "
    975                     + "not FAILED or DRAFT message");
    976             returnUnspecifiedFailure(sentIntents);
    977             return;
    978         }
    979         final String[] textAndAddress = loadTextAndAddress(resolver, messageUri);
    980         if (textAndAddress == null) {
    981             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: can not load text");
    982             returnUnspecifiedFailure(sentIntents);
    983             return;
    984         }
    985         final ArrayList<String> parts = SmsManager.getDefault().divideMessage(textAndAddress[0]);
    986         if (parts == null || parts.size() < 1) {
    987             Log.e(LOG_TAG, "[IccSmsInterfaceManager]sendStoredMultipartText: can not divide text");
    988             returnUnspecifiedFailure(sentIntents);
    989             return;
    990         }
    991 
    992         textAndAddress[1] = filterDestAddress(textAndAddress[1]);
    993 
    994         if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
    995             for (int i = 0; i < parts.size(); i++) {
    996                 // If EMS is not supported, we have to break down EMS into single segment SMS
    997                 // and add page info " x/y".
    998                 String singlePart = parts.get(i);
    999                 if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
   1000                     singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
   1001                 } else {
   1002                     singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size());
   1003                 }
   1004 
   1005                 PendingIntent singleSentIntent = null;
   1006                 if (sentIntents != null && sentIntents.size() > i) {
   1007                     singleSentIntent = sentIntents.get(i);
   1008                 }
   1009 
   1010                 PendingIntent singleDeliveryIntent = null;
   1011                 if (deliveryIntents != null && deliveryIntents.size() > i) {
   1012                     singleDeliveryIntent = deliveryIntents.get(i);
   1013                 }
   1014 
   1015                 mDispatcher.sendText(textAndAddress[1], scAddress, singlePart,
   1016                         singleSentIntent, singleDeliveryIntent, messageUri, callingPkg,
   1017                         true  /* persistMessageForNonDefaultSmsApp */);
   1018             }
   1019             return;
   1020         }
   1021 
   1022         mDispatcher.sendMultipartText(
   1023                 textAndAddress[1], // destAddress
   1024                 scAddress,
   1025                 parts,
   1026                 (ArrayList<PendingIntent>) sentIntents,
   1027                 (ArrayList<PendingIntent>) deliveryIntents,
   1028                 messageUri,
   1029                 callingPkg,
   1030                 true  /* persistMessageForNonDefaultSmsApp */);
   1031     }
   1032 
   1033     private boolean isFailedOrDraft(ContentResolver resolver, Uri messageUri) {
   1034         // Clear the calling identity and query the database using the phone user id
   1035         // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
   1036         // between the calling uid and the package uid
   1037         final long identity = Binder.clearCallingIdentity();
   1038         Cursor cursor = null;
   1039         try {
   1040             cursor = resolver.query(
   1041                     messageUri,
   1042                     new String[]{ Telephony.Sms.TYPE },
   1043                     null/*selection*/,
   1044                     null/*selectionArgs*/,
   1045                     null/*sortOrder*/);
   1046             if (cursor != null && cursor.moveToFirst()) {
   1047                 final int type = cursor.getInt(0);
   1048                 return type == Telephony.Sms.MESSAGE_TYPE_DRAFT
   1049                         || type == Telephony.Sms.MESSAGE_TYPE_FAILED;
   1050             }
   1051         } catch (SQLiteException e) {
   1052             Log.e(LOG_TAG, "[IccSmsInterfaceManager]isFailedOrDraft: query message type failed", e);
   1053         } finally {
   1054             if (cursor != null) {
   1055                 cursor.close();
   1056             }
   1057             Binder.restoreCallingIdentity(identity);
   1058         }
   1059         return false;
   1060     }
   1061 
   1062     // Return an array including both the SMS text (0) and address (1)
   1063     private String[] loadTextAndAddress(ContentResolver resolver, Uri messageUri) {
   1064         // Clear the calling identity and query the database using the phone user id
   1065         // Otherwise the AppOps check in TelephonyProvider would complain about mismatch
   1066         // between the calling uid and the package uid
   1067         final long identity = Binder.clearCallingIdentity();
   1068         Cursor cursor = null;
   1069         try {
   1070             cursor = resolver.query(
   1071                     messageUri,
   1072                     new String[]{
   1073                             Telephony.Sms.BODY,
   1074                             Telephony.Sms.ADDRESS
   1075                     },
   1076                     null/*selection*/,
   1077                     null/*selectionArgs*/,
   1078                     null/*sortOrder*/);
   1079             if (cursor != null && cursor.moveToFirst()) {
   1080                 return new String[]{ cursor.getString(0), cursor.getString(1) };
   1081             }
   1082         } catch (SQLiteException e) {
   1083             Log.e(LOG_TAG, "[IccSmsInterfaceManager]loadText: query message text failed", e);
   1084         } finally {
   1085             if (cursor != null) {
   1086                 cursor.close();
   1087             }
   1088             Binder.restoreCallingIdentity(identity);
   1089         }
   1090         return null;
   1091     }
   1092 
   1093     private void returnUnspecifiedFailure(PendingIntent pi) {
   1094         if (pi != null) {
   1095             try {
   1096                 pi.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
   1097             } catch (PendingIntent.CanceledException e) {
   1098                 // ignore
   1099             }
   1100         }
   1101     }
   1102 
   1103     private void returnUnspecifiedFailure(List<PendingIntent> pis) {
   1104         if (pis == null) {
   1105             return;
   1106         }
   1107         for (PendingIntent pi : pis) {
   1108             returnUnspecifiedFailure(pi);
   1109         }
   1110     }
   1111 
   1112     private void enforceCarrierPrivilege() {
   1113         UiccController controller = UiccController.getInstance();
   1114         if (controller == null || controller.getUiccCard(mPhone.getPhoneId()) == null) {
   1115             throw new SecurityException("No Carrier Privilege: No UICC");
   1116         }
   1117         if (controller.getUiccCard(mPhone.getPhoneId()).getCarrierPrivilegeStatusForCurrentTransaction(
   1118                 mContext.getPackageManager()) !=
   1119                     TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
   1120             throw new SecurityException("No Carrier Privilege.");
   1121         }
   1122     }
   1123 
   1124     private String filterDestAddress(String destAddr) {
   1125         String result  = null;
   1126         result = SmsNumberUtils.filterDestAddr(mPhone, destAddr);
   1127         return result != null ? result : destAddr;
   1128     }
   1129 
   1130 }
   1131