SMSDispatcher.java revision 8d8e8f45200d17b78d196d8cba389fd9c547ac11
10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2006 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.Activity;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.AlertDialog;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent;
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent.CanceledException;
238d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport android.content.BroadcastReceiver;
240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ContentResolver;
250217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.content.ContentValues;
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Context;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.DialogInterface;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Intent;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.ApplicationInfo;
302029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.content.pm.PackageInfo;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.PackageManager;
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources;
33ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.database.ContentObserver;
340217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.database.sqlite.SqliteWrapper;
350217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.net.Uri;
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.AsyncResult;
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Binder;
388d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport android.os.Bundle;
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler;
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.SystemProperties;
42ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.provider.Settings;
430217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.provider.Telephony;
440217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.provider.Telephony.Sms;
458d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport android.provider.Telephony.Sms.Intents;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.PhoneNumberUtils;
470d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.Rlog;
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.ServiceState;
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.TelephonyManager;
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Html;
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Spanned;
522029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.util.EventLog;
534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.LayoutInflater;
544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.View;
5578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwaltimport android.view.ViewGroup;
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.WindowManager;
574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.Button;
584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CheckBox;
594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CompoundButton;
604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.TextView;
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.R;
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
64ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowaimport com.android.internal.telephony.ImsSMSDispatcher;
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
678d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport java.util.Collections;
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap;
698d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport java.util.List;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Random;
710d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.concurrent.atomic.AtomicInteger;
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic abstract class SMSDispatcher extends Handler {
81cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final String TAG = "SMSDispatcher";    // accessed from inner class
82cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final boolean DBG = false;
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Permission required to send SMS to short codes without user confirmation. */
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_SMS_NO_CONFIRMATION_PERMISSION =
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "android.permission.SEND_SMS_NO_CONFIRMATION";
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
89ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_SIM = 1;
90ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_NETWORK = 2;
91ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_BOTH = 3;
92ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
93ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final SettingsObserver mSettingsObserver;
94ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** SMS send complete. */
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int EVENT_SEND_SMS_COMPLETE = 2;
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Retry sending a previously failed SMS message */
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_RETRY = 3;
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for sending a large number of messages. */
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Send the user confirmed SMS */
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_SEND_CONFIRMED_SMS = 5;  // accessed from inner class
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Don't send SMS (user did not confirm). */
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_STOP_SENDING = 7;        // accessed from inner class
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1160d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /** Handle status report from {@code CdmaInboundSmsHandler}. */
1170d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected static final int EVENT_HANDLE_STATUS_REPORT = 10;
1180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1191260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Radio is ON */
1201260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_RADIO_ON = 11;
1211260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1221260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** IMS registration/SMS format changed */
1231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_CHANGED = 12;
1241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1251260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */
1261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_DONE = 13;
1271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    // other
1291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_NEW_ICC_SMS = 14;
1301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_ICC_CHANGED = 15;
1311260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1321260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected PhoneBase mPhone;
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final Context mContext;
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ContentResolver mResolver;
13522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville    protected final CommandsInterface mCi;
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final TelephonyManager mTelephonyManager;
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Maximum number of times to retry sending a failed SMS. */
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MAX_SEND_RETRIES = 3;
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Delay before next send attempt on a failed SMS, in milliseconds. */
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SEND_RETRY_DELAY = 2000;
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** single part SMS */
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SINGLE_PART_SMS = 1;
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Message sending queue limit */
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MO_MSG_QUEUE_LIMIT = 5;
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Message reference for a CONCATENATED_8_BIT_REFERENCE or
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CONCATENATED_16_BIT_REFERENCE message set.  Should be
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * incremented for each set of concatenated messages.
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Static field shared by all dispatcher objects.
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int sConcatenatedRef = new Random().nextInt(256);
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Outgoing message counter. Shared by all dispatchers. */
1561260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    private SmsUsageMonitor mUsageMonitor;
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
158ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    private ImsSMSDispatcher mImsSMSDispatcher;
159ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Number of outgoing SmsTrackers waiting for user confirmation. */
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mPendingTrackerCount;
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* Flags indicating whether the current device allows sms service */
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsCapable = true;
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsSendDisabled;
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected int mRemainingMessages = -1;
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static int getNextConcatenatedRef() {
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sConcatenatedRef += 1;
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return sConcatenatedRef;
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SMS dispatcher.
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param phone the Phone to use
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param usageMonitor the SmsUsageMonitor to use
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
179ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor,
180ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            ImsSMSDispatcher imsSMSDispatcher) {
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhone = phone;
182ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        mImsSMSDispatcher = imsSMSDispatcher;
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mContext = phone.getContext();
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mResolver = mContext.getContentResolver();
18522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi = phone.mCi;
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mUsageMonitor = usageMonitor;
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
188ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
189ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
190ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsCapable = mContext.getResources().getBoolean(
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                com.android.internal.R.bool.config_sms_capable);
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsSendDisabled = !SystemProperties.getBoolean(
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                TelephonyProperties.PROPERTY_SMS_SEND, mSmsCapable);
196ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + " mSmsSendDisabled=" + mSmsSendDisabled);
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
200ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    /**
201ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     * Observe the secure setting for updated premium sms determination rules
202ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     */
203ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static class SettingsObserver extends ContentObserver {
204ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final AtomicInteger mPremiumSmsRule;
205ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final Context mContext;
206ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
207ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            super(handler);
208ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule = premiumSmsRule;
209ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mContext = context;
210ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            onChange(false); // load initial value;
211ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
212ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
213ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        @Override
214ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        public void onChange(boolean selfChange) {
215ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
216ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
217ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
218ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    }
219ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
2201260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void updatePhoneObject(PhoneBase phone) {
2211260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mPhone = phone;
2221260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mUsageMonitor = phone.mSmsUsageMonitor;
2231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() );
2241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
2251260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Unregister for incoming SMS events. */
2270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    public void dispose() {
2280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
2290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The format of the message PDU in the associated broadcast intent.
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Note: All applications which handle incoming SMS messages by processing the
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * into the new methods in {@link android.telephony.SmsMessage} which take an
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * extra format parameter. This is required in order to correctly decode the PDU on
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * devices which require support for both 3GPP and 3GPP2 formats at the same time,
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * such as CDMA/LTE devices and GSM/CDMA world phones.
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the format of the message PDU
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract String getFormat();
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
2480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports
2490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}.
2500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param o the SmsMessage containing the status report
2510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
2520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected void handleStatusReport(Object o) {
2530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        Rlog.d(TAG, "handleStatusReport() called with no subclass.");
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* TODO: Need to figure out how to keep track of status report routing in a
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       persistent manner. If the phone process restarts (reboot or crash),
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       we will lose this list and any status reports that come in after
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       will be dropped.
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Sent messages awaiting a delivery status report. */
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2648d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /** Outgoing messages being handled by the carrier app. */
2658d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected final List<SmsTracker> sendPendingList =
2668d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        Collections.synchronizedList(new ArrayList<SmsTracker>());
2678d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles events coming from the phone stack. Overridden from handler.
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg the message to handle
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msg.what) {
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_SMS_COMPLETE:
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // An outbound SMS has been successfully transferred, or failed.
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleSendComplete((AsyncResult) msg.obj);
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_RETRY:
2821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            Rlog.d(TAG, "SMS retry..");
2831260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            sendRetrySms((SmsTracker) msg.obj);
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleReachSentLimit((SmsTracker)(msg.obj));
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(false, (SmsTracker)(msg.obj));
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(true, (SmsTracker)(msg.obj));
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_CONFIRMED_SMS:
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.isMultipart()) {
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMultipartSms(tracker);
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_STOP_SENDING:
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.mSentIntent != null) {
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {
317ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "failed to send RESULT_ERROR_LIMIT_EXCEEDED");
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        case EVENT_HANDLE_STATUS_REPORT:
3250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            handleStatusReport(msg.obj);
3260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            break;
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        default:
3290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
3300d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
331b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    }
332b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
333b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    /**
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Called when SMS send completes. Broadcasts a sentIntent on success.
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * On failure, either sets up retries or broadcasts a sentIntent with
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the failure in the result code.
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ar AsyncResult passed into the message handler.  ar.result should
3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           an SmsResponse instance if send was successful.  ar.userObj
3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           should be an SmsTracker instance.
3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleSendComplete(AsyncResult ar) {
3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsTracker tracker = (SmsTracker) ar.userObj;
3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PendingIntent sentIntent = tracker.mSentIntent;
3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
346454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        if (ar.result != null) {
3475a176f73dbb2bff2ca8b8f86af86a17be6863b87Wink Saville            tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
348454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        } else {
349454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks            Rlog.d(TAG, "SmsResponse was null");
350454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        }
351454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks
3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (ar.exception == null) {
353cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3554931e2c19616ab5985f61f343b231efb33692241Zhihai Xu            if (SmsApplication.shouldWriteMessageForPackage(
3564931e2c19616ab5985f61f343b231efb33692241Zhihai Xu                    tracker.mAppInfo.applicationInfo.packageName, mContext)) {
3574931e2c19616ab5985f61f343b231efb33692241Zhihai Xu                // Persist it into the SMS database as a sent message
3584931e2c19616ab5985f61f343b231efb33692241Zhihai Xu                // so the user can see it in their default app.
3590217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                tracker.writeSentMessage(mContext);
3600217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
3610217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.mDeliveryIntent != null) {
3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Expecting a status report.  Add it to the list.
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryPendingList.add(tracker);
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (mRemainingMessages > -1) {
3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        mRemainingMessages--;
3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (mRemainingMessages == 0) {
3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        Intent sendNext = new Intent();
3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        sendNext.putExtra(SEND_NEXT_MSG_EXTRA, true);
3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        sentIntent.send(mContext, Activity.RESULT_OK, sendNext);
3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    } else {
3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        sentIntent.send(Activity.RESULT_OK);
3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
383cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send failed");
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3871260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
3881260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // This is retry after failure over IMS but voice is not available.
3891260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // Set retry to max allowed, so no retry is sent and
3901260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.
3911260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                tracker.mRetryCount = MAX_SEND_RETRIES;
3921260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
3931260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                Rlog.d(TAG, "handleSendComplete: Skipping retry: "
3941260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" isIms()="+isIms()
3951260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mRetryCount="+tracker.mRetryCount
3961260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mImsRetry="+tracker.mImsRetry
3971260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mMessageRef="+tracker.mMessageRef
3981260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" SS= "+mPhone.getServiceState().getState());
3991260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
4001260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
4011260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            // if sms over IMS is not supported on data and voice is not available...
4021260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, tracker.mSentIntent);
4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if ((((CommandException)(ar.exception)).getCommandError()
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    == CommandException.Error.SMS_FAIL_RETRY) &&
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                   tracker.mRetryCount < MAX_SEND_RETRIES) {
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Retry after a delay if needed.
4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // TODO: According to TS 23.040, 9.2.3.6, we should resend
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       with the same TP-MR as the failed message, and
4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       TP-RD set to 1.  However, we don't have a means of
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       knowing the MR for the failed message (EF_SMSstatus
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       may or may not have the MR corresponding to this
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       message, depending on the failure).  Also, in some
4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       implementations this retry is handled by the baseband.
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tracker.mRetryCount++;
4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (tracker.mSentIntent != null) {
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int error = RESULT_ERROR_GENERIC_FAILURE;
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (((CommandException)(ar.exception)).getCommandError()
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        == CommandException.Error.FDN_CHECK_FAILURE) {
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    error = RESULT_ERROR_FDN_CHECK_FAILURE;
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Done retrying; return an error to the app.
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Intent fillIn = new Intent();
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (ar.result != null) {
42922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville                        fillIn.putExtra("errorCode", ((SmsResponse)ar.result).mErrorCode);
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (mRemainingMessages > -1) {
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        mRemainingMessages--;
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (mRemainingMessages == 0) {
4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
4380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    tracker.mSentIntent.send(mContext, error, fillIn);
4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles outbound message when the phone is not in service.
4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ss     Current service state.  Valid values are:
4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  OUT_OF_SERVICE
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  EMERGENCY_ONLY
4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  POWER_OFF
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent the PendingIntent to send the error to
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static void handleNotInService(int ss, PendingIntent sentIntent) {
4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (sentIntent != null) {
4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ss == ServiceState.STATE_POWER_OFF) {
4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_RADIO_OFF);
4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
4600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NO_SERVICE);
4610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CanceledException ex) {}
4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a data based SMS to a specific application port.
4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destPort the port to deliver the message to
4730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data the body of the message to send
4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
4840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
4850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
4910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
4920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendData(String destAddr, String scAddr, int destPort,
4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent);
4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
4960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a text based SMS.
4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param text the body of the message to send
5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
5110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
5120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
5130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
5140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
5150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
5170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendText(String destAddr, String scAddr,
5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String text, PendingIntent sentIntent, PendingIntent deliveryIntent);
5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Calculate the number of septets needed to encode the message.
5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param messageBody the message to encode
5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param use7bitOnly ignore (but still count) illegal characters if true
5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return TextEncodingDetails
5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
5310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean use7bitOnly);
5320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
5348d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary.
5358d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * This outbound message was handled by the carrier app. If the carrier app fails to send
5368d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * this message, it would be resent by PSTN.
5378d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *
5388d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param messageRef the reference number of the SMS message.
5398d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param success True if and only if the message was sent successfully. If its value is
5408d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *  false, this message should be resent via PSTN.
5418d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
5428d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected abstract void updateSmsSendStatus(int messageRef, boolean success);
5438d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5448d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
5458d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Handler for a {@link GsmSMSDispatcher} or {@link CdmaSMSDispatcher} broadcast.
5468d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * If SMS sending is successfuly, sends EVENT_SEND_SMS_COMPLETE message. Otherwise,
5478d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * send the message via the GSM/CDMA network.
5488d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
5498d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected final class SMSDispatcherReceiver extends BroadcastReceiver {
5508d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5518d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        private final SmsTracker mTracker;
5528d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5538d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        public SMSDispatcherReceiver(SmsTracker tracker) {
5548d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            mTracker = tracker;
5558d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        }
5568d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5578d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        @Override
5588d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        public void onReceive(Context context, Intent intent) {
5598d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            String action = intent.getAction();
5608d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            if (action.equals(Intents.SMS_SEND_ACTION)) {
5618d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                int rc = getResultCode();
5628d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                if (rc == Activity.RESULT_OK) {
5638d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    Rlog.d(TAG, "Sending SMS by IP pending.");
5648d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    Bundle resultExtras = getResultExtras(false);
5658d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    if (resultExtras != null && resultExtras.containsKey("messageref")) {
5668d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                        mTracker.mMessageRef = resultExtras.getInt("messageref");
5678d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                        Rlog.d(TAG, "messageref = " + mTracker.mMessageRef);
5688d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    } else {
5698d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                        Rlog.e(TAG, "Can't find messageref in result extras.");
5708d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    }
5718d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    sendPendingList.add(mTracker);
5728d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                } else {
5738d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    Rlog.d(TAG, "Sending SMS by IP failed.");
5748d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    sendSmsByPstn(mTracker);
5758d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                }
5768d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            } else {
5778d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                Rlog.e(TAG, "unexpected BroadcastReceiver action: " + action);
5788d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            }
5798d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        }
5808d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    }
5818d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5828d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
5830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a multi-part text based SMS.
5840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
5850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
5860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
5870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   the current default SMSC
5880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param parts an <code>ArrayList</code> of strings that, in order,
5890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   comprise the original message
5900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntents if not null, an <code>ArrayList</code> of
5910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
5920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been sent.
5930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   The result code will be <code>Activity.RESULT_OK<code> for success,
5940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   or one of these errors:
5950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
5960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_RADIO_OFF</code>
5970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NULL_PDU</code>
5980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NO_SERVICE</code>.
5990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
6000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
6010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
6020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntents if not null, an <code>ArrayList</code> of
6030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
6040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been delivered
6050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   to the recipient.  The raw pdu of the status report is in the
6060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   extended data ("pdu").
6070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendMultipartText(String destAddr, String scAddr,
6090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
6100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<PendingIntent> deliveryIntents) {
6110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int refNumber = getNextConcatenatedRef() & 0x00FF;
6130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgCount = parts.size();
6140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int encoding = SmsConstants.ENCODING_UNKNOWN;
6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mRemainingMessages = msgCount;
6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
6200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            TextEncodingDetails details = calculateLength(parts.get(i), false);
6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding != details.codeUnitSize
6220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    && (encoding == SmsConstants.ENCODING_UNKNOWN
6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            || encoding == SmsConstants.ENCODING_7BIT)) {
6240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encoding = details.codeUnitSize;
6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            encodingForParts[i] = details;
6270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
6300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
6310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.refNumber = refNumber;
6320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.seqNumber = i + 1;  // 1-based sequence
6330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.msgCount = msgCount;
6340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // TODO: We currently set this to true since our messaging app will never
6350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // send more than 255 parts (it converts the message to MMS well before that).
6360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // However, we should support 3rd party messaging apps that might need 16-bit
6370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // references
6380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Note:  It's not sufficient to just flip this bit to true; it will have
6390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // ripple effects (several calculations assume 8-bit ref).
6400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.isEightBits = true;
6410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader smsHeader = new SmsHeader();
6420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsHeader.concatRef = concatRef;
6430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Set the national language tables for 3GPP 7-bit encoding, if enabled.
6450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding == SmsConstants.ENCODING_7BIT) {
6460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageTable = encodingForParts[i].languageTable;
6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
6480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent = null;
6510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntents != null && sentIntents.size() > i) {
6520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sentIntent = sentIntents.get(i);
6530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent deliveryIntent = null;
6560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (deliveryIntents != null && deliveryIntents.size() > i) {
6570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryIntent = deliveryIntents.get(i);
6580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding,
6610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent, deliveryIntent, (i == (msgCount - 1)));
6620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SubmitPdu and send it.
6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendNewSubmitPdu(String destinationAddress, String scAddress,
6700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String message, SmsHeader smsHeader, int encoding,
6710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart);
6720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
6740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a SMS
6751260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker will contain:
6761260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -smsc the SMSC to send the message through, or NULL for the
6770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  default SMSC
6781260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -pdu the raw PDU to send
6791260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -sentIntent if not NULL this <code>Intent</code> is
6800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
6810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
6820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:
6830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
6840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code>
6850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code>
6860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code>.
6870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
6880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
6890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
6901260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -deliveryIntent if not NULL this <code>Intent</code> is
6910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
6920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
6931260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -param destAddr the destination phone number (for short code confirmation)
6940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6951260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void sendRawPdu(SmsTracker tracker) {
6961260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap map = tracker.mData;
6971260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        byte pdu[] = (byte[]) map.get("pdu");
6981260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
6991260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PendingIntent sentIntent = tracker.mSentIntent;
7000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mSmsSendDisabled) {
7010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
7020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
7030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NO_SERVICE);
7040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
7050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
706ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "Device does not support sending sms.");
7070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
7080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pdu == null) {
7110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
7120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
7130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NULL_PDU);
7140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
7150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
7170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Get calling app package name via UID from Binder call
7200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
7210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
7220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (packageNames == null || packageNames.length == 0) {
7240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Refuse to send SMS if we can't get the calling package name.
725ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");
7260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
7270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
7280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
7290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {
730ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "failed to send error result");
7310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
7320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
7340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7362029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        // Get package info via packagemanager
7370d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        PackageInfo appInfo;
7382029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        try {
7392029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            // XXX this is lossy- apps can share a UID
7402029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
7412029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        } catch (PackageManager.NameNotFoundException e) {
742ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
7432029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            if (sentIntent != null) {
7442029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                try {
7452029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                    sentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
7462029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                } catch (CanceledException ex) {
747ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "failed to send error result");
7482029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                }
7492029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            }
7502029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            return;
7512029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        }
7520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // checkDestination() returns true if the destination is not a premium short code or the
7540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // sending app is approved to send to short codes. Otherwise, a message is sent to our
7550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // handler with the SmsTracker to request user confirmation before sending.
7560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (checkDestination(tracker)) {
7570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // check for excessive outgoing SMS usage by this app
7582029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
7590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
7600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
7610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
7640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7651260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            // if sms over IMS is not supported on data and voice is not available...
7661260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
7670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, tracker.mSentIntent);
7680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
7690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
7700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Check if destination is a potential premium short code and sender is not pre-approved to
7760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * send to short codes.
7770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the tracker for the SMS to send
7790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the destination is approved; false if user confirmation event was sent
7800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean checkDestination(SmsTracker tracker) {
7820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION_PERMISSION)
7830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                == PackageManager.PERMISSION_GRANTED) {
7840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;            // app is pre-approved to send to short codes
7850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
786ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int rule = mPremiumSmsRule.get();
787ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
788ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
789ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String simCountryIso = mTelephonyManager.getSimCountryIso();
790ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (simCountryIso == null || simCountryIso.length() != 2) {
791ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso");
792ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    simCountryIso = mTelephonyManager.getNetworkCountryIso();
793ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
794ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
795ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                smsCategory = mUsageMonitor.checkDestination(tracker.mDestAddress, simCountryIso);
796ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            }
797ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
798ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String networkCountryIso = mTelephonyManager.getNetworkCountryIso();
799ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (networkCountryIso == null || networkCountryIso.length() != 2) {
800ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso");
801ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    networkCountryIso = mTelephonyManager.getSimCountryIso();
802ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
803ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
804cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville                smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory,
805ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                        mUsageMonitor.checkDestination(tracker.mDestAddress, networkCountryIso));
8060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
808ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE
809ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE
810ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) {
8114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                return true;    // not a premium short code
8124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
8134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
8144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Wait for user confirmation unless the user has set permission to always allow/deny
8154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int premiumSmsPermission = mUsageMonitor.getPremiumSmsPermission(
8164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    tracker.mAppInfo.packageName);
8174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
8184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                // First time trying to send to premium SMS.
8194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
8204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
8210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            switch (premiumSmsPermission) {
8234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
824ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.d(TAG, "User approved this app to send to premium SMS");
8254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return true;
8260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
828ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.w(TAG, "User denied this app from sending to premium SMS");
8294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(EVENT_STOP_SENDING, tracker));
8304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // reject this message
8314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
8324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
8330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                default:
8344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    int event;
835ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
8364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
8374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    } else {
8384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
8394658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    }
8404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(event, tracker));
8414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // wait for user confirmation
8420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Deny sending an SMS if the outgoing queue limit is reached. Used when the message
8480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * must be confirmed by the user due to excessive usage or potential premium SMS detected.
8490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the message to send
8500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the message was denied; false to continue with send confirmation
8510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean denyIfQueueLimitReached(SmsTracker tracker) {
8530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
8540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Deny sending message when the queue limit is reached.
8550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
856a13eb8b86f22b0efcfb888e2491b007d3424ddddRekha Kumar                if (tracker.mSentIntent != null) {
857a13eb8b86f22b0efcfb888e2491b007d3424ddddRekha Kumar                    tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
858a13eb8b86f22b0efcfb888e2491b007d3424ddddRekha Kumar                }
8590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CanceledException ex) {
860ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
8610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;
8630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPendingTrackerCount++;
8650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return false;
8660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns the label for the specified app package name.
8700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param appPackage the package name of the app requesting to send an SMS
8710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the label for the specified app, or the package name if getApplicationInfo() fails
8720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private CharSequence getAppLabel(String appPackage) {
8740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
8750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
8760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ApplicationInfo appInfo = pm.getApplicationInfo(appPackage, 0);
8770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appInfo.loadLabel(pm);
8780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (PackageManager.NameNotFoundException e) {
879ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
8800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appPackage;  // fall back to package name if we can't get app label
8810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert when SMS needs confirmation due to excessive usage.
8860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker an SmsTracker for the current message.
8870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleReachSentLimit(SmsTracker tracker) {
8890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
8900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
8910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8932029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
8940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
8950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
8960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
89778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null);
8980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
9000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setTitle(R.string.sms_control_title)
9010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setIcon(R.drawable.stat_sys_warning)
9020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setMessage(messageText)
9030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
9040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_control_no), listener)
9050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
9060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
9070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
9090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
9100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
9110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert for user confirmation when sending to a potential short code.
9140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param isPremium true if the destination is known to be a premium short code
9150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the current message.
9160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) {
9180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
9190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
9200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        int detailsId;
9230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isPremium) {
9244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_premium_short_code_details;
9250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
9264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_short_code_details;
9270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9292029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
9300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
9314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
9324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                appLabel, tracker.mDestAddress));
9330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
9354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                Context.LAYOUT_INFLATER_SERVICE);
9364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
9374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
93878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
93978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                (TextView)layout.findViewById(R.id.sms_short_code_remember_undo_instruction));
94078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
94178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
9424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
9434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        messageView.setText(messageText);
9444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
94578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
9464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_layout);
9474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView detailsView = (TextView) detailsLayout.findViewById(
9484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_message);
9494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        detailsView.setText(detailsId);
9504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        CheckBox rememberChoice = (CheckBox) layout.findViewById(
9524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_remember_choice_checkbox);
9534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        rememberChoice.setOnCheckedChangeListener(listener);
9544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
9564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                .setView(layout)
9570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
9580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
9590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
9600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
9610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
9630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
9644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
9664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
9674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
9684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
9704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Returns the premium SMS permission for the specified package. If the package has never
9714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}
9724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * will be returned.
9734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to query permission
9744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
9754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
9764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
9774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
9784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
9794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public int getPremiumSmsPermission(String packageName) {
9804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        return mUsageMonitor.getPremiumSmsPermission(packageName);
9814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
9824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
9844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Sets the premium SMS permission for the specified package and save the value asynchronously
9854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * to persistent storage.
9864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to set permission
9874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
9884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
9894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
9904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
9914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public void setPremiumSmsPermission(String packageName, int permission) {
9924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        mUsageMonitor.setPremiumSmsPermission(packageName, permission);
9930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
9940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the message along to the radio.
9970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
9980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the SMS message to send
9990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendSms(SmsTracker tracker);
10010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10038d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Send the SMS via the PSTN network.
10048d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *
10058d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param tracker holds the Sms tracker ready to be sent
10068d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
10078d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected abstract void sendSmsByPstn(SmsTracker tracker);
10088d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
10098d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
10101260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * Retry the message along to the radio.
10111260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     *
10121260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker holds the SMS message to send
10131260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     */
1014ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public void sendRetrySms(SmsTracker tracker) {
1015ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        // re-routing to ImsSMSDispatcher
1016ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1017ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            mImsSMSDispatcher.sendRetrySms(tracker);
1018ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1019ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null. Retry failed");
1020ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1021ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
10221260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
10231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /**
10240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the multi-part SMS based on multipart Sms tracker
10250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
10260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the multipart Sms tracker ready to be sent
10270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void sendMultipartSms(SmsTracker tracker) {
10290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<String> parts;
10300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> sentIntents;
10310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> deliveryIntents;
10320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        HashMap<String, Object> map = tracker.mData;
10340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String destinationAddress = (String) map.get("destination");
10360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String scAddress = (String) map.get("scaddress");
10370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        parts = (ArrayList<String>) map.get("parts");
10390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
10400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
10410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // check if in service
10430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int ss = mPhone.getServiceState().getState();
10441260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // if sms over IMS is not supported on data and voice is not available...
10451260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
10460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0, count = parts.size(); i < count; i++) {
10470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                PendingIntent sentIntent = null;
10480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (sentIntents != null && sentIntents.size() > i) {
10490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent = sentIntents.get(i);
10500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
10510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, sentIntent);
10520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
10540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents);
10570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Keeps track of an SMS that has been sent to the RIL, until it has
10610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * successfully been sent, or we're done trying.
10620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final class SmsTracker {
10640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // fields need to be public for derived SmsDispatchers
10650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final HashMap<String, Object> mData;
10660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mRetryCount;
10671260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        public int mImsRetry; // nonzero indicates initial message was sent over Ims
10680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mMessageRef;
10691260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String mFormat;
10700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mSentIntent;
10720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mDeliveryIntent;
10730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10742029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        public final PackageInfo mAppInfo;
10750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final String mDestAddress;
10760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10770217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        private long mTimestamp = System.currentTimeMillis();
10780217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        private Uri mSentMessageUri; // Uri of persisted message if we wrote one
10790217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
10801260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
10811260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format) {
10820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mData = data;
10830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mSentIntent = sentIntent;
10840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDeliveryIntent = deliveryIntent;
10850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mRetryCount = 0;
10862029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            mAppInfo = appInfo;
10870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDestAddress = destAddr;
10881260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mFormat = format;
10891260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mImsRetry = 0;
10901260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mMessageRef = 0;
10910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /**
10940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * Returns whether this tracker holds a multi-part SMS.
10950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * @return true if the tracker holds a multi-part SMS; false otherwise
10960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
10970d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        boolean isMultipart() {
10980217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            return mData.containsKey("parts");
10990217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        }
11000217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
11010217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        /**
11020217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         * Persist this as a sent message
11030217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         */
11040217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        void writeSentMessage(Context context) {
11050217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            String text = (String)mData.get("text");
11060217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            if (text != null) {
11070217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                boolean deliveryReport = (mDeliveryIntent != null);
11080217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // Using invalid threadId 0 here. When the message is inserted into the db, the
11090217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // provider looks up the threadId based on the recipient(s).
11100217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                mSentMessageUri = Sms.addMessageToUri(context.getContentResolver(),
11110217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        Telephony.Sms.Sent.CONTENT_URI,
11120217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        mDestAddress,
11130217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        text /*body*/,
11140217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        null /*subject*/,
11150217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        mTimestamp /*date*/,
11160217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        true /*read*/,
11170217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        deliveryReport /*deliveryReport*/,
11180217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        0 /*threadId*/);
11190217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
11200217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        }
11210217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
11220217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        /**
11230217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         * Update the status of this message if we persisted it
11240217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         */
11250217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        public void updateSentMessageStatus(Context context, int status) {
11260217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            if (mSentMessageUri != null) {
11270217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // If we wrote this message in writeSentMessage, update it now
11280217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                ContentValues values = new ContentValues(1);
11290217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                values.put(Sms.STATUS, status);
11300217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                SqliteWrapper.update(context, context.getContentResolver(),
11310217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        mSentMessageUri, values, null, null);
11320217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
11330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1136ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
11371260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            PendingIntent deliveryIntent, String format) {
11381260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get calling app package name via UID from Binder call
11391260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageManager pm = mContext.getPackageManager();
11401260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
11411260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
11421260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get package info via packagemanager
11431260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageInfo appInfo = null;
11441260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (packageNames != null && packageNames.length > 0) {
11451260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            try {
11461260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // XXX this is lossy- apps can share a UID
11471260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
11481260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            } catch (PackageManager.NameNotFoundException e) {
11491260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // error will be logged in sendRawPdu
11501260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
11511260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        }
11521260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Strip non-digits from destination phone number before checking for short codes
11531260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // and before displaying the number to the user if confirmation is required.
11541260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
11551260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format);
11561260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
11571260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1158ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
11591260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            String text, SmsMessageBase.SubmitPduBase pdu) {
11601260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
11611260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
11621260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
11631260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("text", text);
11641260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
11651260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
11661260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
11671260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
11681260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1169ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
11701260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
11711260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
11721260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
11731260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
1174ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        map.put("destPort", destPort);
11751260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("data", data);
11761260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
11771260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
11781260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
11791260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
11801260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
11810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dialog listener for SMS confirmation dialog.
11830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final class ConfirmDialogListener
11854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
11864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            CompoundButton.OnCheckedChangeListener {
11870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        private final SmsTracker mTracker;
11894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mPositiveButton;
11904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mNegativeButton;
11914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private boolean mRememberChoice;    // default is unchecked
119278df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        private final TextView mRememberUndoInstruction;
11930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
119478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener(SmsTracker tracker, TextView textView) {
11950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mTracker = tracker;
119678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt            mRememberUndoInstruction = textView;
11970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setPositiveButton(Button button) {
12004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mPositiveButton = button;
12014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
12024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setNegativeButton(Button button) {
12044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mNegativeButton = button;
12054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
12064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
12080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onClick(DialogInterface dialog, int which) {
12094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Always set the SMS permission so that Settings will show a permission setting
12104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // for the app (it won't be shown until after the app tries to send to a short code).
12114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
12124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (which == DialogInterface.BUTTON_POSITIVE) {
1214ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "CONFIRM sending SMS");
12152029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1216634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_SENT_BY_USER,
1217ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1218ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 : mTracker.mAppInfo.applicationInfo.uid);
12190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker));
12204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
12214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
12224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
12230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (which == DialogInterface.BUTTON_NEGATIVE) {
1224ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "DENY sending SMS");
12252029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1226634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
1227ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1228ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 :  mTracker.mAppInfo.applicationInfo.uid);
12290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
12304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
12314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
12324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
12330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
12344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            setPremiumSmsPermission(mTracker.mAppInfo.packageName, newSmsPermission);
12350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
12380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onCancel(DialogInterface dialog) {
1239ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "dialog dismissed: don't send SMS");
12400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
12410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        @Override
12444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1245ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "remember this choice: " + isChecked);
12464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mRememberChoice = isChecked;
12474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (isChecked) {
12484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
12494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
125078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
125178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.
125278df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                            setText(R.string.sms_short_code_remember_undo_instruction);
125378df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,32);
125478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
12554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            } else {
12564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
12575d875796122cdd8a7004e8e3964b20b5c65a31a1Robert Greenwalt                mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
125878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
125978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setText("");
126078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,0);
126178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
12624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
12634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
12640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12651260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1266ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public boolean isIms() {
1267ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1268ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.isIms();
1269ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1270ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1271ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return false;
1272ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1273ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
12741260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1275ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public String getImsSmsFormat() {
1276ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1277ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.getImsSmsFormat();
1278ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1279ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1280ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return null;
1281ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1282ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
12830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
1284