SMSDispatcher.java revision b29851580bba4a13ddbf7a534d8b09295eb2c60f
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;
52b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wenimport android.text.TextUtils;
532029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.util.EventLog;
544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.LayoutInflater;
554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.View;
5678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwaltimport android.view.ViewGroup;
570825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.WindowManager;
584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.Button;
594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CheckBox;
604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CompoundButton;
614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.TextView;
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.R;
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
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;
71c99dab56e20222b28cbc6238645feac938f1c333Ye Wenimport java.util.concurrent.atomic.AtomicBoolean;
720d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.concurrent.atomic.AtomicInteger;
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic abstract class SMSDispatcher extends Handler {
82cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final String TAG = "SMSDispatcher";    // accessed from inner class
83cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final boolean DBG = false;
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Permission required to send SMS to short codes without user confirmation. */
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_SMS_NO_CONFIRMATION_PERMISSION =
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "android.permission.SEND_SMS_NO_CONFIRMATION";
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
90ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_SIM = 1;
91ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_NETWORK = 2;
92ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_BOTH = 3;
93ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
94ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final SettingsObserver mSettingsObserver;
95ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** SMS send complete. */
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int EVENT_SEND_SMS_COMPLETE = 2;
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Retry sending a previously failed SMS message */
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_RETRY = 3;
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for sending a large number of messages. */
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Send the user confirmed SMS */
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_SEND_CONFIRMED_SMS = 5;  // accessed from inner class
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Don't send SMS (user did not confirm). */
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_STOP_SENDING = 7;        // accessed from inner class
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1170d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /** Handle status report from {@code CdmaInboundSmsHandler}. */
1180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected static final int EVENT_HANDLE_STATUS_REPORT = 10;
1190d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1201260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Radio is ON */
1211260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_RADIO_ON = 11;
1221260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** IMS registration/SMS format changed */
1241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_CHANGED = 12;
1251260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */
1271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_DONE = 13;
1281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    // other
1301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_NEW_ICC_SMS = 14;
1311260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_ICC_CHANGED = 15;
1321260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1331260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected PhoneBase mPhone;
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final Context mContext;
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ContentResolver mResolver;
13622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville    protected final CommandsInterface mCi;
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final TelephonyManager mTelephonyManager;
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Maximum number of times to retry sending a failed SMS. */
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MAX_SEND_RETRIES = 3;
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Delay before next send attempt on a failed SMS, in milliseconds. */
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SEND_RETRY_DELAY = 2000;
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** single part SMS */
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SINGLE_PART_SMS = 1;
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Message sending queue limit */
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MO_MSG_QUEUE_LIMIT = 5;
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Message reference for a CONCATENATED_8_BIT_REFERENCE or
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CONCATENATED_16_BIT_REFERENCE message set.  Should be
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * incremented for each set of concatenated messages.
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Static field shared by all dispatcher objects.
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int sConcatenatedRef = new Random().nextInt(256);
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Outgoing message counter. Shared by all dispatchers. */
1571260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    private SmsUsageMonitor mUsageMonitor;
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
159ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    private ImsSMSDispatcher mImsSMSDispatcher;
160ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Number of outgoing SmsTrackers waiting for user confirmation. */
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mPendingTrackerCount;
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* Flags indicating whether the current device allows sms service */
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsCapable = true;
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsSendDisabled;
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static int getNextConcatenatedRef() {
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sConcatenatedRef += 1;
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return sConcatenatedRef;
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SMS dispatcher.
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param phone the Phone to use
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param usageMonitor the SmsUsageMonitor to use
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
178ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor,
179ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            ImsSMSDispatcher imsSMSDispatcher) {
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhone = phone;
181ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        mImsSMSDispatcher = imsSMSDispatcher;
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mContext = phone.getContext();
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mResolver = mContext.getContentResolver();
18422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi = phone.mCi;
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mUsageMonitor = usageMonitor;
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
187ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
188ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
189ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsCapable = mContext.getResources().getBoolean(
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                com.android.internal.R.bool.config_sms_capable);
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsSendDisabled = !SystemProperties.getBoolean(
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                TelephonyProperties.PROPERTY_SMS_SEND, mSmsCapable);
195ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + " mSmsSendDisabled=" + mSmsSendDisabled);
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
199ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    /**
200ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     * Observe the secure setting for updated premium sms determination rules
201ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     */
202ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static class SettingsObserver extends ContentObserver {
203ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final AtomicInteger mPremiumSmsRule;
204ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final Context mContext;
205ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
206ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            super(handler);
207ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule = premiumSmsRule;
208ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mContext = context;
209ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            onChange(false); // load initial value;
210ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
211ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
212ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        @Override
213ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        public void onChange(boolean selfChange) {
214ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
215ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
216ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
217ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    }
218ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
2191260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void updatePhoneObject(PhoneBase phone) {
2201260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mPhone = phone;
2211260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mUsageMonitor = phone.mSmsUsageMonitor;
2221260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() );
2231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
2241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Unregister for incoming SMS events. */
2260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    public void dispose() {
2270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
2280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The format of the message PDU in the associated broadcast intent.
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Note: All applications which handle incoming SMS messages by processing the
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * into the new methods in {@link android.telephony.SmsMessage} which take an
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * extra format parameter. This is required in order to correctly decode the PDU on
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * devices which require support for both 3GPP and 3GPP2 formats at the same time,
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * such as CDMA/LTE devices and GSM/CDMA world phones.
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the format of the message PDU
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract String getFormat();
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2460d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
2470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports
2480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}.
2490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param o the SmsMessage containing the status report
2500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
2510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected void handleStatusReport(Object o) {
2520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        Rlog.d(TAG, "handleStatusReport() called with no subclass.");
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* TODO: Need to figure out how to keep track of status report routing in a
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       persistent manner. If the phone process restarts (reboot or crash),
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       we will lose this list and any status reports that come in after
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       will be dropped.
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Sent messages awaiting a delivery status report. */
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2638d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /** Outgoing messages being handled by the carrier app. */
2648d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected final List<SmsTracker> sendPendingList =
2658d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        Collections.synchronizedList(new ArrayList<SmsTracker>());
2668d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles events coming from the phone stack. Overridden from handler.
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg the message to handle
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msg.what) {
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_SMS_COMPLETE:
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // An outbound SMS has been successfully transferred, or failed.
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleSendComplete((AsyncResult) msg.obj);
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_RETRY:
2811260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            Rlog.d(TAG, "SMS retry..");
2821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            sendRetrySms((SmsTracker) msg.obj);
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleReachSentLimit((SmsTracker)(msg.obj));
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(false, (SmsTracker)(msg.obj));
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(true, (SmsTracker)(msg.obj));
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_CONFIRMED_SMS:
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.isMultipart()) {
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMultipartSms(tracker);
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_STOP_SENDING:
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
312c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3170d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        case EVENT_HANDLE_STATUS_REPORT:
3180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            handleStatusReport(msg.obj);
3190d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            break;
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3210d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        default:
3220d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
3230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
324b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    }
325b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
326b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    /**
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Called when SMS send completes. Broadcasts a sentIntent on success.
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * On failure, either sets up retries or broadcasts a sentIntent with
3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the failure in the result code.
3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ar AsyncResult passed into the message handler.  ar.result should
3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           an SmsResponse instance if send was successful.  ar.userObj
3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           should be an SmsTracker instance.
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleSendComplete(AsyncResult ar) {
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsTracker tracker = (SmsTracker) ar.userObj;
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PendingIntent sentIntent = tracker.mSentIntent;
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
339454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        if (ar.result != null) {
3405a176f73dbb2bff2ca8b8f86af86a17be6863b87Wink Saville            tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
341454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        } else {
342454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks            Rlog.d(TAG, "SmsResponse was null");
343454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        }
344454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks
3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (ar.exception == null) {
346cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
348b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            if (!Telephony.AUTO_PERSIST) {
349370971c25973d9d8061b76e756df2fb8c1ebd990Ye Wen                // TODO(ywen):Temporarily only enable this with a flag so not to break existing apps
350c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (SmsApplication.shouldWriteMessageForPackage(
351c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        tracker.mAppInfo.applicationInfo.packageName, mContext)) {
352c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    // Persist it into the SMS database as a sent message
353c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    // so the user can see it in their default app.
354c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    tracker.writeSentMessage(mContext);
355c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
3560217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.mDeliveryIntent != null) {
3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Expecting a status report.  Add it to the list.
3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryPendingList.add(tracker);
3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
361c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onSent(mContext);
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
363cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send failed");
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3671260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
3681260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // This is retry after failure over IMS but voice is not available.
3691260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // Set retry to max allowed, so no retry is sent and
3701260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.
3711260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                tracker.mRetryCount = MAX_SEND_RETRIES;
3721260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
3731260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                Rlog.d(TAG, "handleSendComplete: Skipping retry: "
3741260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" isIms()="+isIms()
3751260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mRetryCount="+tracker.mRetryCount
3761260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mImsRetry="+tracker.mImsRetry
3771260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mMessageRef="+tracker.mMessageRef
3781260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" SS= "+mPhone.getServiceState().getState());
3791260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
3801260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
3811260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            // if sms over IMS is not supported on data and voice is not available...
3821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
383c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if ((((CommandException)(ar.exception)).getCommandError()
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    == CommandException.Error.SMS_FAIL_RETRY) &&
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                   tracker.mRetryCount < MAX_SEND_RETRIES) {
3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Retry after a delay if needed.
3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // TODO: According to TS 23.040, 9.2.3.6, we should resend
3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       with the same TP-MR as the failed message, and
3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       TP-RD set to 1.  However, we don't have a means of
3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       knowing the MR for the failed message (EF_SMSstatus
3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       may or may not have the MR corresponding to this
3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       message, depending on the failure).  Also, in some
3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       implementations this retry is handled by the baseband.
3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tracker.mRetryCount++;
3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
398c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } else {
399c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                int errorCode = 0;
400c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (ar.result != null) {
401c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    errorCode = ((SmsResponse)ar.result).mErrorCode;
402c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int error = RESULT_ERROR_GENERIC_FAILURE;
4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (((CommandException)(ar.exception)).getCommandError()
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        == CommandException.Error.FDN_CHECK_FAILURE) {
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    error = RESULT_ERROR_FDN_CHECK_FAILURE;
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
408c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, error, errorCode);
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles outbound message when the phone is not in service.
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ss     Current service state.  Valid values are:
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  OUT_OF_SERVICE
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  EMERGENCY_ONLY
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  POWER_OFF
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent the PendingIntent to send the error to
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static void handleNotInService(int ss, PendingIntent sentIntent) {
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (sentIntent != null) {
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ss == ServiceState.STATE_POWER_OFF) {
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_RADIO_OFF);
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NO_SERVICE);
4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CanceledException ex) {}
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
435c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     * @param ss service state
436c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     * @return The result error based on input service state for not in service error
437c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     */
438c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected static int getNotInServiceError(int ss) {
439c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        if (ss == ServiceState.STATE_POWER_OFF) {
440c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return RESULT_ERROR_RADIO_OFF;
441c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
442c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return RESULT_ERROR_NO_SERVICE;
443c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
444c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
445c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    /**
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a data based SMS to a specific application port.
4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destPort the port to deliver the message to
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data the body of the message to send
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
4600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
4610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendData(String destAddr, String scAddr, int destPort,
4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent);
4730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a text based SMS.
476b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     *  @param destAddr the address to send the message to
4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param text the body of the message to send
4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
4840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
4850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
4910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
4920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
496b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param messageUri optional URI of the message if it is already stored in the system
497b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param callingPkg the calling package name
4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
499b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    protected abstract void sendText(String destAddr, String scAddr, String text,
500b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri,
501b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            String callingPkg);
5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
50463418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * Inject an SMS PDU into the android platform.
50563418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *
50663418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param pdu is the byte array of pdu to be injected into android telephony layer
50763418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param format is the format of SMS pdu (3gpp or 3gpp2)
50863418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
50963418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  broadcast when the message is successfully received by the
51063418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  android telephony layer. This intent is broadcasted at
51163418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  the same time an SMS received from radio is responded back.
51263418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     */
51363418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni    protected abstract void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent);
51463418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni
51563418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni    /**
5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Calculate the number of septets needed to encode the message.
5170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param messageBody the message to encode
5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param use7bitOnly ignore (but still count) illegal characters if true
5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return TextEncodingDetails
5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean use7bitOnly);
5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
5268d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary.
5278d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * This outbound message was handled by the carrier app. If the carrier app fails to send
5288d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * this message, it would be resent by PSTN.
5298d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *
5308d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param messageRef the reference number of the SMS message.
5318d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param success True if and only if the message was sent successfully. If its value is
5328d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *  false, this message should be resent via PSTN.
5338d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
5348d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected abstract void updateSmsSendStatus(int messageRef, boolean success);
5358d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5368d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
5378d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Handler for a {@link GsmSMSDispatcher} or {@link CdmaSMSDispatcher} broadcast.
5388d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * If SMS sending is successfuly, sends EVENT_SEND_SMS_COMPLETE message. Otherwise,
5398d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * send the message via the GSM/CDMA network.
5408d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
5418d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected final class SMSDispatcherReceiver extends BroadcastReceiver {
5428d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5438d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        private final SmsTracker mTracker;
5448d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5458d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        public SMSDispatcherReceiver(SmsTracker tracker) {
5468d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            mTracker = tracker;
5478d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        }
5488d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5498d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        @Override
5508d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        public void onReceive(Context context, Intent intent) {
5518d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            String action = intent.getAction();
5528d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            if (action.equals(Intents.SMS_SEND_ACTION)) {
5538d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                int rc = getResultCode();
5548d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                if (rc == Activity.RESULT_OK) {
5558d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    Rlog.d(TAG, "Sending SMS by IP pending.");
5568d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    Bundle resultExtras = getResultExtras(false);
5578d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    if (resultExtras != null && resultExtras.containsKey("messageref")) {
5588d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                        mTracker.mMessageRef = resultExtras.getInt("messageref");
5598d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                        Rlog.d(TAG, "messageref = " + mTracker.mMessageRef);
5608d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    } else {
5618d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                        Rlog.e(TAG, "Can't find messageref in result extras.");
5628d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    }
5638d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    sendPendingList.add(mTracker);
5648d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                } else {
5658d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    Rlog.d(TAG, "Sending SMS by IP failed.");
5668d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                    sendSmsByPstn(mTracker);
5678d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                }
5688d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            } else {
5698d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang                Rlog.e(TAG, "unexpected BroadcastReceiver action: " + action);
5708d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang            }
5718d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang        }
5728d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    }
5738d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
5748d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
5750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a multi-part text based SMS.
576b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     *  @param destAddr the address to send the message to
5770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
5780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   the current default SMSC
5790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param parts an <code>ArrayList</code> of strings that, in order,
5800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   comprise the original message
5810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntents if not null, an <code>ArrayList</code> of
5820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
5830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been sent.
5840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   The result code will be <code>Activity.RESULT_OK<code> for success,
5850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   or one of these errors:
5860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
5870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_RADIO_OFF</code>
5880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NULL_PDU</code>
5890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NO_SERVICE</code>.
5900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
5910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
5920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
5930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntents if not null, an <code>ArrayList</code> of
5940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
5950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been delivered
5960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   to the recipient.  The raw pdu of the status report is in the
597b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param messageUri optional URI of the message if it is already stored in the system
598b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param callingPkg the calling package name
5990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendMultipartText(String destAddr, String scAddr,
6010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
602b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg) {
603b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        if (messageUri == null) {
604b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            messageUri = writeOutboxMessage(
605b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                    getSubId(),
606b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                    destAddr,
607b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                    getMultipartMessageText(parts),
608b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                    deliveryIntents != null && deliveryIntents.size() > 0,
609b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                    callingPkg);
610b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        } else {
611b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            moveToOutbox(getSubId(), messageUri, callingPkg);
612b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        }
6130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int refNumber = getNextConcatenatedRef() & 0x00FF;
6140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgCount = parts.size();
6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int encoding = SmsConstants.ENCODING_UNKNOWN;
6160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            TextEncodingDetails details = calculateLength(parts.get(i), false);
6200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding != details.codeUnitSize
6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    && (encoding == SmsConstants.ENCODING_UNKNOWN
6220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            || encoding == SmsConstants.ENCODING_7BIT)) {
6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encoding = details.codeUnitSize;
6240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            encodingForParts[i] = details;
6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
628c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        // States to track at the message level (for all parts)
629c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
630c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
631c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
6320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
6330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
6340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.refNumber = refNumber;
6350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.seqNumber = i + 1;  // 1-based sequence
6360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.msgCount = msgCount;
6370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // TODO: We currently set this to true since our messaging app will never
6380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // send more than 255 parts (it converts the message to MMS well before that).
6390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // However, we should support 3rd party messaging apps that might need 16-bit
6400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // references
6410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Note:  It's not sufficient to just flip this bit to true; it will have
6420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // ripple effects (several calculations assume 8-bit ref).
6430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.isEightBits = true;
6440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader smsHeader = new SmsHeader();
6450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsHeader.concatRef = concatRef;
6460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Set the national language tables for 3GPP 7-bit encoding, if enabled.
6480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding == SmsConstants.ENCODING_7BIT) {
6490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageTable = encodingForParts[i].languageTable;
6500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
6510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent = null;
6540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntents != null && sentIntents.size() > i) {
6550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sentIntent = sentIntents.get(i);
6560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent deliveryIntent = null;
6590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (deliveryIntents != null && deliveryIntents.size() > i) {
6600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryIntent = deliveryIntents.get(i);
6610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding,
664c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    sentIntent, deliveryIntent, (i == (msgCount - 1)),
665c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    unsentPartCount, anyPartFailed, messageUri);
6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
6700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SubmitPdu and send it.
6710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendNewSubmitPdu(String destinationAddress, String scAddress,
6730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String message, SmsHeader smsHeader, int encoding,
674c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
675c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri);
6760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
6780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a SMS
6791260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker will contain:
6801260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -smsc the SMSC to send the message through, or NULL for the
6810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  default SMSC
6821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -pdu the raw PDU to send
6831260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -sentIntent if not NULL this <code>Intent</code> is
6840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
6850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
6860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:
6870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
6880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code>
6890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code>
6900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code>.
6910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
6920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
6930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
6941260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -deliveryIntent if not NULL this <code>Intent</code> is
6950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
6960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
6971260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -param destAddr the destination phone number (for short code confirmation)
6980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6991260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void sendRawPdu(SmsTracker tracker) {
7001260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap map = tracker.mData;
7011260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        byte pdu[] = (byte[]) map.get("pdu");
7021260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
7030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mSmsSendDisabled) {
704c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Device does not support sending sms.");
705c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
7060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
7070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pdu == null) {
710c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Empty PDU");
711c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);
7120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
7130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Get calling app package name via UID from Binder call
7160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
7170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
7180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (packageNames == null || packageNames.length == 0) {
7200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Refuse to send SMS if we can't get the calling package name.
721ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");
722c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
7230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
7240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7262029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        // Get package info via packagemanager
7270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        PackageInfo appInfo;
7282029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        try {
7292029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            // XXX this is lossy- apps can share a UID
7302029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
7312029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        } catch (PackageManager.NameNotFoundException e) {
732ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
733c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
7342029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            return;
7352029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        }
7360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // checkDestination() returns true if the destination is not a premium short code or the
7380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // sending app is approved to send to short codes. Otherwise, a message is sent to our
7390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // handler with the SmsTracker to request user confirmation before sending.
7400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (checkDestination(tracker)) {
7410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // check for excessive outgoing SMS usage by this app
7422029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
7430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
7440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
7450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
7480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7491260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            // if sms over IMS is not supported on data and voice is not available...
7501260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
751c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
7520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
7530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
7540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Check if destination is a potential premium short code and sender is not pre-approved to
7600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * send to short codes.
7610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the tracker for the SMS to send
7630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the destination is approved; false if user confirmation event was sent
7640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean checkDestination(SmsTracker tracker) {
7660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION_PERMISSION)
7670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                == PackageManager.PERMISSION_GRANTED) {
7680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;            // app is pre-approved to send to short codes
7690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
770ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int rule = mPremiumSmsRule.get();
771ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
772ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
773ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String simCountryIso = mTelephonyManager.getSimCountryIso();
774ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (simCountryIso == null || simCountryIso.length() != 2) {
775ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso");
776ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    simCountryIso = mTelephonyManager.getNetworkCountryIso();
777ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
778ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
779ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                smsCategory = mUsageMonitor.checkDestination(tracker.mDestAddress, simCountryIso);
780ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            }
781ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
782ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String networkCountryIso = mTelephonyManager.getNetworkCountryIso();
783ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (networkCountryIso == null || networkCountryIso.length() != 2) {
784ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso");
785ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    networkCountryIso = mTelephonyManager.getSimCountryIso();
786ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
787ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
788cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville                smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory,
789ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                        mUsageMonitor.checkDestination(tracker.mDestAddress, networkCountryIso));
7900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
792ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE
793ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE
794ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) {
7954658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                return true;    // not a premium short code
7964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
7974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
7984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Wait for user confirmation unless the user has set permission to always allow/deny
7994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int premiumSmsPermission = mUsageMonitor.getPremiumSmsPermission(
8004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    tracker.mAppInfo.packageName);
8014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
8024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                // First time trying to send to premium SMS.
8034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
8044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
8050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            switch (premiumSmsPermission) {
8074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
808ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.d(TAG, "User approved this app to send to premium SMS");
8094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return true;
8100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
812ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.w(TAG, "User denied this app from sending to premium SMS");
8134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(EVENT_STOP_SENDING, tracker));
8144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // reject this message
8154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
8164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
8170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                default:
8184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    int event;
819ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
8204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
8214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    } else {
8224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
8234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    }
8244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(event, tracker));
8254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // wait for user confirmation
8260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Deny sending an SMS if the outgoing queue limit is reached. Used when the message
8320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * must be confirmed by the user due to excessive usage or potential premium SMS detected.
8330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the message to send
8340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the message was denied; false to continue with send confirmation
8350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean denyIfQueueLimitReached(SmsTracker tracker) {
8370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
8380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Deny sending message when the queue limit is reached.
839c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Denied because queue limit reached");
840c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
8410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;
8420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPendingTrackerCount++;
8440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return false;
8450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns the label for the specified app package name.
8490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param appPackage the package name of the app requesting to send an SMS
8500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the label for the specified app, or the package name if getApplicationInfo() fails
8510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private CharSequence getAppLabel(String appPackage) {
8530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
8540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
8550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ApplicationInfo appInfo = pm.getApplicationInfo(appPackage, 0);
8560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appInfo.loadLabel(pm);
8570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (PackageManager.NameNotFoundException e) {
858ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
8590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appPackage;  // fall back to package name if we can't get app label
8600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert when SMS needs confirmation due to excessive usage.
8650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker an SmsTracker for the current message.
8660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleReachSentLimit(SmsTracker tracker) {
8680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
8690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
8700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8722029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
8730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
8740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
8750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
87678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null);
8770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
8790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setTitle(R.string.sms_control_title)
8800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setIcon(R.drawable.stat_sys_warning)
8810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setMessage(messageText)
8820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
8830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_control_no), listener)
8840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
8850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
8860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
8880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
8890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert for user confirmation when sending to a potential short code.
8930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param isPremium true if the destination is known to be a premium short code
8940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the current message.
8950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) {
8970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
8980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
8990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        int detailsId;
9020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isPremium) {
9034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_premium_short_code_details;
9040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
9054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_short_code_details;
9060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9082029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
9090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
9104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
9114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                appLabel, tracker.mDestAddress));
9120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
9144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                Context.LAYOUT_INFLATER_SERVICE);
9154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
9164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
91778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
91878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                (TextView)layout.findViewById(R.id.sms_short_code_remember_undo_instruction));
91978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
92078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
9214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
9224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        messageView.setText(messageText);
9234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
92478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
9254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_layout);
9264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView detailsView = (TextView) detailsLayout.findViewById(
9274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_message);
9284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        detailsView.setText(detailsId);
9294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        CheckBox rememberChoice = (CheckBox) layout.findViewById(
9314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_remember_choice_checkbox);
9324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        rememberChoice.setOnCheckedChangeListener(listener);
9334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
9354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                .setView(layout)
9360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
9370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
9380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
9390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
9400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
9420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
9434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
9454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
9464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
9474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
9494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Returns the premium SMS permission for the specified package. If the package has never
9504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}
9514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * will be returned.
9524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to query permission
9534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
9544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
9554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
9564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
9574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
9584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public int getPremiumSmsPermission(String packageName) {
9594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        return mUsageMonitor.getPremiumSmsPermission(packageName);
9604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
9614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
9624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
9634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Sets the premium SMS permission for the specified package and save the value asynchronously
9644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * to persistent storage.
9654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to set permission
9664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
9674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
9684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
9694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
9704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public void setPremiumSmsPermission(String packageName, int permission) {
9714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        mUsageMonitor.setPremiumSmsPermission(packageName, permission);
9720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
9730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the message along to the radio.
9760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
9770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the SMS message to send
9780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendSms(SmsTracker tracker);
9800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9828d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Send the SMS via the PSTN network.
9838d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *
9848d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param tracker holds the Sms tracker ready to be sent
9858d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
9868d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected abstract void sendSmsByPstn(SmsTracker tracker);
9878d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
9888d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
9891260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * Retry the message along to the radio.
9901260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     *
9911260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker holds the SMS message to send
9921260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     */
993ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public void sendRetrySms(SmsTracker tracker) {
994ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        // re-routing to ImsSMSDispatcher
995ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
996ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            mImsSMSDispatcher.sendRetrySms(tracker);
997ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
998ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null. Retry failed");
999ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1000ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
10011260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
10021260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /**
10030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the multi-part SMS based on multipart Sms tracker
10040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
10050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the multipart Sms tracker ready to be sent
10060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void sendMultipartSms(SmsTracker tracker) {
10080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<String> parts;
10090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> sentIntents;
10100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> deliveryIntents;
10110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        HashMap<String, Object> map = tracker.mData;
10130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String destinationAddress = (String) map.get("destination");
10150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String scAddress = (String) map.get("scaddress");
10160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        parts = (ArrayList<String>) map.get("parts");
10180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
10190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
10200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // check if in service
10220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int ss = mPhone.getServiceState().getState();
10231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // if sms over IMS is not supported on data and voice is not available...
10241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
10250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0, count = parts.size(); i < count; i++) {
10260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                PendingIntent sentIntent = null;
10270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (sentIntents != null && sentIntents.size() > i) {
10280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent = sentIntents.get(i);
10290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
10300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, sentIntent);
10310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
10330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1035b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents,
1036b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                null/*messageUri*/, null/*callingPkg*/);
10370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Keeps track of an SMS that has been sent to the RIL, until it has
10410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * successfully been sent, or we're done trying.
10420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final class SmsTracker {
10440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // fields need to be public for derived SmsDispatchers
10450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final HashMap<String, Object> mData;
10460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mRetryCount;
10471260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        public int mImsRetry; // nonzero indicates initial message was sent over Ims
10480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mMessageRef;
10491260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String mFormat;
10500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mSentIntent;
10520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mDeliveryIntent;
10530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10542029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        public final PackageInfo mAppInfo;
10550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final String mDestAddress;
10560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10570217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        private long mTimestamp = System.currentTimeMillis();
1058c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public Uri mMessageUri; // Uri of persisted message if we wrote one
1059c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1060c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        // Reference to states of a multipart message that this part belongs to
1061c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private AtomicInteger mUnsentPartCount;
1062c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private AtomicBoolean mAnyPartFailed;
10630217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
10641260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1065c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format,
1066c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri) {
10670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mData = data;
10680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mSentIntent = sentIntent;
10690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDeliveryIntent = deliveryIntent;
10700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mRetryCount = 0;
10712029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            mAppInfo = appInfo;
10720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDestAddress = destAddr;
10731260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mFormat = format;
10741260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mImsRetry = 0;
10751260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mMessageRef = 0;
1076c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mUnsentPartCount = unsentPartCount;
1077c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mAnyPartFailed = anyPartFailed;
1078c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mMessageUri = messageUri;
10790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /**
10820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * Returns whether this tracker holds a multi-part SMS.
10830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * @return true if the tracker holds a multi-part SMS; false otherwise
10840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
10850d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        boolean isMultipart() {
10860217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            return mData.containsKey("parts");
10870217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        }
10880217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
10890217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        /**
10900217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         * Persist this as a sent message
10910217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         */
10920217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        void writeSentMessage(Context context) {
10930217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            String text = (String)mData.get("text");
10940217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            if (text != null) {
10950217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                boolean deliveryReport = (mDeliveryIntent != null);
10960217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // Using invalid threadId 0 here. When the message is inserted into the db, the
10970217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // provider looks up the threadId based on the recipient(s).
1098c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                mMessageUri = Sms.addMessageToUri(context.getContentResolver(),
10990217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        Telephony.Sms.Sent.CONTENT_URI,
11000217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        mDestAddress,
11010217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        text /*body*/,
11020217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        null /*subject*/,
11030217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        mTimestamp /*date*/,
11040217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        true /*read*/,
11050217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        deliveryReport /*deliveryReport*/,
11060217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                        0 /*threadId*/);
11070217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
11080217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        }
11090217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
11100217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        /**
11110217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         * Update the status of this message if we persisted it
11120217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         */
11130217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        public void updateSentMessageStatus(Context context, int status) {
1114c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri != null) {
11150217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // If we wrote this message in writeSentMessage, update it now
11160217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                ContentValues values = new ContentValues(1);
11170217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                values.put(Sms.STATUS, status);
11180217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                SqliteWrapper.update(context, context.getContentResolver(),
1119c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        mMessageUri, values, null, null);
1120c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1121c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1122c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1123c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
1124c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Update the error_code column of a message
1125c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1126c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1127c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param errorCode The error code
1128c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1129c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private void updateMessageErrorCode(Context context, int errorCode) {
1130b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            if (!Telephony.AUTO_PERSIST) {
1131370971c25973d9d8061b76e756df2fb8c1ebd990Ye Wen                // TODO(ywen):Temporarily only enable this with a flag so not to break existing apps
1132c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                return;
1133c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1134c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri == null) {
1135c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                return;
1136c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1137c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final ContentValues values = new ContentValues(1);
1138c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            values.put(Sms.ERROR_CODE, errorCode);
1139c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final long identity = Binder.clearCallingIdentity();
1140c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            try {
1141c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
1142c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        null/*where*/, null/*selectionArgs*/) != 1) {
1143c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to update message error code");
1144c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1145c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } finally {
1146c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                Binder.restoreCallingIdentity(identity);
1147c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1148c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1149c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1150c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
1151c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Set the final state of a message: FAILED or SENT
1152c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1153c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1154c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param messageType The final message type
1155c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1156c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private void setMessageFinalState(Context context, int messageType) {
1157b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            if (!Telephony.AUTO_PERSIST) {
1158370971c25973d9d8061b76e756df2fb8c1ebd990Ye Wen                // TODO(ywen):Temporarily only enable this with a flag so not to break existing apps
1159c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                return;
1160c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1161c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri == null) {
1162c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                return;
1163c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1164c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final ContentValues values = new ContentValues(1);
1165c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            values.put(Sms.TYPE, messageType);
1166c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final long identity = Binder.clearCallingIdentity();
1167c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            try {
1168c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
1169c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        null/*where*/, null/*selectionArgs*/) != 1) {
1170c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to move message to " + messageType);
1171c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1172c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } finally {
1173c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                Binder.restoreCallingIdentity(identity);
1174c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1175c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1176c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1177c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
1178c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Handle a failure of a single part message or a part of a multipart message
1179c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1180c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1181c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param error The error to send back with
1182c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param errorCode
1183c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1184c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public void onFailed(Context context, int error, int errorCode) {
1185c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mAnyPartFailed != null) {
1186c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                mAnyPartFailed.set(true);
1187c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1188c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            // is single part or last part of multipart message
1189c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            boolean isSinglePartOrLastPart = true;
1190c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mUnsentPartCount != null) {
1191c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1192c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1193c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (errorCode != 0) {
1194c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                updateMessageErrorCode(context, errorCode);
1195c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1196c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (isSinglePartOrLastPart) {
1197c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                setMessageFinalState(context, Sms.MESSAGE_TYPE_FAILED);
1198c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1199c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mSentIntent != null) {
1200c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                try {
1201fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    // Extra information to send with the sent intent
1202fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    Intent fillIn = new Intent();
1203fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    if (mMessageUri != null) {
1204fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        // Pass this to SMS apps so that they know where it is stored
1205fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra("uri", mMessageUri.toString());
1206fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    }
1207c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (errorCode != 0) {
1208c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        fillIn.putExtra("errorCode", errorCode);
1209c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1210c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1211c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        // Is multipart and last part
1212c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1213c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1214c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    mSentIntent.send(context, error, fillIn);
1215c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } catch (CanceledException ex) {
1216c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to send result");
1217c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1218c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1219c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1220c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1221c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
1222c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Handle the sent of a single part message or a part of a multipart message
1223c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1224c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1225c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1226c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public void onSent(Context context) {
1227c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            // is single part or last part of multipart message
1228c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            boolean isSinglePartOrLastPart = true;
1229c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mUnsentPartCount != null) {
1230c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1231c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1232c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (isSinglePartOrLastPart) {
1233c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                boolean success = true;
1234c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (mAnyPartFailed != null && mAnyPartFailed.get()) {
1235c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    success = false;
1236c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1237c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (success) {
1238c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    setMessageFinalState(context, Sms.MESSAGE_TYPE_SENT);
1239c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } else {
1240c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    setMessageFinalState(context, Sms.MESSAGE_TYPE_FAILED);
1241c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1242c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1243c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mSentIntent != null) {
1244c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                try {
1245fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    // Extra information to send with the sent intent
1246fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    Intent fillIn = new Intent();
1247fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    if (mMessageUri != null) {
1248fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        // Pass this to SMS apps so that they know where it is stored
1249fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra("uri", mMessageUri.toString());
1250fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    }
1251c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1252c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        // Is multipart and last part
1253fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1254c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1255fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    mSentIntent.send(context, Activity.RESULT_OK, fillIn);
1256c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } catch (CanceledException ex) {
1257c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to send result");
1258c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
12590217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
12600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1263ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1264c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount,
1265c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            AtomicBoolean anyPartFailed, Uri messageUri) {
12661260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get calling app package name via UID from Binder call
12671260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageManager pm = mContext.getPackageManager();
12681260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
12691260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
12701260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get package info via packagemanager
12711260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageInfo appInfo = null;
12721260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (packageNames != null && packageNames.length > 0) {
12731260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            try {
12741260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // XXX this is lossy- apps can share a UID
12751260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
12761260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            } catch (PackageManager.NameNotFoundException e) {
12771260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // error will be logged in sendRawPdu
12781260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
12791260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        }
12801260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Strip non-digits from destination phone number before checking for short codes
12811260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // and before displaying the number to the user if confirmation is required.
12821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
1283c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format,
1284c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                unsentPartCount, anyPartFailed, messageUri);
1285c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1286c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1287c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1288c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent deliveryIntent, String format, Uri messageUri) {
1289c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/,
1290c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                null/*anyPartFailed*/, messageUri);
12911260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
12921260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1293ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
12941260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            String text, SmsMessageBase.SubmitPduBase pdu) {
12951260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
12961260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
12971260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
12981260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("text", text);
12991260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
13001260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
13011260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
13021260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
13031260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1304ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
13051260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
13061260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
13071260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
13081260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
1309ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        map.put("destPort", destPort);
13101260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("data", data);
13111260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
13121260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
13131260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
13141260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
13151260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
13160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
13170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dialog listener for SMS confirmation dialog.
13180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
13190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final class ConfirmDialogListener
13204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
13214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            CompoundButton.OnCheckedChangeListener {
13220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        private final SmsTracker mTracker;
13244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mPositiveButton;
13254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mNegativeButton;
13264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private boolean mRememberChoice;    // default is unchecked
132778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        private final TextView mRememberUndoInstruction;
13280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
132978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener(SmsTracker tracker, TextView textView) {
13300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mTracker = tracker;
133178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt            mRememberUndoInstruction = textView;
13320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setPositiveButton(Button button) {
13354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mPositiveButton = button;
13364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
13374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
13384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setNegativeButton(Button button) {
13394658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mNegativeButton = button;
13404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
13414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
13420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
13430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onClick(DialogInterface dialog, int which) {
13444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Always set the SMS permission so that Settings will show a permission setting
13454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // for the app (it won't be shown until after the app tries to send to a short code).
13464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
13474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
13480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (which == DialogInterface.BUTTON_POSITIVE) {
1349ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "CONFIRM sending SMS");
13502029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1351634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_SENT_BY_USER,
1352ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1353ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 : mTracker.mAppInfo.applicationInfo.uid);
13540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker));
13554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
13564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
13574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
13580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (which == DialogInterface.BUTTON_NEGATIVE) {
1359ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "DENY sending SMS");
13602029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1361634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
1362ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1363ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 :  mTracker.mAppInfo.applicationInfo.uid);
13640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
13654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
13664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
13674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
13680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
13694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            setPremiumSmsPermission(mTracker.mAppInfo.packageName, newSmsPermission);
13700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
13730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onCancel(DialogInterface dialog) {
1374ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "dialog dismissed: don't send SMS");
13750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
13760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
13784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        @Override
13794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1380ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "remember this choice: " + isChecked);
13814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mRememberChoice = isChecked;
13824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (isChecked) {
13834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
13844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
138578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
138678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.
138778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                            setText(R.string.sms_short_code_remember_undo_instruction);
138878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,32);
138978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
13904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            } else {
13914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
13925d875796122cdd8a7004e8e3964b20b5c65a31a1Robert Greenwalt                mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
139378df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
139478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setText("");
139578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,0);
139678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
13974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
13984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
13990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
14001260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1401ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public boolean isIms() {
1402ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1403ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.isIms();
1404ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1405ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1406ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return false;
1407ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1408ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
14091260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1410ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public String getImsSmsFormat() {
1411ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1412ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.getImsSmsFormat();
1413ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1414ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1415ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return null;
1416ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1417ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
1418c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1419c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected Uri writeOutboxMessage(long subId, String address, String text,
1420b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            boolean requireDeliveryReport, String creator) {
1421b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        if (!Telephony.AUTO_PERSIST) {
1422370971c25973d9d8061b76e756df2fb8c1ebd990Ye Wen            // TODO(ywen): Temporarily only enable this with a flag so not to break existing apps
1423c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return null;
1424c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1425b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        final ContentValues values = new ContentValues(8);
1426c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.SUB_ID, subId);
1427c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.ADDRESS, address);
1428b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        values.put(Telephony.Sms.BODY, text);
1429c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.DATE, System.currentTimeMillis()); // milliseconds
1430c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.SEEN, 1);
1431c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.READ, 1);
1432b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        if (!TextUtils.isEmpty(creator)) {
1433b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            values.put(Telephony.Sms.CREATOR, creator);
1434b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        }
1435c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        if (requireDeliveryReport) {
1436c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            values.put(Telephony.Sms.STATUS, Telephony.Sms.STATUS_PENDING);
1437c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1438c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final long identity = Binder.clearCallingIdentity();
1439c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        try {
1440c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final Uri uri =  mContext.getContentResolver().insert(
1441c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Telephony.Sms.Outbox.CONTENT_URI, values);
1442c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return uri;
1443c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        } catch (Exception e) {
1444b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
1445c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return null;
1446c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        } finally {
1447c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Binder.restoreCallingIdentity(identity);
1448c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1449c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1450c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1451b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    protected void moveToOutbox(long subId, Uri messageUri, String creator) {
1452b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        final ContentValues values = new ContentValues(4);
1453b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        values.put(Telephony.Sms.SUB_ID, subId);
1454b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        if (!TextUtils.isEmpty(creator)) {
1455b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            // Reset creator/sender
1456b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            values.put(Telephony.Sms.CREATOR, creator);
1457b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        }
1458b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        // Reset the timestamp
1459b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        values.put(Telephony.Sms.DATE, System.currentTimeMillis()); // milliseconds
1460b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        values.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_OUTBOX);
1461b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        final long identity = Binder.clearCallingIdentity();
1462b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        try {
1463b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            if (mContext.getContentResolver().update(messageUri, values,
1464b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                    null/*where*/, null/*selectionArgs*/) != 1) {
1465b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                Rlog.e(TAG, "moveToOutbox: failed to update message " + messageUri);
1466b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            }
1467b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        } catch (Exception e) {
1468b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            Rlog.e(TAG, "moveToOutbox: Failed to update message", e);
1469b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        } finally {
1470b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            Binder.restoreCallingIdentity(identity);
1471b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        }
1472b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    }
1473b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen
1474c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    private String getMultipartMessageText(ArrayList<String> parts) {
1475c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final StringBuilder sb = new StringBuilder();
1476c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        for (String part : parts) {
1477c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (part != null) {
1478c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                sb.append(part);
1479c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1480c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1481c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return sb.toString();
1482c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1483b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen
1484b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    protected long getSubId() {
1485b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.mPhoneId);
1486b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    }
14870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
1488