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