Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2006 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 static android.Manifest.permission.SEND_SMS_NO_CONFIRMATION;
     20 import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PERIOD_NOT_SPECIFIED;
     21 import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PRIORITY_NOT_SPECIFIED;
     22 import static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
     23 import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
     24 import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
     25 import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
     26 import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
     27 import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
     28 import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED;
     29 import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED;
     30 
     31 import android.annotation.Nullable;
     32 import android.annotation.UserIdInt;
     33 import android.app.Activity;
     34 import android.app.AlertDialog;
     35 import android.app.PendingIntent;
     36 import android.app.PendingIntent.CanceledException;
     37 import android.content.ContentResolver;
     38 import android.content.ContentValues;
     39 import android.content.Context;
     40 import android.content.DialogInterface;
     41 import android.content.Intent;
     42 import android.content.pm.ApplicationInfo;
     43 import android.content.pm.PackageInfo;
     44 import android.content.pm.PackageManager;
     45 import android.content.res.Resources;
     46 import android.database.ContentObserver;
     47 import android.database.sqlite.SqliteWrapper;
     48 import android.net.Uri;
     49 import android.os.AsyncResult;
     50 import android.os.Binder;
     51 import android.os.Handler;
     52 import android.os.Message;
     53 import android.os.Process;
     54 import android.os.RemoteException;
     55 import android.os.UserHandle;
     56 import android.provider.Settings;
     57 import android.provider.Telephony;
     58 import android.provider.Telephony.Sms;
     59 import android.service.carrier.CarrierMessagingService;
     60 import android.service.carrier.ICarrierMessagingCallback;
     61 import android.service.carrier.ICarrierMessagingService;
     62 import android.telephony.CarrierMessagingServiceManager;
     63 import android.telephony.PhoneNumberUtils;
     64 import android.telephony.Rlog;
     65 import android.telephony.ServiceState;
     66 import android.telephony.SmsManager;
     67 import android.telephony.TelephonyManager;
     68 import android.text.Html;
     69 import android.text.Spanned;
     70 import android.text.TextUtils;
     71 import android.util.EventLog;
     72 import android.view.LayoutInflater;
     73 import android.view.View;
     74 import android.view.ViewGroup;
     75 import android.view.WindowManager;
     76 import android.widget.Button;
     77 import android.widget.CheckBox;
     78 import android.widget.CompoundButton;
     79 import android.widget.TextView;
     80 
     81 import com.android.internal.R;
     82 import com.android.internal.annotations.VisibleForTesting;
     83 import com.android.internal.telephony.cdma.sms.UserData;
     84 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
     85 import com.android.internal.telephony.uicc.UiccCard;
     86 import com.android.internal.telephony.uicc.UiccController;
     87 
     88 import java.util.ArrayList;
     89 import java.util.HashMap;
     90 import java.util.List;
     91 import java.util.Random;
     92 import java.util.concurrent.atomic.AtomicBoolean;
     93 import java.util.concurrent.atomic.AtomicInteger;
     94 
     95 public abstract class SMSDispatcher extends Handler {
     96     static final String TAG = "SMSDispatcher";    // accessed from inner class
     97     static final boolean DBG = false;
     98     private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
     99     protected static final String MAP_KEY_PDU = "pdu";
    100     protected static final String MAP_KEY_SMSC = "smsc";
    101     protected static final String MAP_KEY_DEST_ADDR = "destAddr";
    102     protected static final String MAP_KEY_SC_ADDR = "scAddr";
    103     protected static final String MAP_KEY_DEST_PORT = "destPort";
    104     protected static final String MAP_KEY_DATA = "data";
    105     protected static final String MAP_KEY_TEXT = "text";
    106 
    107     private static final int PREMIUM_RULE_USE_SIM = 1;
    108     private static final int PREMIUM_RULE_USE_NETWORK = 2;
    109     private static final int PREMIUM_RULE_USE_BOTH = 3;
    110     private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
    111     private final SettingsObserver mSettingsObserver;
    112 
    113     /** SMS send complete. */
    114     protected static final int EVENT_SEND_SMS_COMPLETE = 2;
    115 
    116     /** Retry sending a previously failed SMS message */
    117     private static final int EVENT_SEND_RETRY = 3;
    118 
    119     /** Confirmation required for sending a large number of messages. */
    120     private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
    121 
    122     /** Send the user confirmed SMS */
    123     static final int EVENT_SEND_CONFIRMED_SMS = 5;  // accessed from inner class
    124 
    125     /** Don't send SMS (user did not confirm). */
    126     static final int EVENT_STOP_SENDING = 7;        // accessed from inner class
    127 
    128     /** Confirmation required for third-party apps sending to an SMS short code. */
    129     private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
    130 
    131     /** Confirmation required for third-party apps sending to an SMS short code. */
    132     private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
    133 
    134     /** Handle status report from {@code CdmaInboundSmsHandler}. */
    135     protected static final int EVENT_HANDLE_STATUS_REPORT = 10;
    136 
    137     // other
    138     protected static final int EVENT_NEW_ICC_SMS = 14;
    139     protected static final int EVENT_ICC_CHANGED = 15;
    140     protected static final int EVENT_GET_IMS_SERVICE = 16;
    141 
    142 
    143     protected Phone mPhone;
    144     protected final Context mContext;
    145     protected final ContentResolver mResolver;
    146     protected final CommandsInterface mCi;
    147     protected final TelephonyManager mTelephonyManager;
    148 
    149     /** Maximum number of times to retry sending a failed SMS. */
    150     private static final int MAX_SEND_RETRIES = 3;
    151     /** Delay before next send attempt on a failed SMS, in milliseconds. */
    152     private static final int SEND_RETRY_DELAY = 2000;
    153     /** single part SMS */
    154     private static final int SINGLE_PART_SMS = 1;
    155     /** Message sending queue limit */
    156     private static final int MO_MSG_QUEUE_LIMIT = 5;
    157 
    158     /**
    159      * Message reference for a CONCATENATED_8_BIT_REFERENCE or
    160      * CONCATENATED_16_BIT_REFERENCE message set.  Should be
    161      * incremented for each set of concatenated messages.
    162      * Static field shared by all dispatcher objects.
    163      */
    164     private static int sConcatenatedRef = new Random().nextInt(256);
    165 
    166     protected SmsDispatchersController mSmsDispatchersController;
    167 
    168     /** Number of outgoing SmsTrackers waiting for user confirmation. */
    169     private int mPendingTrackerCount;
    170 
    171     /* Flags indicating whether the current device allows sms service */
    172     protected boolean mSmsCapable = true;
    173     protected boolean mSmsSendDisabled;
    174 
    175     protected static int getNextConcatenatedRef() {
    176         sConcatenatedRef += 1;
    177         return sConcatenatedRef;
    178     }
    179 
    180     /**
    181      * Create a new SMS dispatcher.
    182      * @param phone the Phone to use
    183      */
    184     protected SMSDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) {
    185         mPhone = phone;
    186         mSmsDispatchersController = smsDispatchersController;
    187         mContext = phone.getContext();
    188         mResolver = mContext.getContentResolver();
    189         mCi = phone.mCi;
    190         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
    191         mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
    192         mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
    193                 Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
    194 
    195         mSmsCapable = mContext.getResources().getBoolean(
    196                 com.android.internal.R.bool.config_sms_capable);
    197         mSmsSendDisabled = !mTelephonyManager.getSmsSendCapableForPhone(
    198                 mPhone.getPhoneId(), mSmsCapable);
    199         Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
    200                 + " mSmsSendDisabled=" + mSmsSendDisabled);
    201     }
    202 
    203     /**
    204      * Observe the secure setting for updated premium sms determination rules
    205      */
    206     private static class SettingsObserver extends ContentObserver {
    207         private final AtomicInteger mPremiumSmsRule;
    208         private final Context mContext;
    209         SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
    210             super(handler);
    211             mPremiumSmsRule = premiumSmsRule;
    212             mContext = context;
    213             onChange(false); // load initial value;
    214         }
    215 
    216         @Override
    217         public void onChange(boolean selfChange) {
    218             mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
    219                     Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
    220         }
    221     }
    222 
    223     protected void updatePhoneObject(Phone phone) {
    224         mPhone = phone;
    225         Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() );
    226     }
    227 
    228     /** Unregister for incoming SMS events. */
    229     public void dispose() {
    230         mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
    231     }
    232 
    233     /**
    234      * The format of the message PDU in the associated broadcast intent.
    235      * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
    236      * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
    237      *
    238      * Note: All applications which handle incoming SMS messages by processing the
    239      * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
    240      * into the new methods in {@link android.telephony.SmsMessage} which take an
    241      * extra format parameter. This is required in order to correctly decode the PDU on
    242      * devices which require support for both 3GPP and 3GPP2 formats at the same time,
    243      * such as CDMA/LTE devices and GSM/CDMA world phones.
    244      *
    245      * @return the format of the message PDU
    246      */
    247     protected abstract String getFormat();
    248 
    249     /**
    250      * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports
    251      * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}.
    252      * @param o the SmsMessage containing the status report
    253      */
    254     protected void handleStatusReport(Object o) {
    255         Rlog.d(TAG, "handleStatusReport() called with no subclass.");
    256     }
    257 
    258     /* TODO: Need to figure out how to keep track of status report routing in a
    259      *       persistent manner. If the phone process restarts (reboot or crash),
    260      *       we will lose this list and any status reports that come in after
    261      *       will be dropped.
    262      */
    263     /** Sent messages awaiting a delivery status report. */
    264     protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
    265 
    266     /**
    267      * Handles events coming from the phone stack. Overridden from handler.
    268      *
    269      * @param msg the message to handle
    270      */
    271     @Override
    272     public void handleMessage(Message msg) {
    273         switch (msg.what) {
    274         case EVENT_SEND_SMS_COMPLETE:
    275             // An outbound SMS has been successfully transferred, or failed.
    276             handleSendComplete((AsyncResult) msg.obj);
    277             break;
    278 
    279         case EVENT_SEND_RETRY:
    280             Rlog.d(TAG, "SMS retry..");
    281             sendRetrySms((SmsTracker) msg.obj);
    282             break;
    283 
    284         case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
    285             handleReachSentLimit((SmsTracker)(msg.obj));
    286             break;
    287 
    288         case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
    289             handleConfirmShortCode(false, (SmsTracker)(msg.obj));
    290             break;
    291 
    292         case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
    293             handleConfirmShortCode(true, (SmsTracker)(msg.obj));
    294             break;
    295 
    296         case EVENT_SEND_CONFIRMED_SMS:
    297         {
    298             SmsTracker tracker = (SmsTracker) msg.obj;
    299             if (tracker.isMultipart()) {
    300                 sendMultipartSms(tracker);
    301             } else {
    302                 if (mPendingTrackerCount > 1) {
    303                     tracker.mExpectMore = true;
    304                 } else {
    305                     tracker.mExpectMore = false;
    306                 }
    307                 sendSms(tracker);
    308             }
    309             mPendingTrackerCount--;
    310             break;
    311         }
    312 
    313         case EVENT_STOP_SENDING:
    314         {
    315             SmsTracker tracker = (SmsTracker) msg.obj;
    316             if (msg.arg1 == ConfirmDialogListener.SHORT_CODE_MSG) {
    317                 if (msg.arg2 == ConfirmDialogListener.NEVER_ALLOW) {
    318                     tracker.onFailed(mContext,
    319                             RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, 0/*errorCode*/);
    320                     Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
    321                             + "sending SHORT_CODE_NEVER_ALLOWED error code.");
    322                 } else {
    323                     tracker.onFailed(mContext,
    324                             RESULT_ERROR_SHORT_CODE_NOT_ALLOWED, 0/*errorCode*/);
    325                     Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
    326                             + "sending SHORT_CODE_NOT_ALLOWED error code.");
    327                 }
    328             } else if (msg.arg1 == ConfirmDialogListener.RATE_LIMIT) {
    329                 tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
    330                 Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
    331                         + "sending LIMIT_EXCEEDED error code.");
    332             } else {
    333                 Rlog.e(TAG, "SMSDispatcher: EVENT_STOP_SENDING - unexpected cases.");
    334             }
    335             mPendingTrackerCount--;
    336             break;
    337         }
    338 
    339         case EVENT_HANDLE_STATUS_REPORT:
    340             handleStatusReport(msg.obj);
    341             break;
    342 
    343         default:
    344             Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
    345         }
    346     }
    347 
    348     /**
    349      * Use the carrier messaging service to send a data or text SMS.
    350      */
    351     protected abstract class SmsSender extends CarrierMessagingServiceManager {
    352         protected final SmsTracker mTracker;
    353         // Initialized in sendSmsByCarrierApp
    354         protected volatile SmsSenderCallback mSenderCallback;
    355 
    356         protected SmsSender(SmsTracker tracker) {
    357             mTracker = tracker;
    358         }
    359 
    360         public void sendSmsByCarrierApp(String carrierPackageName,
    361                                         SmsSenderCallback senderCallback) {
    362             mSenderCallback = senderCallback;
    363             if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
    364                 Rlog.e(TAG, "bindService() for carrier messaging service failed");
    365                 mSenderCallback.onSendSmsComplete(
    366                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
    367                         0 /* messageRef */);
    368             } else {
    369                 Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
    370             }
    371         }
    372     }
    373 
    374     private static int getSendSmsFlag(@Nullable PendingIntent deliveryIntent) {
    375         if (deliveryIntent == null) {
    376             return 0;
    377         }
    378         return CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS;
    379     }
    380 
    381     /**
    382      * Use the carrier messaging service to send a text SMS.
    383      */
    384     protected final class TextSmsSender extends SmsSender {
    385         public TextSmsSender(SmsTracker tracker) {
    386             super(tracker);
    387         }
    388 
    389         @Override
    390         protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
    391             HashMap<String, Object> map = mTracker.getData();
    392             String text = (String) map.get(MAP_KEY_TEXT);
    393 
    394             if (text != null) {
    395                 try {
    396                     carrierMessagingService.sendTextSms(text, getSubId(),
    397                             mTracker.mDestAddress, getSendSmsFlag(mTracker.mDeliveryIntent),
    398                             mSenderCallback);
    399                 } catch (RemoteException e) {
    400                     Rlog.e(TAG, "Exception sending the SMS: " + e);
    401                     mSenderCallback.onSendSmsComplete(
    402                             CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
    403                             0 /* messageRef */);
    404                 }
    405             } else {
    406                 mSenderCallback.onSendSmsComplete(
    407                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
    408                         0 /* messageRef */);
    409             }
    410         }
    411     }
    412 
    413     /**
    414      * Use the carrier messaging service to send a data SMS.
    415      */
    416     protected final class DataSmsSender extends SmsSender {
    417         public DataSmsSender(SmsTracker tracker) {
    418             super(tracker);
    419         }
    420 
    421         @Override
    422         protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
    423             HashMap<String, Object> map = mTracker.getData();
    424             byte[] data = (byte[]) map.get(MAP_KEY_DATA);
    425             int destPort = (int) map.get(MAP_KEY_DEST_PORT);
    426 
    427             if (data != null) {
    428                 try {
    429                     carrierMessagingService.sendDataSms(data, getSubId(),
    430                             mTracker.mDestAddress, destPort,
    431                             getSendSmsFlag(mTracker.mDeliveryIntent), mSenderCallback);
    432                 } catch (RemoteException e) {
    433                     Rlog.e(TAG, "Exception sending the SMS: " + e);
    434                     mSenderCallback.onSendSmsComplete(
    435                             CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
    436                             0 /* messageRef */);
    437                 }
    438             } else {
    439                 mSenderCallback.onSendSmsComplete(
    440                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
    441                         0 /* messageRef */);
    442             }
    443         }
    444     }
    445 
    446     /**
    447      * Callback for TextSmsSender and DataSmsSender from the carrier messaging service.
    448      * Once the result is ready, the carrier messaging service connection is disposed.
    449      */
    450     protected final class SmsSenderCallback extends ICarrierMessagingCallback.Stub {
    451         private final SmsSender mSmsSender;
    452 
    453         public SmsSenderCallback(SmsSender smsSender) {
    454             mSmsSender = smsSender;
    455         }
    456 
    457         /**
    458          * This method should be called only once.
    459          */
    460         @Override
    461         public void onSendSmsComplete(int result, int messageRef) {
    462             checkCallerIsPhoneOrCarrierApp();
    463             final long identity = Binder.clearCallingIdentity();
    464             try {
    465                 mSmsSender.disposeConnection(mContext);
    466                 processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
    467             } finally {
    468                 Binder.restoreCallingIdentity(identity);
    469             }
    470         }
    471 
    472         @Override
    473         public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
    474             Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result);
    475         }
    476 
    477         @Override
    478         public void onFilterComplete(int result) {
    479             Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
    480         }
    481 
    482         @Override
    483         public void onSendMmsComplete(int result, byte[] sendConfPdu) {
    484             Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
    485         }
    486 
    487         @Override
    488         public void onDownloadMmsComplete(int result) {
    489             Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
    490         }
    491     }
    492 
    493     private void processSendSmsResponse(SmsTracker tracker, int result, int messageRef) {
    494         if (tracker == null) {
    495             Rlog.e(TAG, "processSendSmsResponse: null tracker");
    496             return;
    497         }
    498 
    499         SmsResponse smsResponse = new SmsResponse(
    500                 messageRef, null /* ackPdu */, -1 /* unknown error code */);
    501 
    502         switch (result) {
    503         case CarrierMessagingService.SEND_STATUS_OK:
    504             Rlog.d(TAG, "Sending SMS by IP succeeded.");
    505             sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
    506                                       new AsyncResult(tracker,
    507                                                       smsResponse,
    508                                                       null /* exception*/ )));
    509             break;
    510         case CarrierMessagingService.SEND_STATUS_ERROR:
    511             Rlog.d(TAG, "Sending SMS by IP failed.");
    512             sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
    513                     new AsyncResult(tracker, smsResponse,
    514                             new CommandException(CommandException.Error.GENERIC_FAILURE))));
    515             break;
    516         case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
    517             Rlog.d(TAG, "Sending SMS by IP failed. Retry on carrier network.");
    518             sendSubmitPdu(tracker);
    519             break;
    520         default:
    521             Rlog.d(TAG, "Unknown result " + result + " Retry on carrier network.");
    522             sendSubmitPdu(tracker);
    523         }
    524     }
    525 
    526     /**
    527      * Use the carrier messaging service to send a multipart text SMS.
    528      */
    529     private final class MultipartSmsSender extends CarrierMessagingServiceManager {
    530         private final List<String> mParts;
    531         public final SmsTracker[] mTrackers;
    532         // Initialized in sendSmsByCarrierApp
    533         private volatile MultipartSmsSenderCallback mSenderCallback;
    534 
    535         MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) {
    536             mParts = parts;
    537             mTrackers = trackers;
    538         }
    539 
    540         void sendSmsByCarrierApp(String carrierPackageName,
    541                                  MultipartSmsSenderCallback senderCallback) {
    542             mSenderCallback = senderCallback;
    543             if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
    544                 Rlog.e(TAG, "bindService() for carrier messaging service failed");
    545                 mSenderCallback.onSendMultipartSmsComplete(
    546                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
    547                         null /* smsResponse */);
    548             } else {
    549                 Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
    550             }
    551         }
    552 
    553         @Override
    554         protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
    555             try {
    556                 carrierMessagingService.sendMultipartTextSms(
    557                         mParts, getSubId(), mTrackers[0].mDestAddress,
    558                         getSendSmsFlag(mTrackers[0].mDeliveryIntent), mSenderCallback);
    559             } catch (RemoteException e) {
    560                 Rlog.e(TAG, "Exception sending the SMS: " + e);
    561                 mSenderCallback.onSendMultipartSmsComplete(
    562                         CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
    563                         null /* smsResponse */);
    564             }
    565         }
    566     }
    567 
    568     /**
    569      * Callback for MultipartSmsSender from the carrier messaging service.
    570      * Once the result is ready, the carrier messaging service connection is disposed.
    571      */
    572     private final class MultipartSmsSenderCallback extends ICarrierMessagingCallback.Stub {
    573         private final MultipartSmsSender mSmsSender;
    574 
    575         MultipartSmsSenderCallback(MultipartSmsSender smsSender) {
    576             mSmsSender = smsSender;
    577         }
    578 
    579         @Override
    580         public void onSendSmsComplete(int result, int messageRef) {
    581             Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result);
    582         }
    583 
    584         /**
    585          * This method should be called only once.
    586          */
    587         @Override
    588         public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
    589             mSmsSender.disposeConnection(mContext);
    590 
    591             if (mSmsSender.mTrackers == null) {
    592                 Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers.");
    593                 return;
    594             }
    595 
    596             checkCallerIsPhoneOrCarrierApp();
    597             final long identity = Binder.clearCallingIdentity();
    598             try {
    599                 for (int i = 0; i < mSmsSender.mTrackers.length; i++) {
    600                     int messageRef = 0;
    601                     if (messageRefs != null && messageRefs.length > i) {
    602                         messageRef = messageRefs[i];
    603                     }
    604                     processSendSmsResponse(mSmsSender.mTrackers[i], result, messageRef);
    605                 }
    606             } finally {
    607                 Binder.restoreCallingIdentity(identity);
    608             }
    609         }
    610 
    611         @Override
    612         public void onFilterComplete(int result) {
    613             Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
    614         }
    615 
    616         @Override
    617         public void onSendMmsComplete(int result, byte[] sendConfPdu) {
    618             Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
    619         }
    620 
    621         @Override
    622         public void onDownloadMmsComplete(int result) {
    623             Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
    624         }
    625     }
    626 
    627     /**
    628      * Send an SMS PDU. Usually just calls {@link sendRawPdu}.
    629      */
    630     private void sendSubmitPdu(SmsTracker tracker) {
    631         if (shouldBlockSmsForEcbm()) {
    632             Rlog.d(TAG, "Block SMS in Emergency Callback mode");
    633             tracker.onFailed(mContext, SmsManager.RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
    634         } else {
    635             sendRawPdu(tracker);
    636         }
    637     }
    638 
    639     /**
    640      * @return true if MO SMS should be blocked for Emergency Callback Mode.
    641      */
    642     protected abstract boolean shouldBlockSmsForEcbm();
    643 
    644     /**
    645      * Called when SMS send completes. Broadcasts a sentIntent on success.
    646      * On failure, either sets up retries or broadcasts a sentIntent with
    647      * the failure in the result code.
    648      *
    649      * @param ar AsyncResult passed into the message handler.  ar.result should
    650      *           an SmsResponse instance if send was successful.  ar.userObj
    651      *           should be an SmsTracker instance.
    652      */
    653     protected void handleSendComplete(AsyncResult ar) {
    654         SmsTracker tracker = (SmsTracker) ar.userObj;
    655         PendingIntent sentIntent = tracker.mSentIntent;
    656 
    657         if (ar.result != null) {
    658             tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
    659         } else {
    660             Rlog.d(TAG, "SmsResponse was null");
    661         }
    662 
    663         if (ar.exception == null) {
    664             if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
    665 
    666             if (tracker.mDeliveryIntent != null) {
    667                 // Expecting a status report.  Add it to the list.
    668                 deliveryPendingList.add(tracker);
    669             }
    670             tracker.onSent(mContext);
    671         } else {
    672             if (DBG) Rlog.d(TAG, "SMS send failed");
    673 
    674             int ss = mPhone.getServiceState().getState();
    675 
    676             if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
    677                 // This is retry after failure over IMS but voice is not available.
    678                 // Set retry to max allowed, so no retry is sent and
    679                 //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.
    680                 tracker.mRetryCount = MAX_SEND_RETRIES;
    681 
    682                 Rlog.d(TAG, "handleSendComplete: Skipping retry: "
    683                 +" isIms()="+isIms()
    684                 +" mRetryCount="+tracker.mRetryCount
    685                 +" mImsRetry="+tracker.mImsRetry
    686                 +" mMessageRef="+tracker.mMessageRef
    687                 +" SS= "+mPhone.getServiceState().getState());
    688             }
    689 
    690             // if sms over IMS is not supported on data and voice is not available...
    691             if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
    692                 tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
    693             } else if ((((CommandException)(ar.exception)).getCommandError()
    694                     == CommandException.Error.SMS_FAIL_RETRY) &&
    695                    tracker.mRetryCount < MAX_SEND_RETRIES) {
    696                 // Retry after a delay if needed.
    697                 // TODO: According to TS 23.040, 9.2.3.6, we should resend
    698                 //       with the same TP-MR as the failed message, and
    699                 //       TP-RD set to 1.  However, we don't have a means of
    700                 //       knowing the MR for the failed message (EF_SMSstatus
    701                 //       may or may not have the MR corresponding to this
    702                 //       message, depending on the failure).  Also, in some
    703                 //       implementations this retry is handled by the baseband.
    704                 tracker.mRetryCount++;
    705                 Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
    706                 sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
    707             } else {
    708                 int errorCode = 0;
    709                 if (ar.result != null) {
    710                     errorCode = ((SmsResponse)ar.result).mErrorCode;
    711                 }
    712                 int error = RESULT_ERROR_GENERIC_FAILURE;
    713                 if (((CommandException)(ar.exception)).getCommandError()
    714                         == CommandException.Error.FDN_CHECK_FAILURE) {
    715                     error = RESULT_ERROR_FDN_CHECK_FAILURE;
    716                 }
    717                 tracker.onFailed(mContext, error, errorCode);
    718             }
    719         }
    720     }
    721 
    722     /**
    723      * Handles outbound message when the phone is not in service.
    724      *
    725      * @param ss     Current service state.  Valid values are:
    726      *                  OUT_OF_SERVICE
    727      *                  EMERGENCY_ONLY
    728      *                  POWER_OFF
    729      * @param sentIntent the PendingIntent to send the error to
    730      */
    731     protected static void handleNotInService(int ss, PendingIntent sentIntent) {
    732         if (sentIntent != null) {
    733             try {
    734                 if (ss == ServiceState.STATE_POWER_OFF) {
    735                     sentIntent.send(RESULT_ERROR_RADIO_OFF);
    736                 } else {
    737                     sentIntent.send(RESULT_ERROR_NO_SERVICE);
    738                 }
    739             } catch (CanceledException ex) {
    740                 Rlog.e(TAG, "Failed to send result");
    741             }
    742         }
    743     }
    744 
    745     /**
    746      * @param ss service state
    747      * @return The result error based on input service state for not in service error
    748      */
    749     protected static int getNotInServiceError(int ss) {
    750         if (ss == ServiceState.STATE_POWER_OFF) {
    751             return RESULT_ERROR_RADIO_OFF;
    752         }
    753         return RESULT_ERROR_NO_SERVICE;
    754     }
    755 
    756     /**
    757      * Send a data based SMS to a specific application port.
    758      *
    759      * @param destAddr the address to send the message to
    760      * @param scAddr is the service center address or null to use
    761      *  the current default SMSC
    762      * @param destPort the port to deliver the message to
    763      * @param data the body of the message to send
    764      * @param sentIntent if not NULL this <code>PendingIntent</code> is
    765      *  broadcast when the message is successfully sent, or failed.
    766      *  The result code will be <code>Activity.RESULT_OK<code> for success,
    767      *  or one of these errors:<br>
    768      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
    769      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
    770      *  <code>RESULT_ERROR_NULL_PDU</code><br>
    771      *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
    772      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
    773      *  the extra "errorCode" containing a radio technology specific value,
    774      *  generally only useful for troubleshooting.<br>
    775      *  The per-application based SMS control checks sentIntent. If sentIntent
    776      *  is NULL the caller will be checked against all unknown applications,
    777      *  which cause smaller number of SMS to be sent in checking period.
    778      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
    779      *  broadcast when the message is delivered to the recipient.  The
    780      *  raw pdu of the status report is in the extended data ("pdu").
    781      */
    782     protected void sendData(String destAddr, String scAddr, int destPort,
    783             byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
    784         SmsMessageBase.SubmitPduBase pdu = getSubmitPdu(
    785                 scAddr, destAddr, destPort, data, (deliveryIntent != null));
    786         if (pdu != null) {
    787             HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
    788             SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
    789                     null /*messageUri*/, false /*expectMore*/,
    790                     null /*fullMessageText*/, false /*isText*/,
    791                     true /*persistMessage*/);
    792 
    793             if (!sendSmsByCarrierApp(true /* isDataSms */, tracker)) {
    794                 sendSubmitPdu(tracker);
    795             }
    796         } else {
    797             Rlog.e(TAG, "SMSDispatcher.sendData(): getSubmitPdu() returned null");
    798             triggerSentIntentForFailure(sentIntent);
    799         }
    800     }
    801 
    802     /**
    803      * Send a text based SMS.
    804      *  @param destAddr the address to send the message to
    805      * @param scAddr is the service center address or null to use
    806      *  the current default SMSC
    807      * @param text the body of the message to send
    808      * @param sentIntent if not NULL this <code>PendingIntent</code> is
    809      *  broadcast when the message is successfully sent, or failed.
    810      *  The result code will be <code>Activity.RESULT_OK<code> for success,
    811      *  or one of these errors:<br>
    812      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
    813      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
    814      *  <code>RESULT_ERROR_NULL_PDU</code><br>
    815      *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
    816      *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
    817      *  the extra "errorCode" containing a radio technology specific value,
    818      *  generally only useful for troubleshooting.<br>
    819      *  The per-application based SMS control checks sentIntent. If sentIntent
    820      *  is NULL the caller will be checked against all unknown applications,
    821      *  which cause smaller number of SMS to be sent in checking period.
    822      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
    823      *  broadcast when the message is delivered to the recipient.  The
    824      * @param messageUri optional URI of the message if it is already stored in the system
    825      * @param callingPkg the calling package name
    826      * @param persistMessage whether to save the sent message into SMS DB for a
    827      *   non-default SMS app.
    828      *
    829      * @param priority Priority level of the message
    830      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
    831      *  ---------------------------------
    832      *  PRIORITY      | Level of Priority
    833      *  ---------------------------------
    834      *      '00'      |     Normal
    835      *      '01'      |     Interactive
    836      *      '10'      |     Urgent
    837      *      '11'      |     Emergency
    838      *  ----------------------------------
    839      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
    840      * @param expectMore is a boolean to indicate the sending messages through same link or not.
    841      * @param validityPeriod Validity Period of the message in mins.
    842      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
    843      *  Validity Period(Minimum) -> 5 mins
    844      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
    845      *  Any Other values included Negative considered as Invalid Validity Period of the message.
    846      */
    847     public void sendText(String destAddr, String scAddr, String text,
    848                          PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri,
    849                          String callingPkg, boolean persistMessage, int priority,
    850                          boolean expectMore, int validityPeriod) {
    851         Rlog.d(TAG, "sendText");
    852         SmsMessageBase.SubmitPduBase pdu = getSubmitPdu(
    853                 scAddr, destAddr, text, (deliveryIntent != null), null, priority, validityPeriod);
    854         if (pdu != null) {
    855             HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
    856             SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
    857                     messageUri, expectMore, text, true /*isText*/,
    858                     persistMessage, priority, validityPeriod);
    859 
    860             if (!sendSmsByCarrierApp(false /* isDataSms */, tracker)) {
    861                 sendSubmitPdu(tracker);
    862             }
    863         } else {
    864             Rlog.e(TAG, "SmsDispatcher.sendText(): getSubmitPdu() returned null");
    865             triggerSentIntentForFailure(sentIntent);
    866         }
    867     }
    868 
    869     private void triggerSentIntentForFailure(PendingIntent sentIntent) {
    870         if (sentIntent != null) {
    871             try {
    872                 sentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
    873             } catch (CanceledException ex) {
    874                 Rlog.e(TAG, "Intent has been canceled!");
    875             }
    876         }
    877     }
    878 
    879     private boolean sendSmsByCarrierApp(boolean isDataSms, SmsTracker tracker ) {
    880         String carrierPackage = getCarrierAppPackageName();
    881         if (carrierPackage != null) {
    882             Rlog.d(TAG, "Found carrier package.");
    883             SmsSender smsSender;
    884             if (isDataSms) {
    885                 smsSender = new DataSmsSender(tracker);
    886             } else {
    887                 smsSender = new TextSmsSender(tracker);
    888             }
    889             smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
    890             return true;
    891         }
    892 
    893         return false;
    894     }
    895 
    896     protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr,
    897             String message, boolean statusReportRequested, SmsHeader smsHeader,
    898             int priority, int validityPeriod);
    899 
    900     protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr,
    901             int destPort, byte[] message, boolean statusReportRequested);
    902 
    903     /**
    904      * Calculate the number of septets needed to encode the message. This function should only be
    905      * called for individual segments of multipart message.
    906      *
    907      * @param messageBody the message to encode
    908      * @param use7bitOnly ignore (but still count) illegal characters if true
    909      * @return TextEncodingDetails
    910      */
    911     protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
    912             boolean use7bitOnly);
    913 
    914     /**
    915      * Send a multi-part text based SMS.
    916      *  @param destAddr the address to send the message to
    917      * @param scAddr is the service center address or null to use
    918      *   the current default SMSC
    919      * @param parts an <code>ArrayList</code> of strings that, in order,
    920      *   comprise the original message
    921      * @param sentIntents if not null, an <code>ArrayList</code> of
    922      *   <code>PendingIntent</code>s (one for each message part) that is
    923      *   broadcast when the corresponding message part has been sent.
    924      *   The result code will be <code>Activity.RESULT_OK<code> for success,
    925      *   or one of these errors:
    926      *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
    927      *   <code>RESULT_ERROR_RADIO_OFF</code>
    928      *   <code>RESULT_ERROR_NULL_PDU</code>
    929      *   <code>RESULT_ERROR_NO_SERVICE</code>.
    930      *  The per-application based SMS control checks sentIntent. If sentIntent
    931      *  is NULL the caller will be checked against all unknown applications,
    932      *  which cause smaller number of SMS to be sent in checking period.
    933      * @param deliveryIntents if not null, an <code>ArrayList</code> of
    934      *   <code>PendingIntent</code>s (one for each message part) that is
    935      *   broadcast when the corresponding message part has been delivered
    936      *   to the recipient.  The raw pdu of the status report is in the
    937      * @param messageUri optional URI of the message if it is already stored in the system
    938      * @param callingPkg the calling package name
    939      * @param persistMessage whether to save the sent message into SMS DB for a
    940      *   non-default SMS app.
    941      * @param priority Priority level of the message
    942      *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
    943      *  ---------------------------------
    944      *  PRIORITY      | Level of Priority
    945      *  ---------------------------------
    946      *      '00'      |     Normal
    947      *      '01'      |     Interactive
    948      *      '10'      |     Urgent
    949      *      '11'      |     Emergency
    950      *  ----------------------------------
    951      *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
    952      * @param expectMore is a boolean to indicate the sending messages through same link or not.
    953      * @param validityPeriod Validity Period of the message in mins.
    954      *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
    955      *  Validity Period(Minimum) -> 5 mins
    956      *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
    957      *  Any Other values included Negative considered as Invalid Validity Period of the message.
    958      */
    959     protected void sendMultipartText(String destAddr, String scAddr,
    960             ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
    961             ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
    962             boolean persistMessage, int priority, boolean expectMore, int validityPeriod) {
    963         final String fullMessageText = getMultipartMessageText(parts);
    964         int refNumber = getNextConcatenatedRef() & 0x00FF;
    965         int msgCount = parts.size();
    966         int encoding = SmsConstants.ENCODING_UNKNOWN;
    967 
    968         TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
    969         for (int i = 0; i < msgCount; i++) {
    970             TextEncodingDetails details = calculateLength(parts.get(i), false);
    971             if (encoding != details.codeUnitSize
    972                     && (encoding == SmsConstants.ENCODING_UNKNOWN
    973                             || encoding == SmsConstants.ENCODING_7BIT)) {
    974                 encoding = details.codeUnitSize;
    975             }
    976             encodingForParts[i] = details;
    977         }
    978 
    979         SmsTracker[] trackers = new SmsTracker[msgCount];
    980 
    981         // States to track at the message level (for all parts)
    982         final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
    983         final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
    984 
    985         for (int i = 0; i < msgCount; i++) {
    986             SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
    987             concatRef.refNumber = refNumber;
    988             concatRef.seqNumber = i + 1;  // 1-based sequence
    989             concatRef.msgCount = msgCount;
    990             // TODO: We currently set this to true since our messaging app will never
    991             // send more than 255 parts (it converts the message to MMS well before that).
    992             // However, we should support 3rd party messaging apps that might need 16-bit
    993             // references
    994             // Note:  It's not sufficient to just flip this bit to true; it will have
    995             // ripple effects (several calculations assume 8-bit ref).
    996             concatRef.isEightBits = true;
    997             SmsHeader smsHeader = new SmsHeader();
    998             smsHeader.concatRef = concatRef;
    999 
   1000             // Set the national language tables for 3GPP 7-bit encoding, if enabled.
   1001             if (encoding == SmsConstants.ENCODING_7BIT) {
   1002                 smsHeader.languageTable = encodingForParts[i].languageTable;
   1003                 smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
   1004             }
   1005 
   1006             PendingIntent sentIntent = null;
   1007             if (sentIntents != null && sentIntents.size() > i) {
   1008                 sentIntent = sentIntents.get(i);
   1009             }
   1010 
   1011             PendingIntent deliveryIntent = null;
   1012             if (deliveryIntents != null && deliveryIntents.size() > i) {
   1013                 deliveryIntent = deliveryIntents.get(i);
   1014             }
   1015 
   1016             trackers[i] =
   1017                 getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding,
   1018                         sentIntent, deliveryIntent, (i == (msgCount - 1)),
   1019                         unsentPartCount, anyPartFailed, messageUri,
   1020                         fullMessageText, priority, expectMore, validityPeriod);
   1021             trackers[i].mPersistMessage = persistMessage;
   1022         }
   1023 
   1024         if (parts == null || trackers == null || trackers.length == 0
   1025                 || trackers[0] == null) {
   1026             Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers);
   1027             return;
   1028         }
   1029 
   1030         String carrierPackage = getCarrierAppPackageName();
   1031         if (carrierPackage != null) {
   1032             Rlog.d(TAG, "Found carrier package.");
   1033             MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
   1034             smsSender.sendSmsByCarrierApp(carrierPackage,
   1035                     new MultipartSmsSenderCallback(smsSender));
   1036         } else {
   1037             Rlog.v(TAG, "No carrier package.");
   1038             for (SmsTracker tracker : trackers) {
   1039                 if (tracker != null) {
   1040                     sendSubmitPdu(tracker);
   1041                 } else {
   1042                     Rlog.e(TAG, "Null tracker.");
   1043                 }
   1044             }
   1045         }
   1046     }
   1047 
   1048     /**
   1049      * Create a new SubmitPdu and return the SMS tracker.
   1050      */
   1051     private SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
   1052             String message, SmsHeader smsHeader, int encoding,
   1053             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
   1054             AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
   1055             String fullMessageText, int priority, boolean expectMore, int validityPeriod) {
   1056         if (isCdmaMo()) {
   1057             UserData uData = new UserData();
   1058             uData.payloadStr = message;
   1059             uData.userDataHeader = smsHeader;
   1060             if (encoding == SmsConstants.ENCODING_7BIT) {
   1061                 uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
   1062             } else { // assume UTF-16
   1063                 uData.msgEncoding = UserData.ENCODING_UNICODE_16;
   1064             }
   1065             uData.msgEncodingSet = true;
   1066 
   1067             /* By setting the statusReportRequested bit only for the
   1068              * last message fragment, this will result in only one
   1069              * callback to the sender when that last fragment delivery
   1070              * has been acknowledged. */
   1071             //TODO FIX
   1072             SmsMessageBase.SubmitPduBase submitPdu =
   1073                     com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(destinationAddress,
   1074                             uData, (deliveryIntent != null) && lastPart, priority);
   1075 
   1076             HashMap map = getSmsTrackerMap(destinationAddress, scAddress,
   1077                     message, submitPdu);
   1078             return getSmsTracker(map, sentIntent, deliveryIntent,
   1079                     getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader,
   1080                     (!lastPart || expectMore), fullMessageText, true /*isText*/,
   1081                     true /*persistMessage*/, priority, validityPeriod);
   1082 
   1083         } else {
   1084             SmsMessageBase.SubmitPduBase pdu =
   1085                     com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
   1086                             destinationAddress, message, deliveryIntent != null,
   1087                             SmsHeader.toByteArray(smsHeader), encoding, smsHeader.languageTable,
   1088                             smsHeader.languageShiftTable, validityPeriod);
   1089             if (pdu != null) {
   1090                 HashMap map =  getSmsTrackerMap(destinationAddress, scAddress,
   1091                         message, pdu);
   1092                 return getSmsTracker(map, sentIntent,
   1093                         deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri,
   1094                         smsHeader, (!lastPart || expectMore), fullMessageText, true /*isText*/,
   1095                         false /*persistMessage*/, priority, validityPeriod);
   1096             } else {
   1097                 Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null");
   1098                 return null;
   1099             }
   1100         }
   1101     }
   1102 
   1103     /**
   1104      * Send an SMS
   1105      * @param tracker will contain:
   1106      * -smsc the SMSC to send the message through, or NULL for the
   1107      *  default SMSC
   1108      * -pdu the raw PDU to send
   1109      * -sentIntent if not NULL this <code>Intent</code> is
   1110      *  broadcast when the message is successfully sent, or failed.
   1111      *  The result code will be <code>Activity.RESULT_OK<code> for success,
   1112      *  or one of these errors:
   1113      *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
   1114      *  <code>RESULT_ERROR_RADIO_OFF</code>
   1115      *  <code>RESULT_ERROR_NULL_PDU</code>
   1116      *  <code>RESULT_ERROR_NO_SERVICE</code>.
   1117      *  The per-application based SMS control checks sentIntent. If sentIntent
   1118      *  is NULL the caller will be checked against all unknown applications,
   1119      *  which cause smaller number of SMS to be sent in checking period.
   1120      * -deliveryIntent if not NULL this <code>Intent</code> is
   1121      *  broadcast when the message is delivered to the recipient.  The
   1122      *  raw pdu of the status report is in the extended data ("pdu").
   1123      * -param destAddr the destination phone number (for short code confirmation)
   1124      */
   1125     @VisibleForTesting
   1126     public void sendRawPdu(SmsTracker tracker) {
   1127         HashMap map = tracker.getData();
   1128         byte pdu[] = (byte[]) map.get(MAP_KEY_PDU);
   1129 
   1130         if (mSmsSendDisabled) {
   1131             Rlog.e(TAG, "Device does not support sending sms.");
   1132             tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
   1133             return;
   1134         }
   1135 
   1136         if (pdu == null) {
   1137             Rlog.e(TAG, "Empty PDU");
   1138             tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);
   1139             return;
   1140         }
   1141 
   1142         // Get calling app package name via UID from Binder call
   1143         PackageManager pm = mContext.getPackageManager();
   1144         String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
   1145 
   1146         if (packageNames == null || packageNames.length == 0) {
   1147             // Refuse to send SMS if we can't get the calling package name.
   1148             Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");
   1149             tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
   1150             return;
   1151         }
   1152 
   1153         // Get package info via packagemanager
   1154         PackageInfo appInfo;
   1155         try {
   1156             // XXX this is lossy- apps can share a UID
   1157             appInfo = pm.getPackageInfoAsUser(
   1158                     packageNames[0], PackageManager.GET_SIGNATURES, tracker.mUserId);
   1159         } catch (PackageManager.NameNotFoundException e) {
   1160             Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
   1161             tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
   1162             return;
   1163         }
   1164 
   1165         // checkDestination() returns true if the destination is not a premium short code or the
   1166         // sending app is approved to send to short codes. Otherwise, a message is sent to our
   1167         // handler with the SmsTracker to request user confirmation before sending.
   1168         if (checkDestination(tracker)) {
   1169             // check for excessive outgoing SMS usage by this app
   1170             if (!mSmsDispatchersController.getUsageMonitor().check(
   1171                     appInfo.packageName, SINGLE_PART_SMS)) {
   1172                 sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
   1173                 return;
   1174             }
   1175 
   1176             sendSms(tracker);
   1177         }
   1178 
   1179         if (PhoneNumberUtils.isLocalEmergencyNumber(mContext, tracker.mDestAddress)) {
   1180             new AsyncEmergencyContactNotifier(mContext).execute();
   1181         }
   1182     }
   1183 
   1184     /**
   1185      * Check if destination is a potential premium short code and sender is not pre-approved to
   1186      * send to short codes.
   1187      *
   1188      * @param tracker the tracker for the SMS to send
   1189      * @return true if the destination is approved; false if user confirmation event was sent
   1190      */
   1191     boolean checkDestination(SmsTracker tracker) {
   1192         if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION)
   1193                 == PackageManager.PERMISSION_GRANTED) {
   1194             return true;            // app is pre-approved to send to short codes
   1195         } else {
   1196             int rule = mPremiumSmsRule.get();
   1197             int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
   1198             if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
   1199                 String simCountryIso = mTelephonyManager.getSimCountryIso();
   1200                 if (simCountryIso == null || simCountryIso.length() != 2) {
   1201                     Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso");
   1202                     simCountryIso = mTelephonyManager.getNetworkCountryIso();
   1203                 }
   1204 
   1205                 smsCategory = mSmsDispatchersController.getUsageMonitor().checkDestination(
   1206                         tracker.mDestAddress, simCountryIso);
   1207             }
   1208             if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
   1209                 String networkCountryIso = mTelephonyManager.getNetworkCountryIso();
   1210                 if (networkCountryIso == null || networkCountryIso.length() != 2) {
   1211                     Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso");
   1212                     networkCountryIso = mTelephonyManager.getSimCountryIso();
   1213                 }
   1214 
   1215                 smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory,
   1216                         mSmsDispatchersController.getUsageMonitor().checkDestination(
   1217                                 tracker.mDestAddress, networkCountryIso));
   1218             }
   1219 
   1220             if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE
   1221                     || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE
   1222                     || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) {
   1223                 return true;    // not a premium short code
   1224             }
   1225 
   1226             // Do not allow any premium sms during SuW
   1227             if (Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
   1228                 Rlog.e(TAG, "Can't send premium sms during Setup Wizard");
   1229                 return false;
   1230             }
   1231 
   1232             // Wait for user confirmation unless the user has set permission to always allow/deny
   1233             int premiumSmsPermission =
   1234                     mSmsDispatchersController.getUsageMonitor().getPremiumSmsPermission(
   1235                     tracker.getAppPackageName());
   1236             if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
   1237                 // First time trying to send to premium SMS.
   1238                 premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
   1239             }
   1240 
   1241             switch (premiumSmsPermission) {
   1242                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
   1243                     Rlog.d(TAG, "User approved this app to send to premium SMS");
   1244                     return true;
   1245 
   1246                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
   1247                     Rlog.w(TAG, "User denied this app from sending to premium SMS");
   1248                     Message msg = obtainMessage(EVENT_STOP_SENDING, tracker);
   1249                     msg.arg1 = ConfirmDialogListener.SHORT_CODE_MSG;
   1250                     msg.arg2 = ConfirmDialogListener.NEVER_ALLOW;
   1251                     sendMessage(msg);
   1252                     return false;   // reject this message
   1253 
   1254                 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
   1255                 default:
   1256                     int event;
   1257                     if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
   1258                         event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
   1259                     } else {
   1260                         event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
   1261                     }
   1262                     sendMessage(obtainMessage(event, tracker));
   1263                     return false;   // wait for user confirmation
   1264             }
   1265         }
   1266     }
   1267 
   1268     /**
   1269      * Deny sending an SMS if the outgoing queue limit is reached. Used when the message
   1270      * must be confirmed by the user due to excessive usage or potential premium SMS detected.
   1271      * @param tracker the SmsTracker for the message to send
   1272      * @return true if the message was denied; false to continue with send confirmation
   1273      */
   1274     private boolean denyIfQueueLimitReached(SmsTracker tracker) {
   1275         if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
   1276             // Deny sending message when the queue limit is reached.
   1277             Rlog.e(TAG, "Denied because queue limit reached");
   1278             tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
   1279             return true;
   1280         }
   1281         mPendingTrackerCount++;
   1282         return false;
   1283     }
   1284 
   1285     /**
   1286      * Returns the label for the specified app package name.
   1287      * @param appPackage the package name of the app requesting to send an SMS
   1288      * @return the label for the specified app, or the package name if getApplicationInfo() fails
   1289      */
   1290     private CharSequence getAppLabel(String appPackage, @UserIdInt int userId) {
   1291         PackageManager pm = mContext.getPackageManager();
   1292         try {
   1293             ApplicationInfo appInfo = pm.getApplicationInfoAsUser(appPackage, 0, userId);
   1294             return appInfo.loadSafeLabel(pm);
   1295         } catch (PackageManager.NameNotFoundException e) {
   1296             Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
   1297             return appPackage;  // fall back to package name if we can't get app label
   1298         }
   1299     }
   1300 
   1301     /**
   1302      * Post an alert when SMS needs confirmation due to excessive usage.
   1303      * @param tracker an SmsTracker for the current message.
   1304      */
   1305     protected void handleReachSentLimit(SmsTracker tracker) {
   1306         if (denyIfQueueLimitReached(tracker)) {
   1307             return;     // queue limit reached; error was returned to caller
   1308         }
   1309 
   1310         CharSequence appLabel = getAppLabel(tracker.getAppPackageName(), tracker.mUserId);
   1311         Resources r = Resources.getSystem();
   1312         Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
   1313 
   1314         // Construct ConfirmDialogListenter for Rate Limit handling
   1315         ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null,
   1316                 ConfirmDialogListener.RATE_LIMIT);
   1317 
   1318         AlertDialog d = new AlertDialog.Builder(mContext)
   1319                 .setTitle(R.string.sms_control_title)
   1320                 .setIcon(R.drawable.stat_sys_warning)
   1321                 .setMessage(messageText)
   1322                 .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
   1323                 .setNegativeButton(r.getString(R.string.sms_control_no), listener)
   1324                 .setOnCancelListener(listener)
   1325                 .create();
   1326 
   1327         d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   1328         d.show();
   1329     }
   1330 
   1331     /**
   1332      * Post an alert for user confirmation when sending to a potential short code.
   1333      * @param isPremium true if the destination is known to be a premium short code
   1334      * @param tracker the SmsTracker for the current message.
   1335      */
   1336     protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) {
   1337         if (denyIfQueueLimitReached(tracker)) {
   1338             return;     // queue limit reached; error was returned to caller
   1339         }
   1340 
   1341         int detailsId;
   1342         if (isPremium) {
   1343             detailsId = R.string.sms_premium_short_code_details;
   1344         } else {
   1345             detailsId = R.string.sms_short_code_details;
   1346         }
   1347 
   1348         CharSequence appLabel = getAppLabel(tracker.getAppPackageName(), tracker.mUserId);
   1349         Resources r = Resources.getSystem();
   1350         Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
   1351                 appLabel, tracker.mDestAddress));
   1352 
   1353         LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
   1354                 Context.LAYOUT_INFLATER_SERVICE);
   1355         View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
   1356 
   1357         // Construct ConfirmDialogListenter for short code message sending
   1358         ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
   1359                 (TextView) layout.findViewById(R.id.sms_short_code_remember_undo_instruction),
   1360                 ConfirmDialogListener.SHORT_CODE_MSG);
   1361 
   1362 
   1363         TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
   1364         messageView.setText(messageText);
   1365 
   1366         ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
   1367                 R.id.sms_short_code_detail_layout);
   1368         TextView detailsView = (TextView) detailsLayout.findViewById(
   1369                 R.id.sms_short_code_detail_message);
   1370         detailsView.setText(detailsId);
   1371 
   1372         CheckBox rememberChoice = (CheckBox) layout.findViewById(
   1373                 R.id.sms_short_code_remember_choice_checkbox);
   1374         rememberChoice.setOnCheckedChangeListener(listener);
   1375 
   1376         AlertDialog d = new AlertDialog.Builder(mContext)
   1377                 .setView(layout)
   1378                 .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
   1379                 .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
   1380                 .setOnCancelListener(listener)
   1381                 .create();
   1382 
   1383         d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
   1384         d.show();
   1385 
   1386         listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
   1387         listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
   1388     }
   1389 
   1390     /**
   1391      * Send the message along to the radio.
   1392      *
   1393      * @param tracker holds the SMS message to send
   1394      */
   1395     protected abstract void sendSms(SmsTracker tracker);
   1396 
   1397     /**
   1398      * Retry the message along to the radio.
   1399      *
   1400      * @param tracker holds the SMS message to send
   1401      */
   1402     public void sendRetrySms(SmsTracker tracker) {
   1403         // re-routing to SmsDispatchersController
   1404         if (mSmsDispatchersController != null) {
   1405             mSmsDispatchersController.sendRetrySms(tracker);
   1406         } else {
   1407             Rlog.e(TAG, mSmsDispatchersController + " is null. Retry failed");
   1408         }
   1409     }
   1410 
   1411     /**
   1412      * Send the multi-part SMS based on multipart Sms tracker
   1413      *
   1414      * @param tracker holds the multipart Sms tracker ready to be sent
   1415      */
   1416     private void sendMultipartSms(SmsTracker tracker) {
   1417         ArrayList<String> parts;
   1418         ArrayList<PendingIntent> sentIntents;
   1419         ArrayList<PendingIntent> deliveryIntents;
   1420 
   1421         HashMap<String, Object> map = tracker.getData();
   1422 
   1423         String destinationAddress = (String) map.get("destination");
   1424         String scAddress = (String) map.get("scaddress");
   1425 
   1426         parts = (ArrayList<String>) map.get("parts");
   1427         sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
   1428         deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
   1429 
   1430         // check if in service
   1431         int ss = mPhone.getServiceState().getState();
   1432         // if sms over IMS is not supported on data and voice is not available...
   1433         if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
   1434             for (int i = 0, count = parts.size(); i < count; i++) {
   1435                 PendingIntent sentIntent = null;
   1436                 if (sentIntents != null && sentIntents.size() > i) {
   1437                     sentIntent = sentIntents.get(i);
   1438                 }
   1439                 handleNotInService(ss, sentIntent);
   1440             }
   1441             return;
   1442         }
   1443 
   1444         sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents,
   1445                 null/*messageUri*/, null/*callingPkg*/, tracker.mPersistMessage, tracker.mPriority,
   1446                 tracker.mExpectMore, tracker.mValidityPeriod);
   1447     }
   1448 
   1449     /**
   1450      * Keeps track of an SMS that has been sent to the RIL, until it has
   1451      * successfully been sent, or we're done trying.
   1452      */
   1453     public static class SmsTracker {
   1454         // fields need to be public for derived SmsDispatchers
   1455         private final HashMap<String, Object> mData;
   1456         public int mRetryCount;
   1457         // IMS retry counter. Nonzero indicates initial message was sent over IMS channel in RIL and
   1458         // counts how many retries have been made on the IMS channel.
   1459         // Used in older implementations where the message is sent over IMS using the RIL.
   1460         public int mImsRetry;
   1461         // Tag indicating that this SMS is being handled by the ImsSmsDispatcher. This tracker
   1462         // should not try to use SMS over IMS over the RIL interface in this case when falling back.
   1463         public boolean mUsesImsServiceForIms;
   1464         public int mMessageRef;
   1465         public boolean mExpectMore;
   1466         public int mValidityPeriod;
   1467         public int mPriority;
   1468         String mFormat;
   1469 
   1470         public final PendingIntent mSentIntent;
   1471         public final PendingIntent mDeliveryIntent;
   1472 
   1473         public final PackageInfo mAppInfo;
   1474         public final String mDestAddress;
   1475 
   1476         public final SmsHeader mSmsHeader;
   1477 
   1478         private long mTimestamp = System.currentTimeMillis();
   1479         public Uri mMessageUri; // Uri of persisted message if we wrote one
   1480 
   1481         // Reference to states of a multipart message that this part belongs to
   1482         private AtomicInteger mUnsentPartCount;
   1483         private AtomicBoolean mAnyPartFailed;
   1484         // The full message content of a single part message
   1485         // or a multipart message that this part belongs to
   1486         private String mFullMessageText;
   1487 
   1488         private int mSubId;
   1489 
   1490         // If this is a text message (instead of data message)
   1491         private boolean mIsText;
   1492 
   1493         private boolean mPersistMessage;
   1494 
   1495         // User who sends the SMS.
   1496         private final @UserIdInt int mUserId;
   1497 
   1498         private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
   1499                 PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format,
   1500                 AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
   1501                 SmsHeader smsHeader, boolean expectMore, String fullMessageText, int subId,
   1502                 boolean isText, boolean persistMessage, int userId, int priority,
   1503                 int validityPeriod) {
   1504             mData = data;
   1505             mSentIntent = sentIntent;
   1506             mDeliveryIntent = deliveryIntent;
   1507             mRetryCount = 0;
   1508             mAppInfo = appInfo;
   1509             mDestAddress = destAddr;
   1510             mFormat = format;
   1511             mExpectMore = expectMore;
   1512             mImsRetry = 0;
   1513             mUsesImsServiceForIms = false;
   1514             mMessageRef = 0;
   1515             mUnsentPartCount = unsentPartCount;
   1516             mAnyPartFailed = anyPartFailed;
   1517             mMessageUri = messageUri;
   1518             mSmsHeader = smsHeader;
   1519             mFullMessageText = fullMessageText;
   1520             mSubId = subId;
   1521             mIsText = isText;
   1522             mPersistMessage = persistMessage;
   1523             mUserId = userId;
   1524             mPriority = priority;
   1525             mValidityPeriod = validityPeriod;
   1526         }
   1527 
   1528         /**
   1529          * Returns whether this tracker holds a multi-part SMS.
   1530          * @return true if the tracker holds a multi-part SMS; false otherwise
   1531          */
   1532         boolean isMultipart() {
   1533             return mData.containsKey("parts");
   1534         }
   1535 
   1536         public HashMap<String, Object> getData() {
   1537             return mData;
   1538         }
   1539 
   1540         /**
   1541          * Get the App package name
   1542          * @return App package name info
   1543          */
   1544         public String getAppPackageName() {
   1545             return mAppInfo != null ? mAppInfo.packageName : null;
   1546         }
   1547 
   1548         /**
   1549          * Update the status of this message if we persisted it
   1550          */
   1551         public void updateSentMessageStatus(Context context, int status) {
   1552             if (mMessageUri != null) {
   1553                 // If we wrote this message in writeSentMessage, update it now
   1554                 ContentValues values = new ContentValues(1);
   1555                 values.put(Sms.STATUS, status);
   1556                 SqliteWrapper.update(context, context.getContentResolver(),
   1557                         mMessageUri, values, null, null);
   1558             }
   1559         }
   1560 
   1561         /**
   1562          * Set the final state of a message: FAILED or SENT
   1563          *
   1564          * @param context The Context
   1565          * @param messageType The final message type
   1566          * @param errorCode The error code
   1567          */
   1568         private void updateMessageState(Context context, int messageType, int errorCode) {
   1569             if (mMessageUri == null) {
   1570                 return;
   1571             }
   1572             final ContentValues values = new ContentValues(2);
   1573             values.put(Sms.TYPE, messageType);
   1574             values.put(Sms.ERROR_CODE, errorCode);
   1575             final long identity = Binder.clearCallingIdentity();
   1576             try {
   1577                 if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
   1578                         null/*where*/, null/*selectionArgs*/) != 1) {
   1579                     Rlog.e(TAG, "Failed to move message to " + messageType);
   1580                 }
   1581             } finally {
   1582                 Binder.restoreCallingIdentity(identity);
   1583             }
   1584         }
   1585 
   1586         /**
   1587          * Persist a sent SMS if required:
   1588          * 1. It is a text message
   1589          * 2. SmsApplication tells us to persist: sent from apps that are not default-SMS app or
   1590          *    bluetooth
   1591          *
   1592          * @param context
   1593          * @param messageType The folder to store (FAILED or SENT)
   1594          * @param errorCode The current error code for this SMS or SMS part
   1595          * @return The telephony provider URI if stored
   1596          */
   1597         private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) {
   1598             if (!mIsText || !mPersistMessage ||
   1599                     !SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) {
   1600                 return null;
   1601             }
   1602             Rlog.d(TAG, "Persist SMS into "
   1603                     + (messageType == Sms.MESSAGE_TYPE_FAILED ? "FAILED" : "SENT"));
   1604             final ContentValues values = new ContentValues();
   1605             values.put(Sms.SUBSCRIPTION_ID, mSubId);
   1606             values.put(Sms.ADDRESS, mDestAddress);
   1607             values.put(Sms.BODY, mFullMessageText);
   1608             values.put(Sms.DATE, System.currentTimeMillis()); // milliseconds
   1609             values.put(Sms.SEEN, 1);
   1610             values.put(Sms.READ, 1);
   1611             final String creator = mAppInfo != null ? mAppInfo.packageName : null;
   1612             if (!TextUtils.isEmpty(creator)) {
   1613                 values.put(Sms.CREATOR, creator);
   1614             }
   1615             if (mDeliveryIntent != null) {
   1616                 values.put(Sms.STATUS, Telephony.Sms.STATUS_PENDING);
   1617             }
   1618             if (errorCode != 0) {
   1619                 values.put(Sms.ERROR_CODE, errorCode);
   1620             }
   1621             final long identity = Binder.clearCallingIdentity();
   1622             final ContentResolver resolver = context.getContentResolver();
   1623             try {
   1624                 final Uri uri =  resolver.insert(Telephony.Sms.Sent.CONTENT_URI, values);
   1625                 if (uri != null && messageType == Sms.MESSAGE_TYPE_FAILED) {
   1626                     // Since we can't persist a message directly into FAILED box,
   1627                     // we have to update the column after we persist it into SENT box.
   1628                     // The gap between the state change is tiny so I would not expect
   1629                     // it to cause any serious problem
   1630                     // TODO: we should add a "failed" URI for this in SmsProvider?
   1631                     final ContentValues updateValues = new ContentValues(1);
   1632                     updateValues.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
   1633                     resolver.update(uri, updateValues, null/*where*/, null/*selectionArgs*/);
   1634                 }
   1635                 return uri;
   1636             } catch (Exception e) {
   1637                 Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
   1638                 return null;
   1639             } finally {
   1640                 Binder.restoreCallingIdentity(identity);
   1641             }
   1642         }
   1643 
   1644         /**
   1645          * Persist or update an SMS depending on if we send a new message or a stored message
   1646          *
   1647          * @param context
   1648          * @param messageType The message folder for this SMS, FAILED or SENT
   1649          * @param errorCode The current error code for this SMS or SMS part
   1650          */
   1651         private void persistOrUpdateMessage(Context context, int messageType, int errorCode) {
   1652             if (mMessageUri != null) {
   1653                 updateMessageState(context, messageType, errorCode);
   1654             } else {
   1655                 mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode);
   1656             }
   1657         }
   1658 
   1659         /**
   1660          * Handle a failure of a single part message or a part of a multipart message
   1661          *
   1662          * @param context The Context
   1663          * @param error The error to send back with
   1664          * @param errorCode
   1665          */
   1666         public void onFailed(Context context, int error, int errorCode) {
   1667             if (mAnyPartFailed != null) {
   1668                 mAnyPartFailed.set(true);
   1669             }
   1670             // is single part or last part of multipart message
   1671             boolean isSinglePartOrLastPart = true;
   1672             if (mUnsentPartCount != null) {
   1673                 isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
   1674             }
   1675             if (isSinglePartOrLastPart) {
   1676                 persistOrUpdateMessage(context, Sms.MESSAGE_TYPE_FAILED, errorCode);
   1677             }
   1678             if (mSentIntent != null) {
   1679                 try {
   1680                     // Extra information to send with the sent intent
   1681                     Intent fillIn = new Intent();
   1682                     if (mMessageUri != null) {
   1683                         // Pass this to SMS apps so that they know where it is stored
   1684                         fillIn.putExtra("uri", mMessageUri.toString());
   1685                     }
   1686                     if (errorCode != 0) {
   1687                         fillIn.putExtra("errorCode", errorCode);
   1688                     }
   1689                     if (mUnsentPartCount != null && isSinglePartOrLastPart) {
   1690                         // Is multipart and last part
   1691                         fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
   1692                     }
   1693                     mSentIntent.send(context, error, fillIn);
   1694                 } catch (CanceledException ex) {
   1695                     Rlog.e(TAG, "Failed to send result");
   1696                 }
   1697             }
   1698         }
   1699 
   1700         /**
   1701          * Handle the sent of a single part message or a part of a multipart message
   1702          *
   1703          * @param context The Context
   1704          */
   1705         public void onSent(Context context) {
   1706             // is single part or last part of multipart message
   1707             boolean isSinglePartOrLastPart = true;
   1708             if (mUnsentPartCount != null) {
   1709                 isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
   1710             }
   1711             if (isSinglePartOrLastPart) {
   1712                 int messageType = Sms.MESSAGE_TYPE_SENT;
   1713                 if (mAnyPartFailed != null && mAnyPartFailed.get()) {
   1714                     messageType = Sms.MESSAGE_TYPE_FAILED;
   1715                 }
   1716                 persistOrUpdateMessage(context, messageType, 0/*errorCode*/);
   1717             }
   1718             if (mSentIntent != null) {
   1719                 try {
   1720                     // Extra information to send with the sent intent
   1721                     Intent fillIn = new Intent();
   1722                     if (mMessageUri != null) {
   1723                         // Pass this to SMS apps so that they know where it is stored
   1724                         fillIn.putExtra("uri", mMessageUri.toString());
   1725                     }
   1726                     if (mUnsentPartCount != null && isSinglePartOrLastPart) {
   1727                         // Is multipart and last part
   1728                         fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
   1729                     }
   1730                     mSentIntent.send(context, Activity.RESULT_OK, fillIn);
   1731                 } catch (CanceledException ex) {
   1732                     Rlog.e(TAG, "Failed to send result");
   1733                 }
   1734             }
   1735         }
   1736     }
   1737 
   1738     protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
   1739             PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount,
   1740             AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader,
   1741             boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage,
   1742             int priority, int validityPeriod) {
   1743         // Get calling app package name via UID from Binder call
   1744         PackageManager pm = mContext.getPackageManager();
   1745         String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
   1746 
   1747         // Get package info via packagemanager
   1748         final int userId = UserHandle.getCallingUserId();
   1749         PackageInfo appInfo = null;
   1750         if (packageNames != null && packageNames.length > 0) {
   1751             try {
   1752                 // XXX this is lossy- apps can share a UID
   1753                 appInfo = pm.getPackageInfoAsUser(
   1754                         packageNames[0], PackageManager.GET_SIGNATURES, userId);
   1755             } catch (PackageManager.NameNotFoundException e) {
   1756                 // error will be logged in sendRawPdu
   1757             }
   1758         }
   1759         // Strip non-digits from destination phone number before checking for short codes
   1760         // and before displaying the number to the user if confirmation is required.
   1761         String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
   1762         return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format,
   1763                 unsentPartCount, anyPartFailed, messageUri, smsHeader, expectMore,
   1764                 fullMessageText, getSubId(), isText, persistMessage, userId, priority,
   1765                 validityPeriod);
   1766     }
   1767 
   1768     protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
   1769             PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore,
   1770             String fullMessageText, boolean isText, boolean persistMessage) {
   1771         return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/,
   1772                 null/*anyPartFailed*/, messageUri, null/*smsHeader*/, expectMore,
   1773                 fullMessageText, isText, persistMessage, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
   1774                 SMS_MESSAGE_PERIOD_NOT_SPECIFIED);
   1775     }
   1776 
   1777     protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
   1778             PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore,
   1779             String fullMessageText, boolean isText, boolean persistMessage, int priority,
   1780             int validityPeriod) {
   1781         return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/,
   1782                 null/*anyPartFailed*/, messageUri, null/*smsHeader*/, expectMore, fullMessageText,
   1783                 isText, persistMessage, priority, validityPeriod);
   1784     }
   1785 
   1786     protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
   1787             String text, SmsMessageBase.SubmitPduBase pdu) {
   1788         HashMap<String, Object> map = new HashMap<String, Object>();
   1789         map.put(MAP_KEY_DEST_ADDR, destAddr);
   1790         map.put(MAP_KEY_SC_ADDR, scAddr);
   1791         map.put(MAP_KEY_TEXT, text);
   1792         map.put(MAP_KEY_SMSC, pdu.encodedScAddress);
   1793         map.put(MAP_KEY_PDU, pdu.encodedMessage);
   1794         return map;
   1795     }
   1796 
   1797     protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
   1798             int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
   1799         HashMap<String, Object> map = new HashMap<String, Object>();
   1800         map.put(MAP_KEY_DEST_ADDR, destAddr);
   1801         map.put(MAP_KEY_SC_ADDR, scAddr);
   1802         map.put(MAP_KEY_DEST_PORT, destPort);
   1803         map.put(MAP_KEY_DATA, data);
   1804         map.put(MAP_KEY_SMSC, pdu.encodedScAddress);
   1805         map.put(MAP_KEY_PDU, pdu.encodedMessage);
   1806         return map;
   1807     }
   1808 
   1809     /**
   1810      * Dialog listener for SMS confirmation dialog.
   1811      */
   1812     private final class ConfirmDialogListener
   1813             implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
   1814             CompoundButton.OnCheckedChangeListener {
   1815 
   1816         private final SmsTracker mTracker;
   1817         private Button mPositiveButton;
   1818         private Button mNegativeButton;
   1819         private boolean mRememberChoice;    // default is unchecked
   1820         private final TextView mRememberUndoInstruction;
   1821         private int mConfirmationType;  // 0 - Short Code Msg Sending; 1 - Rate Limit Exceeded
   1822         private static final int SHORT_CODE_MSG = 0; // Short Code Msg
   1823         private static final int RATE_LIMIT = 1; // Rate Limit Exceeded
   1824         private static final int NEVER_ALLOW = 1; // Never Allow
   1825 
   1826         ConfirmDialogListener(SmsTracker tracker, TextView textView, int confirmationType) {
   1827             mTracker = tracker;
   1828             mRememberUndoInstruction = textView;
   1829             mConfirmationType = confirmationType;
   1830         }
   1831 
   1832         void setPositiveButton(Button button) {
   1833             mPositiveButton = button;
   1834         }
   1835 
   1836         void setNegativeButton(Button button) {
   1837             mNegativeButton = button;
   1838         }
   1839 
   1840         @Override
   1841         public void onClick(DialogInterface dialog, int which) {
   1842             // Always set the SMS permission so that Settings will show a permission setting
   1843             // for the app (it won't be shown until after the app tries to send to a short code).
   1844             int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
   1845 
   1846             if (which == DialogInterface.BUTTON_POSITIVE) {
   1847                 Rlog.d(TAG, "CONFIRM sending SMS");
   1848                 // XXX this is lossy- apps can have more than one signature
   1849                 EventLog.writeEvent(EventLogTags.EXP_DET_SMS_SENT_BY_USER,
   1850                                     mTracker.mAppInfo.applicationInfo == null ?
   1851                                     -1 : mTracker.mAppInfo.applicationInfo.uid);
   1852                 sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker));
   1853                 if (mRememberChoice) {
   1854                     newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
   1855                 }
   1856             } else if (which == DialogInterface.BUTTON_NEGATIVE) {
   1857                 Rlog.d(TAG, "DENY sending SMS");
   1858                 // XXX this is lossy- apps can have more than one signature
   1859                 EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
   1860                                     mTracker.mAppInfo.applicationInfo == null ?
   1861                                     -1 :  mTracker.mAppInfo.applicationInfo.uid);
   1862                 Message msg = obtainMessage(EVENT_STOP_SENDING, mTracker);
   1863                 msg.arg1 = mConfirmationType;
   1864                 if (mRememberChoice) {
   1865                     newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
   1866                     msg.arg2 = ConfirmDialogListener.NEVER_ALLOW;
   1867                 }
   1868                 sendMessage(msg);
   1869             }
   1870             mSmsDispatchersController.setPremiumSmsPermission(mTracker.getAppPackageName(),
   1871                     newSmsPermission);
   1872         }
   1873 
   1874         @Override
   1875         public void onCancel(DialogInterface dialog) {
   1876             Rlog.d(TAG, "dialog dismissed: don't send SMS");
   1877             Message msg = obtainMessage(EVENT_STOP_SENDING, mTracker);
   1878             msg.arg1 = mConfirmationType;
   1879             sendMessage(msg);
   1880         }
   1881 
   1882         @Override
   1883         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
   1884             Rlog.d(TAG, "remember this choice: " + isChecked);
   1885             mRememberChoice = isChecked;
   1886             if (isChecked) {
   1887                 mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
   1888                 mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
   1889                 if (mRememberUndoInstruction != null) {
   1890                     mRememberUndoInstruction.
   1891                             setText(R.string.sms_short_code_remember_undo_instruction);
   1892                     mRememberUndoInstruction.setPadding(0,0,0,32);
   1893                 }
   1894             } else {
   1895                 mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
   1896                 mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
   1897                 if (mRememberUndoInstruction != null) {
   1898                     mRememberUndoInstruction.setText("");
   1899                     mRememberUndoInstruction.setPadding(0,0,0,0);
   1900                 }
   1901             }
   1902         }
   1903     }
   1904 
   1905     public boolean isIms() {
   1906         if (mSmsDispatchersController != null) {
   1907             return mSmsDispatchersController.isIms();
   1908         } else {
   1909             Rlog.e(TAG, "mSmsDispatchersController  is null");
   1910             return false;
   1911         }
   1912     }
   1913 
   1914     private String getMultipartMessageText(ArrayList<String> parts) {
   1915         final StringBuilder sb = new StringBuilder();
   1916         for (String part : parts) {
   1917             if (part != null) {
   1918                 sb.append(part);
   1919             }
   1920         }
   1921         return sb.toString();
   1922     }
   1923 
   1924     protected String getCarrierAppPackageName() {
   1925         UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
   1926         if (card == null) {
   1927             return null;
   1928         }
   1929 
   1930         List<String> carrierPackages = card.getCarrierPackageNamesForIntent(
   1931             mContext.getPackageManager(), new Intent(CarrierMessagingService.SERVICE_INTERFACE));
   1932         if (carrierPackages != null && carrierPackages.size() == 1) {
   1933             return carrierPackages.get(0);
   1934         }
   1935         // If there is no carrier package which implements CarrierMessagingService, then lookup if
   1936         // for a carrierImsPackage that implements CarrierMessagingService.
   1937         return CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
   1938                 new Intent(CarrierMessagingService.SERVICE_INTERFACE));
   1939     }
   1940 
   1941     protected int getSubId() {
   1942         return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.getPhoneId());
   1943     }
   1944 
   1945     private void checkCallerIsPhoneOrCarrierApp() {
   1946         int uid = Binder.getCallingUid();
   1947         int appId = UserHandle.getAppId(uid);
   1948         if (appId == Process.PHONE_UID || uid == 0) {
   1949             return;
   1950         }
   1951         try {
   1952             PackageManager pm = mContext.getPackageManager();
   1953             ApplicationInfo ai = pm.getApplicationInfo(getCarrierAppPackageName(), 0);
   1954             if (!UserHandle.isSameApp(ai.uid, Binder.getCallingUid())) {
   1955                 throw new SecurityException("Caller is not phone or carrier app!");
   1956             }
   1957         } catch (PackageManager.NameNotFoundException re) {
   1958             throw new SecurityException("Caller is not phone or carrier app!");
   1959         }
   1960     }
   1961 
   1962     protected boolean isCdmaMo() {
   1963         return mSmsDispatchersController.isCdmaMo();
   1964     }
   1965 }
   1966