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;
18ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wangimport android.annotation.Nullable;
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.Activity;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.AlertDialog;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent;
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent.CanceledException;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ContentResolver;
240217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.content.ContentValues;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Context;
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.DialogInterface;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Intent;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.ApplicationInfo;
292029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.content.pm.PackageInfo;
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.PackageManager;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources;
32ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.database.ContentObserver;
330217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.database.sqlite.SqliteWrapper;
340217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.net.Uri;
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.AsyncResult;
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Binder;
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler;
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
39f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawalimport android.os.Process;
408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.os.RemoteException;
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.SystemProperties;
42f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawalimport android.os.UserHandle;
43ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.provider.Settings;
440217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.provider.Telephony;
450217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.provider.Telephony.Sms;
468215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.CarrierMessagingService;
478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.ICarrierMessagingCallback;
488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.ICarrierMessagingService;
498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.telephony.CarrierMessagingServiceManager;
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.PhoneNumberUtils;
510d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.Rlog;
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.ServiceState;
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.TelephonyManager;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Html;
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Spanned;
56b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wenimport android.text.TextUtils;
572029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.util.EventLog;
584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.LayoutInflater;
594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.View;
6078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwaltimport android.view.ViewGroup;
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.WindowManager;
624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.Button;
634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CheckBox;
644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CompoundButton;
654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.TextView;
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.R;
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
69a9552aa6bf3ce12c75ad43165034d9a1233fb131Shishir Agrawalimport com.android.internal.telephony.uicc.UiccCard;
70c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawalimport com.android.internal.telephony.uicc.UiccController;
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap;
748d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport java.util.List;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Random;
76c99dab56e20222b28cbc6238645feac938f1c333Ye Wenimport java.util.concurrent.atomic.AtomicBoolean;
770d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.concurrent.atomic.AtomicInteger;
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic abstract class SMSDispatcher extends Handler {
87cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final String TAG = "SMSDispatcher";    // accessed from inner class
88cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final boolean DBG = false;
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Permission required to send SMS to short codes without user confirmation. */
92ce058be9f5bcfdaa531f1b480ca5ed051b84e72eTom Taylor    private static final String SEND_RESPOND_VIA_MESSAGE_PERMISSION =
93ce058be9f5bcfdaa531f1b480ca5ed051b84e72eTom Taylor            "android.permission.SEND_RESPOND_VIA_MESSAGE";
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
95ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_SIM = 1;
96ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_NETWORK = 2;
97ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_BOTH = 3;
98ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
99ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final SettingsObserver mSettingsObserver;
100ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** SMS send complete. */
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int EVENT_SEND_SMS_COMPLETE = 2;
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Retry sending a previously failed SMS message */
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_RETRY = 3;
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for sending a large number of messages. */
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Send the user confirmed SMS */
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_SEND_CONFIRMED_SMS = 5;  // accessed from inner class
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Don't send SMS (user did not confirm). */
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_STOP_SENDING = 7;        // accessed from inner class
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1220d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /** Handle status report from {@code CdmaInboundSmsHandler}. */
1230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected static final int EVENT_HANDLE_STATUS_REPORT = 10;
1240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1251260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Radio is ON */
1261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_RADIO_ON = 11;
1271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** IMS registration/SMS format changed */
1291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_CHANGED = 12;
1301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1311260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */
1321260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_DONE = 13;
1331260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1341260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    // other
1351260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_NEW_ICC_SMS = 14;
1361260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_ICC_CHANGED = 15;
1371260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1381260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected PhoneBase mPhone;
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final Context mContext;
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ContentResolver mResolver;
14122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville    protected final CommandsInterface mCi;
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final TelephonyManager mTelephonyManager;
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Maximum number of times to retry sending a failed SMS. */
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MAX_SEND_RETRIES = 3;
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Delay before next send attempt on a failed SMS, in milliseconds. */
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SEND_RETRY_DELAY = 2000;
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** single part SMS */
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SINGLE_PART_SMS = 1;
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Message sending queue limit */
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MO_MSG_QUEUE_LIMIT = 5;
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Message reference for a CONCATENATED_8_BIT_REFERENCE or
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CONCATENATED_16_BIT_REFERENCE message set.  Should be
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * incremented for each set of concatenated messages.
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Static field shared by all dispatcher objects.
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int sConcatenatedRef = new Random().nextInt(256);
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Outgoing message counter. Shared by all dispatchers. */
1621260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    private SmsUsageMonitor mUsageMonitor;
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
164ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    private ImsSMSDispatcher mImsSMSDispatcher;
165ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Number of outgoing SmsTrackers waiting for user confirmation. */
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mPendingTrackerCount;
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* Flags indicating whether the current device allows sms service */
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsCapable = true;
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsSendDisabled;
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static int getNextConcatenatedRef() {
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sConcatenatedRef += 1;
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return sConcatenatedRef;
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SMS dispatcher.
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param phone the Phone to use
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param usageMonitor the SmsUsageMonitor to use
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
183ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor,
184ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            ImsSMSDispatcher imsSMSDispatcher) {
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhone = phone;
186ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        mImsSMSDispatcher = imsSMSDispatcher;
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mContext = phone.getContext();
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mResolver = mContext.getContentResolver();
18922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi = phone.mCi;
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mUsageMonitor = usageMonitor;
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
192ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
193ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
194ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsCapable = mContext.getResources().getBoolean(
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                com.android.internal.R.bool.config_sms_capable);
198e70617d81dcd42350a737b11c25532e1d43df4ffLegler Wu        mSmsSendDisabled = !mTelephonyManager.getSmsSendCapableForPhone(
199e70617d81dcd42350a737b11c25532e1d43df4ffLegler Wu                mPhone.getPhoneId(), mSmsCapable);
200ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + " mSmsSendDisabled=" + mSmsSendDisabled);
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
204ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    /**
205ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     * Observe the secure setting for updated premium sms determination rules
206ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     */
207ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static class SettingsObserver extends ContentObserver {
208ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final AtomicInteger mPremiumSmsRule;
209ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final Context mContext;
210ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
211ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            super(handler);
212ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule = premiumSmsRule;
213ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mContext = context;
214ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            onChange(false); // load initial value;
215ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
216ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
217ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        @Override
218ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        public void onChange(boolean selfChange) {
219ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
220ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
221ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
222ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    }
223ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
2241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void updatePhoneObject(PhoneBase phone) {
2251260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mPhone = phone;
2261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mUsageMonitor = phone.mSmsUsageMonitor;
2271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() );
2281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
2291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Unregister for incoming SMS events. */
2310d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    public void dispose() {
2320d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
2330d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The format of the message PDU in the associated broadcast intent.
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Note: All applications which handle incoming SMS messages by processing the
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * into the new methods in {@link android.telephony.SmsMessage} which take an
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * extra format parameter. This is required in order to correctly decode the PDU on
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * devices which require support for both 3GPP and 3GPP2 formats at the same time,
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * such as CDMA/LTE devices and GSM/CDMA world phones.
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the format of the message PDU
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract String getFormat();
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
2520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports
2530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}.
2540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param o the SmsMessage containing the status report
2550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
2560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected void handleStatusReport(Object o) {
2570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        Rlog.d(TAG, "handleStatusReport() called with no subclass.");
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* TODO: Need to figure out how to keep track of status report routing in a
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       persistent manner. If the phone process restarts (reboot or crash),
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       we will lose this list and any status reports that come in after
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       will be dropped.
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Sent messages awaiting a delivery status report. */
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles events coming from the phone stack. Overridden from handler.
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg the message to handle
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msg.what) {
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_SMS_COMPLETE:
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // An outbound SMS has been successfully transferred, or failed.
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleSendComplete((AsyncResult) msg.obj);
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_RETRY:
2821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            Rlog.d(TAG, "SMS retry..");
2831260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            sendRetrySms((SmsTracker) msg.obj);
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleReachSentLimit((SmsTracker)(msg.obj));
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(false, (SmsTracker)(msg.obj));
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(true, (SmsTracker)(msg.obj));
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_CONFIRMED_SMS:
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.isMultipart()) {
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMultipartSms(tracker);
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
3046c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                if (mPendingTrackerCount > 1) {
3056c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                    tracker.mExpectMore = true;
3066c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                } else {
3076c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                    tracker.mExpectMore = false;
3086c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                }
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_STOP_SENDING:
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
318c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        case EVENT_HANDLE_STATUS_REPORT:
3240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            handleStatusReport(msg.obj);
3250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            break;
3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        default:
3280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
3290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
330b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    }
331b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
332b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    /**
3338215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a data or text SMS.
3348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
3358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract class SmsSender extends CarrierMessagingServiceManager {
3368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected final SmsTracker mTracker;
3378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        // Initialized in sendSmsByCarrierApp
3388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected volatile SmsSenderCallback mSenderCallback;
3398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected SmsSender(SmsTracker tracker) {
3418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mTracker = tracker;
3428215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3448215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void sendSmsByCarrierApp(String carrierPackageName,
3458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                        SmsSenderCallback senderCallback) {
3468215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSenderCallback = senderCallback;
3478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
3488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "bindService() for carrier messaging service failed");
3498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
3508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3518215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
3528215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
3538215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
3548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
3558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
3578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
358ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang    private static int getSendSmsFlag(@Nullable PendingIntent deliveryIntent) {
359ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang        if (deliveryIntent == null) {
360ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang            return 0;
361ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang        }
362ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang        return CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS;
363ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang    }
364ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang
3658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
3668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a text SMS.
3678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
3688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class TextSmsSender extends SmsSender {
3698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public TextSmsSender(SmsTracker tracker) {
3708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            super(tracker);
3718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
3748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
3758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            HashMap<String, Object> map = mTracker.mData;
3768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            String text = (String) map.get("text");
3778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (text != null) {
3798215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                try {
3808215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    carrierMessagingService.sendTextSms(text, getSubId(),
381ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                            mTracker.mDestAddress, getSendSmsFlag(mTracker.mDeliveryIntent),
382ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                            mSenderCallback);
3838215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } catch (RemoteException e) {
3848215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Exception sending the SMS: " + e);
3858215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    mSenderCallback.onSendSmsComplete(
3868215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            0 /* messageRef */);
3888215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
3898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
3908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
3918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
3938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
3948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
3968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
3988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a data SMS.
3998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
4008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class DataSmsSender extends SmsSender {
4018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public DataSmsSender(SmsTracker tracker) {
4028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            super(tracker);
4038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
4078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            HashMap<String, Object> map = mTracker.mData;
4088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            byte[] data = (byte[]) map.get("data");
4098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            int destPort = (int) map.get("destPort");
4108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (data != null) {
4128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                try {
4138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    carrierMessagingService.sendDataSms(data, getSubId(),
414ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                            mTracker.mDestAddress, destPort,
415ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                            getSendSmsFlag(mTracker.mDeliveryIntent), mSenderCallback);
4168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } catch (RemoteException e) {
4178215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Exception sending the SMS: " + e);
4188215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    mSenderCallback.onSendSmsComplete(
4198215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
4208215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            0 /* messageRef */);
4218215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
4228215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
4238215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
4248215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
4258215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
4268215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
4278215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4288215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
4298215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4308215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
4318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Callback for TextSmsSender and DataSmsSender from the carrier messaging service.
4328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Once the result is ready, the carrier messaging service connection is disposed.
4338215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
4348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class SmsSenderCallback extends ICarrierMessagingCallback.Stub {
4358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final SmsSender mSmsSender;
4368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public SmsSenderCallback(SmsSender smsSender) {
4388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender = smsSender;
4398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        /**
4428215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         * This method should be called only once.
4438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         */
4448215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendSmsComplete(int result, int messageRef) {
446f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            checkCallerIsPhoneOrCarrierApp();
447f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            final long identity = Binder.clearCallingIdentity();
448f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            try {
449f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                mSmsSender.disposeConnection(mContext);
450f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
451f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            } finally {
452f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                Binder.restoreCallingIdentity(identity);
453f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            }
4548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
4588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result);
4598215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4608215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4618215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4628215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onFilterComplete(boolean keepMessage) {
4638215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + keepMessage);
4648215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
4688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
4698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onDownloadMmsComplete(int result) {
4738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
4748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
4768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private void processSendSmsResponse(SmsTracker tracker, int result, int messageRef) {
4788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (tracker == null) {
4798215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "processSendSmsResponse: null tracker");
4808215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            return;
4818215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4828215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4838215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        SmsResponse smsResponse = new SmsResponse(
4848215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                messageRef, null /* ackPdu */, -1 /* unknown error code */);
4858215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4868215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        switch (result) {
4878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_OK:
4888215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP succeeded.");
4898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
4908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                      new AsyncResult(tracker,
4918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                                      smsResponse,
4928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                                      null /* exception*/ )));
4938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
4948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_ERROR:
4958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP failed.");
4968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
4978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    new AsyncResult(tracker, smsResponse,
4988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            new CommandException(CommandException.Error.GENERIC_FAILURE))));
4998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
5008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
5018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP failed. Retry on carrier network.");
5028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendSubmitPdu(tracker);
5038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
5048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        default:
5058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Unknown result " + result + " Retry on carrier network.");
5068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendSubmitPdu(tracker);
5078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
5098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
5118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a multipart text SMS.
5128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
5138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private final class MultipartSmsSender extends CarrierMessagingServiceManager {
5148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final List<String> mParts;
5158215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public final SmsTracker[] mTrackers;
5168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        // Initialized in sendSmsByCarrierApp
5178215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private volatile MultipartSmsSenderCallback mSenderCallback;
5188215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5198215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) {
5208215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mParts = parts;
5218215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mTrackers = trackers;
5228215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5238215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5248215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        void sendSmsByCarrierApp(String carrierPackageName,
5258215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                 MultipartSmsSenderCallback senderCallback) {
5268215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSenderCallback = senderCallback;
5278215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
5288215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "bindService() for carrier messaging service failed");
5298215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendMultipartSmsComplete(
5308215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
5318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        null /* smsResponse */);
5328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
5338215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
5348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
5398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            try {
5408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                carrierMessagingService.sendMultipartTextSms(
541ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                        mParts, getSubId(), mTrackers[0].mDestAddress,
542ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                        getSendSmsFlag(mTrackers[0].mDeliveryIntent), mSenderCallback);
5438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } catch (RemoteException e) {
5448215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "Exception sending the SMS: " + e);
5458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendMultipartSmsComplete(
5468215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
5478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        null /* smsResponse */);
5488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
5518215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5528215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
5538215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Callback for MultipartSmsSender from the carrier messaging service.
5548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Once the result is ready, the carrier messaging service connection is disposed.
5558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
5568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private final class MultipartSmsSenderCallback extends ICarrierMessagingCallback.Stub {
5578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final MultipartSmsSender mSmsSender;
5588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5598215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        MultipartSmsSenderCallback(MultipartSmsSender smsSender) {
5608215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender = smsSender;
5618215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5628215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5638215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5648215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendSmsComplete(int result, int messageRef) {
5658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result);
5668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        /**
5698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         * This method should be called only once.
5708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         */
5718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
5738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender.disposeConnection(mContext);
5748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (mSmsSender.mTrackers == null) {
5768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers.");
5778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                return;
5788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5798215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
580f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            checkCallerIsPhoneOrCarrierApp();
581f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            final long identity = Binder.clearCallingIdentity();
582f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            try {
583f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                for (int i = 0; i < mSmsSender.mTrackers.length; i++) {
584f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                    int messageRef = 0;
585f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                    if (messageRefs != null && messageRefs.length > i) {
586f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                        messageRef = messageRefs[i];
587f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                    }
588f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                    processSendSmsResponse(mSmsSender.mTrackers[i], result, messageRef);
5898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
590f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            } finally {
591f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                Binder.restoreCallingIdentity(identity);
5928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onFilterComplete(boolean keepMessage) {
5978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + keepMessage);
5988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
6008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
6018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
6028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
6038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
6048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
6058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
6068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onDownloadMmsComplete(int result) {
6078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
6088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
6098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
6108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
6118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
6128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Send an SMS PDU. Usually just calls {@link sendRawPdu}.
6138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
6148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract void sendSubmitPdu(SmsTracker tracker);
6158215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
6168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Called when SMS send completes. Broadcasts a sentIntent on success.
6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * On failure, either sets up retries or broadcasts a sentIntent with
6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the failure in the result code.
6200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ar AsyncResult passed into the message handler.  ar.result should
6220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           an SmsResponse instance if send was successful.  ar.userObj
6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           should be an SmsTracker instance.
6240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleSendComplete(AsyncResult ar) {
6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsTracker tracker = (SmsTracker) ar.userObj;
6270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PendingIntent sentIntent = tracker.mSentIntent;
6280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
629454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        if (ar.result != null) {
6305a176f73dbb2bff2ca8b8f86af86a17be6863b87Wink Saville            tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
631454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        } else {
632454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks            Rlog.d(TAG, "SmsResponse was null");
633454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        }
634454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks
6350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (ar.exception == null) {
636cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
6370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.mDeliveryIntent != null) {
6390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Expecting a status report.  Add it to the list.
6400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryPendingList.add(tracker);
6410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
642c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onSent(mContext);
6430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
644cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send failed");
6450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6481260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
6491260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // This is retry after failure over IMS but voice is not available.
6501260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // Set retry to max allowed, so no retry is sent and
6511260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.
6521260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                tracker.mRetryCount = MAX_SEND_RETRIES;
6531260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
6541260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                Rlog.d(TAG, "handleSendComplete: Skipping retry: "
6551260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" isIms()="+isIms()
6561260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mRetryCount="+tracker.mRetryCount
6571260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mImsRetry="+tracker.mImsRetry
6581260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mMessageRef="+tracker.mMessageRef
6591260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" SS= "+mPhone.getServiceState().getState());
6601260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
6611260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
6621260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            // if sms over IMS is not supported on data and voice is not available...
6631260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
664c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
6650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if ((((CommandException)(ar.exception)).getCommandError()
6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    == CommandException.Error.SMS_FAIL_RETRY) &&
6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                   tracker.mRetryCount < MAX_SEND_RETRIES) {
6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Retry after a delay if needed.
6690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // TODO: According to TS 23.040, 9.2.3.6, we should resend
6700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       with the same TP-MR as the failed message, and
6710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       TP-RD set to 1.  However, we don't have a means of
6720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       knowing the MR for the failed message (EF_SMSstatus
6730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       may or may not have the MR corresponding to this
6740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       message, depending on the failure).  Also, in some
6750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       implementations this retry is handled by the baseband.
6760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tracker.mRetryCount++;
6770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
6780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
679c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } else {
680c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                int errorCode = 0;
681c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (ar.result != null) {
682c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    errorCode = ((SmsResponse)ar.result).mErrorCode;
683c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
6840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int error = RESULT_ERROR_GENERIC_FAILURE;
6850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (((CommandException)(ar.exception)).getCommandError()
6860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        == CommandException.Error.FDN_CHECK_FAILURE) {
6870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    error = RESULT_ERROR_FDN_CHECK_FAILURE;
6880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
689c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, error, errorCode);
6900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
6950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles outbound message when the phone is not in service.
6960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
6970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ss     Current service state.  Valid values are:
6980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  OUT_OF_SERVICE
6990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  EMERGENCY_ONLY
7000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  POWER_OFF
7010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent the PendingIntent to send the error to
7020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static void handleNotInService(int ss, PendingIntent sentIntent) {
7040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (sentIntent != null) {
7050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
7060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ss == ServiceState.STATE_POWER_OFF) {
7070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_RADIO_OFF);
7080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
7090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NO_SERVICE);
7100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
7110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CanceledException ex) {}
7120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
716c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     * @param ss service state
717c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     * @return The result error based on input service state for not in service error
718c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     */
719c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected static int getNotInServiceError(int ss) {
720c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        if (ss == ServiceState.STATE_POWER_OFF) {
721c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return RESULT_ERROR_RADIO_OFF;
722c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
723c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return RESULT_ERROR_NO_SERVICE;
724c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
725c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
726c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    /**
7270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a data based SMS to a specific application port.
7280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
7300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
7310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
7320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destPort the port to deliver the message to
7330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data the body of the message to send
7340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
7350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
7360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
7370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
7380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
7390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
7400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
7410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
7420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
7430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
7440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
7450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
7460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
7470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
7480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
7490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
7500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
7510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendData(String destAddr, String scAddr, int destPort,
7530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent);
7540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a text based SMS.
757b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     *  @param destAddr the address to send the message to
7580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
7590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
7600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param text the body of the message to send
7610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
7620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
7630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
7640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
7650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
7660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
7670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
7680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
7690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
7700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
7710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
7720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
7730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
7740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
7750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
7760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
777b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param messageUri optional URI of the message if it is already stored in the system
778b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param callingPkg the calling package name
779a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang     * @param persistMessage whether to save the sent message into SMS DB for a
780a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang     *   non-default SMS app.
7810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
782b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    protected abstract void sendText(String destAddr, String scAddr, String text,
783b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri,
784a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            String callingPkg, boolean persistMessage);
7850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
78763418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * Inject an SMS PDU into the android platform.
78863418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *
78963418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param pdu is the byte array of pdu to be injected into android telephony layer
79063418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param format is the format of SMS pdu (3gpp or 3gpp2)
79163418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
79263418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  broadcast when the message is successfully received by the
79363418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  android telephony layer. This intent is broadcasted at
79463418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  the same time an SMS received from radio is responded back.
79563418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     */
79663418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni    protected abstract void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent);
79763418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni
79863418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni    /**
7993ce96a061c2c6e24f4ff3bd237e18c29fc0c0108Amit Mahajan     * Calculate the number of septets needed to encode the message. This function should only be
8003ce96a061c2c6e24f4ff3bd237e18c29fc0c0108Amit Mahajan     * called for individual segments of multipart message.
8010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
8020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param messageBody the message to encode
8030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param use7bitOnly ignore (but still count) illegal characters if true
8040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return TextEncodingDetails
8050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
8070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean use7bitOnly);
8080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a multi-part text based SMS.
811b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     *  @param destAddr the address to send the message to
8120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
8130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   the current default SMSC
8140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param parts an <code>ArrayList</code> of strings that, in order,
8150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   comprise the original message
8160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntents if not null, an <code>ArrayList</code> of
8170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
8180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been sent.
8190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   The result code will be <code>Activity.RESULT_OK<code> for success,
8200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   or one of these errors:
8210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
8220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_RADIO_OFF</code>
8230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NULL_PDU</code>
8240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NO_SERVICE</code>.
8250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
8260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
8270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
8280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntents if not null, an <code>ArrayList</code> of
8290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
8300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been delivered
8310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   to the recipient.  The raw pdu of the status report is in the
832b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param messageUri optional URI of the message if it is already stored in the system
833b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param callingPkg the calling package name
834a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang     * @param persistMessage whether to save the sent message into SMS DB for a
835a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang     *   non-default SMS app.
8360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendMultipartText(String destAddr, String scAddr,
8380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
839a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
840a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            boolean persistMessage) {
8414bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        final String fullMessageText = getMultipartMessageText(parts);
8420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int refNumber = getNextConcatenatedRef() & 0x00FF;
8430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgCount = parts.size();
8440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int encoding = SmsConstants.ENCODING_UNKNOWN;
8450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
8470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
8480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            TextEncodingDetails details = calculateLength(parts.get(i), false);
8490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding != details.codeUnitSize
8500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    && (encoding == SmsConstants.ENCODING_UNKNOWN
8510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            || encoding == SmsConstants.ENCODING_7BIT)) {
8520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encoding = details.codeUnitSize;
8530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            encodingForParts[i] = details;
8550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        SmsTracker[] trackers = new SmsTracker[msgCount];
8588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
859c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        // States to track at the message level (for all parts)
860c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
861c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
862c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
8630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
8640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
8650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.refNumber = refNumber;
8660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.seqNumber = i + 1;  // 1-based sequence
8670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.msgCount = msgCount;
8680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // TODO: We currently set this to true since our messaging app will never
8690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // send more than 255 parts (it converts the message to MMS well before that).
8700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // However, we should support 3rd party messaging apps that might need 16-bit
8710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // references
8720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Note:  It's not sufficient to just flip this bit to true; it will have
8730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // ripple effects (several calculations assume 8-bit ref).
8740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.isEightBits = true;
8750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader smsHeader = new SmsHeader();
8760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsHeader.concatRef = concatRef;
8770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Set the national language tables for 3GPP 7-bit encoding, if enabled.
8790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding == SmsConstants.ENCODING_7BIT) {
8800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageTable = encodingForParts[i].languageTable;
8810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
8820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent = null;
8850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntents != null && sentIntents.size() > i) {
8860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sentIntent = sentIntents.get(i);
8870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent deliveryIntent = null;
8900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (deliveryIntents != null && deliveryIntents.size() > i) {
8910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryIntent = deliveryIntents.get(i);
8920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            trackers[i] =
8958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding,
8968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        sentIntent, deliveryIntent, (i == (msgCount - 1)),
8978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        unsentPartCount, anyPartFailed, messageUri, fullMessageText);
898a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            trackers[i].mPersistMessage = persistMessage;
8998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
9008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
9018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (parts == null || trackers == null || trackers.length == 0
9028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                || trackers[0] == null) {
9038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers);
9048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            return;
9058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
9068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
9078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        String carrierPackage = getCarrierAppPackageName();
9088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (carrierPackage != null) {
9098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Found carrier package.");
9108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
9118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            smsSender.sendSmsByCarrierApp(carrierPackage, new MultipartSmsSenderCallback(smsSender));
9128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        } else {
9138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.v(TAG, "No carrier package.");
9148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            for (SmsTracker tracker : trackers) {
9158215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                if (tracker != null) {
9168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    sendSubmitPdu(tracker);
9178215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } else {
9188215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Null tracker.");
9198215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
9208215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
9210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
9230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9258215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Create a new SubmitPdu and return the SMS tracker.
9260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9278215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
9280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String message, SmsHeader smsHeader, int encoding,
929c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
9304bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
9314bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            String fullMessageText);
9320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Send an SMS
9351260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker will contain:
9361260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -smsc the SMSC to send the message through, or NULL for the
9370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  default SMSC
9381260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -pdu the raw PDU to send
9391260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -sentIntent if not NULL this <code>Intent</code> is
9400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
9410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
9420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:
9430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
9440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code>
9450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code>
9460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code>.
9470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
9480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
9490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
9501260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -deliveryIntent if not NULL this <code>Intent</code> is
9510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
9520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
9531260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -param destAddr the destination phone number (for short code confirmation)
9540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9551260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void sendRawPdu(SmsTracker tracker) {
9561260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap map = tracker.mData;
9571260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        byte pdu[] = (byte[]) map.get("pdu");
9581260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
9590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mSmsSendDisabled) {
960c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Device does not support sending sms.");
961c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
9620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pdu == null) {
966c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Empty PDU");
967c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);
9680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Get calling app package name via UID from Binder call
9720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
9730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
9740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (packageNames == null || packageNames.length == 0) {
9760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Refuse to send SMS if we can't get the calling package name.
977ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");
978c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
9790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9822029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        // Get package info via packagemanager
9830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        PackageInfo appInfo;
9842029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        try {
9852029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            // XXX this is lossy- apps can share a UID
9862029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
9872029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        } catch (PackageManager.NameNotFoundException e) {
988ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
989c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
9902029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            return;
9912029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        }
9920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // checkDestination() returns true if the destination is not a premium short code or the
9940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // sending app is approved to send to short codes. Otherwise, a message is sent to our
9950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // handler with the SmsTracker to request user confirmation before sending.
9960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (checkDestination(tracker)) {
9970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // check for excessive outgoing SMS usage by this app
9982029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
9990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
10000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
10010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1003a0c22039b77054d659151537896c1db90c7057f7Shishir Agrawal            sendSms(tracker);
10040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Check if destination is a potential premium short code and sender is not pre-approved to
10090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * send to short codes.
10100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
10110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the tracker for the SMS to send
10120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the destination is approved; false if user confirmation event was sent
10130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean checkDestination(SmsTracker tracker) {
1015ce058be9f5bcfdaa531f1b480ca5ed051b84e72eTom Taylor        if (mContext.checkCallingOrSelfPermission(SEND_RESPOND_VIA_MESSAGE_PERMISSION)
10160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                == PackageManager.PERMISSION_GRANTED) {
10170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;            // app is pre-approved to send to short codes
10180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
1019ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int rule = mPremiumSmsRule.get();
1020ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
1021ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
1022ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String simCountryIso = mTelephonyManager.getSimCountryIso();
1023ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (simCountryIso == null || simCountryIso.length() != 2) {
1024ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso");
1025ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    simCountryIso = mTelephonyManager.getNetworkCountryIso();
1026ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
1027ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1028ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                smsCategory = mUsageMonitor.checkDestination(tracker.mDestAddress, simCountryIso);
1029ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            }
1030ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
1031ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String networkCountryIso = mTelephonyManager.getNetworkCountryIso();
1032ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (networkCountryIso == null || networkCountryIso.length() != 2) {
1033ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso");
1034ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    networkCountryIso = mTelephonyManager.getSimCountryIso();
1035ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
1036ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1037cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville                smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory,
1038ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                        mUsageMonitor.checkDestination(tracker.mDestAddress, networkCountryIso));
10390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1041ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE
1042ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE
1043ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) {
10444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                return true;    // not a premium short code
10454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
10464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
10474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Wait for user confirmation unless the user has set permission to always allow/deny
10484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int premiumSmsPermission = mUsageMonitor.getPremiumSmsPermission(
10494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    tracker.mAppInfo.packageName);
10504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
10514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                // First time trying to send to premium SMS.
10524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
10534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
10540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            switch (premiumSmsPermission) {
10564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
1057ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.d(TAG, "User approved this app to send to premium SMS");
10584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return true;
10590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
1061ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.w(TAG, "User denied this app from sending to premium SMS");
10624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(EVENT_STOP_SENDING, tracker));
10634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // reject this message
10644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
10654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
10660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                default:
10674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    int event;
1068ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
10694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
10704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    } else {
10714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
10724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    }
10734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(event, tracker));
10744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // wait for user confirmation
10750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Deny sending an SMS if the outgoing queue limit is reached. Used when the message
10810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * must be confirmed by the user due to excessive usage or potential premium SMS detected.
10820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the message to send
10830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the message was denied; false to continue with send confirmation
10840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean denyIfQueueLimitReached(SmsTracker tracker) {
10860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
10870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Deny sending message when the queue limit is reached.
1088c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Denied because queue limit reached");
1089c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
10900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;
10910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPendingTrackerCount++;
10930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return false;
10940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns the label for the specified app package name.
10980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param appPackage the package name of the app requesting to send an SMS
10990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the label for the specified app, or the package name if getApplicationInfo() fails
11000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private CharSequence getAppLabel(String appPackage) {
11020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
11030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
11040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ApplicationInfo appInfo = pm.getApplicationInfo(appPackage, 0);
11050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appInfo.loadLabel(pm);
11060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (PackageManager.NameNotFoundException e) {
1107ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
11080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appPackage;  // fall back to package name if we can't get app label
11090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert when SMS needs confirmation due to excessive usage.
11140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker an SmsTracker for the current message.
11150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleReachSentLimit(SmsTracker tracker) {
11170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
11180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
11190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11212029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
11220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
11230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
11240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
112578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null);
11260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
11280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setTitle(R.string.sms_control_title)
11290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setIcon(R.drawable.stat_sys_warning)
11300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setMessage(messageText)
11310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
11320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_control_no), listener)
11330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
11340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
11350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
11370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
11380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert for user confirmation when sending to a potential short code.
11420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param isPremium true if the destination is known to be a premium short code
11430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the current message.
11440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) {
11460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
11470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
11480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        int detailsId;
11510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isPremium) {
11524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_premium_short_code_details;
11530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
11544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_short_code_details;
11550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11572029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
11580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
11594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
11604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                appLabel, tracker.mDestAddress));
11610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
11634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                Context.LAYOUT_INFLATER_SERVICE);
11644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
11654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
116678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
116778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                (TextView)layout.findViewById(R.id.sms_short_code_remember_undo_instruction));
116878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
116978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
11704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
11714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        messageView.setText(messageText);
11724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
117378df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
11744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_layout);
11754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView detailsView = (TextView) detailsLayout.findViewById(
11764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_message);
11774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        detailsView.setText(detailsId);
11784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        CheckBox rememberChoice = (CheckBox) layout.findViewById(
11804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_remember_choice_checkbox);
11814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        rememberChoice.setOnCheckedChangeListener(listener);
11824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
11844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                .setView(layout)
11850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
11860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
11870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
11880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
11890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
11910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
11924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11934658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
11944658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
11954658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
11964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
11984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Returns the premium SMS permission for the specified package. If the package has never
11994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}
12004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * will be returned.
12014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to query permission
12024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
12034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
12044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
12054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
12064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
12074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public int getPremiumSmsPermission(String packageName) {
12084658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        return mUsageMonitor.getPremiumSmsPermission(packageName);
12094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
12104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
12124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Sets the premium SMS permission for the specified package and save the value asynchronously
12134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * to persistent storage.
12144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to set permission
12154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
12164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
12174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
12184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
12194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public void setPremiumSmsPermission(String packageName, int permission) {
12204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        mUsageMonitor.setPremiumSmsPermission(packageName, permission);
12210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the message along to the radio.
12250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the SMS message to send
12270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendSms(SmsTracker tracker);
12290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12318d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Send the SMS via the PSTN network.
12328d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *
12338d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param tracker holds the Sms tracker ready to be sent
12348d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
12358d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected abstract void sendSmsByPstn(SmsTracker tracker);
12368d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
12378d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
12381260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * Retry the message along to the radio.
12391260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     *
12401260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker holds the SMS message to send
12411260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     */
1242ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public void sendRetrySms(SmsTracker tracker) {
1243ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        // re-routing to ImsSMSDispatcher
1244ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1245ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            mImsSMSDispatcher.sendRetrySms(tracker);
1246ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1247ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null. Retry failed");
1248ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1249ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
12501260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
12511260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /**
12520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the multi-part SMS based on multipart Sms tracker
12530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the multipart Sms tracker ready to be sent
12550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void sendMultipartSms(SmsTracker tracker) {
12570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<String> parts;
12580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> sentIntents;
12590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> deliveryIntents;
12600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        HashMap<String, Object> map = tracker.mData;
12620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String destinationAddress = (String) map.get("destination");
12640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String scAddress = (String) map.get("scaddress");
12650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        parts = (ArrayList<String>) map.get("parts");
12670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
12680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
12690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // check if in service
12710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int ss = mPhone.getServiceState().getState();
12721260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // if sms over IMS is not supported on data and voice is not available...
12731260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
12740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0, count = parts.size(); i < count; i++) {
12750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                PendingIntent sentIntent = null;
12760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (sentIntents != null && sentIntents.size() > i) {
12770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent = sentIntents.get(i);
12780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
12790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, sentIntent);
12800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
12810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
12820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1284b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents,
1285a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang                null/*messageUri*/, null/*callingPkg*/, tracker.mPersistMessage);
12860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Keeps track of an SMS that has been sent to the RIL, until it has
12900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * successfully been sent, or we're done trying.
12910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final class SmsTracker {
12930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // fields need to be public for derived SmsDispatchers
12940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final HashMap<String, Object> mData;
12950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mRetryCount;
12961260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        public int mImsRetry; // nonzero indicates initial message was sent over Ims
12970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mMessageRef;
12986ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi        public boolean mExpectMore;
12991260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String mFormat;
13000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mSentIntent;
13020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mDeliveryIntent;
13030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13042029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        public final PackageInfo mAppInfo;
13050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final String mDestAddress;
13060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
130778d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal        public final SmsHeader mSmsHeader;
130878d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal
13090217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        private long mTimestamp = System.currentTimeMillis();
1310c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public Uri mMessageUri; // Uri of persisted message if we wrote one
1311c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1312c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        // Reference to states of a multipart message that this part belongs to
1313c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private AtomicInteger mUnsentPartCount;
1314c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private AtomicBoolean mAnyPartFailed;
13154bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        // The full message content of a single part message
13164bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        // or a multipart message that this part belongs to
13174bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private String mFullMessageText;
13184bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen
13194bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private int mSubId;
13200217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
132152a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen        // If this is a text message (instead of data message)
132252a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen        private boolean mIsText;
132352a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen
1324a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang        private boolean mPersistMessage;
1325a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang
13261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1327c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format,
132878d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal                AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
132952a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen                SmsHeader smsHeader, boolean isExpectMore, String fullMessageText, int subId,
1330a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang                boolean isText, boolean persistMessage) {
13310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mData = data;
13320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mSentIntent = sentIntent;
13330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDeliveryIntent = deliveryIntent;
13340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mRetryCount = 0;
13352029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            mAppInfo = appInfo;
13360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDestAddress = destAddr;
13371260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mFormat = format;
13386ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi            mExpectMore = isExpectMore;
13391260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mImsRetry = 0;
13401260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mMessageRef = 0;
1341c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mUnsentPartCount = unsentPartCount;
1342c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mAnyPartFailed = anyPartFailed;
1343c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mMessageUri = messageUri;
134478d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal            mSmsHeader = smsHeader;
13454bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            mFullMessageText = fullMessageText;
13464bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            mSubId = subId;
134752a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen            mIsText = isText;
1348a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            mPersistMessage = persistMessage;
13490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /**
13520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * Returns whether this tracker holds a multi-part SMS.
13530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * @return true if the tracker holds a multi-part SMS; false otherwise
13540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
13550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        boolean isMultipart() {
13560217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            return mData.containsKey("parts");
13570217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        }
13580217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
13590217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        /**
13600217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         * Update the status of this message if we persisted it
13610217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         */
13620217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        public void updateSentMessageStatus(Context context, int status) {
1363c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri != null) {
13640217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // If we wrote this message in writeSentMessage, update it now
13650217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                ContentValues values = new ContentValues(1);
13660217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                values.put(Sms.STATUS, status);
13670217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                SqliteWrapper.update(context, context.getContentResolver(),
1368c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        mMessageUri, values, null, null);
1369c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1370c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1371c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1372c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
13734bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * Set the final state of a message: FAILED or SENT
1374c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1375c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
13764bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The final message type
1377c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param errorCode The error code
1378c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
13794bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private void updateMessageState(Context context, int messageType, int errorCode) {
1380c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri == null) {
1381c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                return;
1382c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
13834bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentValues values = new ContentValues(2);
13844bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.TYPE, messageType);
1385c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            values.put(Sms.ERROR_CODE, errorCode);
1386c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final long identity = Binder.clearCallingIdentity();
1387c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            try {
1388c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
1389c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        null/*where*/, null/*selectionArgs*/) != 1) {
13904bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    Rlog.e(TAG, "Failed to move message to " + messageType);
1391c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1392c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } finally {
1393c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                Binder.restoreCallingIdentity(identity);
1394c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1395c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1396c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1397c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
139852a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen         * Persist a sent SMS if required:
139952a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen         * 1. It is a text message
140052a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen         * 2. SmsApplication tells us to persist: sent from apps that are not default-SMS app or
140152a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen         *    bluetooth
1402c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
14034bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param context
14044bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The folder to store (FAILED or SENT)
14054bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param errorCode The current error code for this SMS or SMS part
14064bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @return The telephony provider URI if stored
1407c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
14084bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) {
1409a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            if (!mIsText || !mPersistMessage ||
141052a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen                    !SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) {
14114bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return null;
14124bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14134bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            Rlog.d(TAG, "Persist SMS into "
14144bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    + (messageType == Sms.MESSAGE_TYPE_FAILED ? "FAILED" : "SENT"));
14154bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentValues values = new ContentValues();
14164b09dff383ae7dfca595aeeea886a594a1947340Wink Saville            values.put(Sms.SUBSCRIPTION_ID, mSubId);
14174bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.ADDRESS, mDestAddress);
14184bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.BODY, mFullMessageText);
14194bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.DATE, System.currentTimeMillis()); // milliseconds
14204bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.SEEN, 1);
14214bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.READ, 1);
14224bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final String creator = mAppInfo != null ? mAppInfo.packageName : null;
14234bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (!TextUtils.isEmpty(creator)) {
14244bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.CREATOR, creator);
14254bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14264bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (mDeliveryIntent != null) {
14274bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.STATUS, Telephony.Sms.STATUS_PENDING);
14284bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14294bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (errorCode != 0) {
14304bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.ERROR_CODE, errorCode);
1431c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1432c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final long identity = Binder.clearCallingIdentity();
14334bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentResolver resolver = context.getContentResolver();
1434c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            try {
14354bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                final Uri uri =  resolver.insert(Telephony.Sms.Sent.CONTENT_URI, values);
14364bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                if (uri != null && messageType == Sms.MESSAGE_TYPE_FAILED) {
14374bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // Since we can't persist a message directly into FAILED box,
14384bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // we have to update the column after we persist it into SENT box.
14394bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // The gap between the state change is tiny so I would not expect
14404bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // it to cause any serious problem
14414bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // TODO: we should add a "failed" URI for this in SmsProvider?
14424bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    final ContentValues updateValues = new ContentValues(1);
14434bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    updateValues.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
14444bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    resolver.update(uri, updateValues, null/*where*/, null/*selectionArgs*/);
1445c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
14464bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return uri;
14474bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            } catch (Exception e) {
14484bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
14494bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return null;
1450c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } finally {
1451c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                Binder.restoreCallingIdentity(identity);
1452c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1453c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1454c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1455c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
14564bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * Persist or update an SMS depending on if we send a new message or a stored message
14574bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         *
14584bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param context
14594bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The message folder for this SMS, FAILED or SENT
14604bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param errorCode The current error code for this SMS or SMS part
14614bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         */
14624bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private void persistOrUpdateMessage(Context context, int messageType, int errorCode) {
14634bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (mMessageUri != null) {
14644bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                updateMessageState(context, messageType, errorCode);
14654bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            } else {
14664bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode);
14674bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14684bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        }
14694bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen
14704bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        /**
1471c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Handle a failure of a single part message or a part of a multipart message
1472c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1473c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1474c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param error The error to send back with
1475c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param errorCode
1476c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1477c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public void onFailed(Context context, int error, int errorCode) {
1478c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mAnyPartFailed != null) {
1479c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                mAnyPartFailed.set(true);
1480c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1481c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            // is single part or last part of multipart message
1482c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            boolean isSinglePartOrLastPart = true;
1483c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mUnsentPartCount != null) {
1484c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1485c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1486c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (isSinglePartOrLastPart) {
14874bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                persistOrUpdateMessage(context, Sms.MESSAGE_TYPE_FAILED, errorCode);
1488c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1489c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mSentIntent != null) {
1490c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                try {
1491fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    // Extra information to send with the sent intent
1492fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    Intent fillIn = new Intent();
1493fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    if (mMessageUri != null) {
1494fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        // Pass this to SMS apps so that they know where it is stored
1495fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra("uri", mMessageUri.toString());
1496fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    }
1497c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (errorCode != 0) {
1498c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        fillIn.putExtra("errorCode", errorCode);
1499c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1500c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1501c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        // Is multipart and last part
1502c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1503c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1504c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    mSentIntent.send(context, error, fillIn);
1505c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } catch (CanceledException ex) {
1506c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to send result");
1507c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1508c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1509c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1510c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1511c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
1512c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Handle the sent of a single part message or a part of a multipart message
1513c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1514c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1515c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1516c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public void onSent(Context context) {
1517c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            // is single part or last part of multipart message
1518c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            boolean isSinglePartOrLastPart = true;
1519c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mUnsentPartCount != null) {
1520c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1521c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1522c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (isSinglePartOrLastPart) {
15234bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                int messageType = Sms.MESSAGE_TYPE_SENT;
1524c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (mAnyPartFailed != null && mAnyPartFailed.get()) {
15254bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    messageType = Sms.MESSAGE_TYPE_FAILED;
1526c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
15274bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                persistOrUpdateMessage(context, messageType, 0/*errorCode*/);
1528c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1529c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mSentIntent != null) {
1530c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                try {
1531fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    // Extra information to send with the sent intent
1532fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    Intent fillIn = new Intent();
1533fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    if (mMessageUri != null) {
1534fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        // Pass this to SMS apps so that they know where it is stored
1535fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra("uri", mMessageUri.toString());
1536fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    }
1537c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1538c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        // Is multipart and last part
1539fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1540c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1541fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    mSentIntent.send(context, Activity.RESULT_OK, fillIn);
1542c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } catch (CanceledException ex) {
1543c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to send result");
1544c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
15450217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
15460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
15480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1549ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1550c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount,
15516ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi            AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader,
1552a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            boolean isExpectMore, String fullMessageText, boolean isText, boolean persistMessage) {
15531260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get calling app package name via UID from Binder call
15541260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageManager pm = mContext.getPackageManager();
15551260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
15561260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
15571260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get package info via packagemanager
15581260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageInfo appInfo = null;
15591260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (packageNames != null && packageNames.length > 0) {
15601260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            try {
15611260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // XXX this is lossy- apps can share a UID
15621260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
15631260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            } catch (PackageManager.NameNotFoundException e) {
15641260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // error will be logged in sendRawPdu
15651260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
15661260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        }
15671260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Strip non-digits from destination phone number before checking for short codes
15681260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // and before displaying the number to the user if confirmation is required.
15691260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
1570c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format,
15714bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                unsentPartCount, anyPartFailed, messageUri, smsHeader, isExpectMore,
1572a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang                fullMessageText, getSubId(), isText, persistMessage);
1573c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1574c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1575c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
15764bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            PendingIntent deliveryIntent, String format, Uri messageUri, boolean isExpectMore,
1577a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            String fullMessageText, boolean isText, boolean persistMessage) {
1578c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/,
15794bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                null/*anyPartFailed*/, messageUri, null/*smsHeader*/, isExpectMore,
1580a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang                fullMessageText, isText, persistMessage);
15811260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
15821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1583ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
15841260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            String text, SmsMessageBase.SubmitPduBase pdu) {
15851260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
15861260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
15871260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
15881260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("text", text);
15891260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
15901260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
15911260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
15921260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
15931260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1594ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
15951260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
15961260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
15971260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
15981260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
1599ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        map.put("destPort", destPort);
16001260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("data", data);
16011260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
16021260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
16031260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
16041260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
16051260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
16060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
16070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dialog listener for SMS confirmation dialog.
16080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
16090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final class ConfirmDialogListener
16104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
16114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            CompoundButton.OnCheckedChangeListener {
16120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        private final SmsTracker mTracker;
16144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mPositiveButton;
16154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mNegativeButton;
16164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private boolean mRememberChoice;    // default is unchecked
161778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        private final TextView mRememberUndoInstruction;
16180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
161978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener(SmsTracker tracker, TextView textView) {
16200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mTracker = tracker;
162178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt            mRememberUndoInstruction = textView;
16220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setPositiveButton(Button button) {
16254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mPositiveButton = button;
16264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
16274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setNegativeButton(Button button) {
16294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mNegativeButton = button;
16304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
16314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
16330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onClick(DialogInterface dialog, int which) {
16344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Always set the SMS permission so that Settings will show a permission setting
16354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // for the app (it won't be shown until after the app tries to send to a short code).
16364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
16374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (which == DialogInterface.BUTTON_POSITIVE) {
1639ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "CONFIRM sending SMS");
16402029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1641634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_SENT_BY_USER,
1642ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1643ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 : mTracker.mAppInfo.applicationInfo.uid);
16440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker));
16454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
16464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
16474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
16480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (which == DialogInterface.BUTTON_NEGATIVE) {
1649ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "DENY sending SMS");
16502029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1651634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
1652ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1653ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 :  mTracker.mAppInfo.applicationInfo.uid);
16540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
16554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
16564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
16574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
16580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
16594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            setPremiumSmsPermission(mTracker.mAppInfo.packageName, newSmsPermission);
16600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
16630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onCancel(DialogInterface dialog) {
1664ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "dialog dismissed: don't send SMS");
16650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
16660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        @Override
16694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1670ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "remember this choice: " + isChecked);
16714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mRememberChoice = isChecked;
16724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (isChecked) {
16734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
16744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
167578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
167678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.
167778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                            setText(R.string.sms_short_code_remember_undo_instruction);
167878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,32);
167978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
16804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            } else {
16814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
16825d875796122cdd8a7004e8e3964b20b5c65a31a1Robert Greenwalt                mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
168378df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
168478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setText("");
168578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,0);
168678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
16874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
16884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
16890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
16901260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1691ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public boolean isIms() {
1692ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1693ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.isIms();
1694ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1695ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1696ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return false;
1697ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1698ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
16991260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1700ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public String getImsSmsFormat() {
1701ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1702ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.getImsSmsFormat();
1703ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1704ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1705ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return null;
1706ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1707ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
1708c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1709c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    private String getMultipartMessageText(ArrayList<String> parts) {
1710c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final StringBuilder sb = new StringBuilder();
1711c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        for (String part : parts) {
1712c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (part != null) {
1713c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                sb.append(part);
1714c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1715c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1716c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return sb.toString();
1717c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1718b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen
17198215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected String getCarrierAppPackageName() {
1720062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
17217f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal        if (card == null) {
17227f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal            return null;
17237f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal        }
17247f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal
1725934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero        List<String> carrierPackages = card.getCarrierPackageNamesForIntent(
17268215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mContext.getPackageManager(), new Intent(CarrierMessagingService.SERVICE_INTERFACE));
17277f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal        return (carrierPackages != null && carrierPackages.size() == 1) ?
17287f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal                carrierPackages.get(0) : null;
1729c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal    }
1730c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal
1731b237a11044ed842d2865ff8c8716befb06b6ca25Wink Saville    protected int getSubId() {
1732b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.mPhoneId);
1733b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    }
1734f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal
1735f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal    private void checkCallerIsPhoneOrCarrierApp() {
1736f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        int uid = Binder.getCallingUid();
1737f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        int appId = UserHandle.getAppId(uid);
1738f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        if (appId == Process.PHONE_UID || uid == 0) {
1739f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            return;
1740f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        }
1741f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        try {
1742f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            PackageManager pm = mContext.getPackageManager();
1743f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            ApplicationInfo ai = pm.getApplicationInfo(getCarrierAppPackageName(), 0);
1744f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            if (!UserHandle.isSameApp(ai.uid, Binder.getCallingUid())) {
1745f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                throw new SecurityException("Caller is not phone or carrier app!");
1746f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            }
1747f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        } catch (PackageManager.NameNotFoundException re) {
1748f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            throw new SecurityException("Caller is not phone or carrier app!");
1749f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        }
1750f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal    }
17510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
1752