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;
1896f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastry
1996f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastryimport static android.Manifest.permission.SEND_SMS_NO_CONFIRMATION;
2096f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastryimport static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
2196f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastryimport static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
2296f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastryimport static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
2396f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastryimport static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
2496f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastryimport static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
2596f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastryimport static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
2696f2245d927c81fcd348bace3bc417bd0f91fb33Abhijith Shastry
27ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wangimport android.annotation.Nullable;
2832cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Makimport android.annotation.UserIdInt;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.Activity;
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.AlertDialog;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent;
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent.CanceledException;
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ContentResolver;
340217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.content.ContentValues;
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Context;
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.DialogInterface;
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Intent;
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.ApplicationInfo;
392029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.content.pm.PackageInfo;
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.PackageManager;
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources;
42ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.database.ContentObserver;
430217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.database.sqlite.SqliteWrapper;
440217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.net.Uri;
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.AsyncResult;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Binder;
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler;
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
49f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawalimport android.os.Process;
508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.os.RemoteException;
51f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawalimport android.os.UserHandle;
52ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.provider.Settings;
530217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.provider.Telephony;
540217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.provider.Telephony.Sms;
558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.CarrierMessagingService;
568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.ICarrierMessagingCallback;
578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.ICarrierMessagingService;
588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.telephony.CarrierMessagingServiceManager;
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.PhoneNumberUtils;
600d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.Rlog;
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.ServiceState;
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.TelephonyManager;
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Html;
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Spanned;
65b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wenimport android.text.TextUtils;
662029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.util.EventLog;
674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.LayoutInflater;
684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.View;
6978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwaltimport android.view.ViewGroup;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.WindowManager;
714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.Button;
724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CheckBox;
734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CompoundButton;
744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.TextView;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.R;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
78a9552aa6bf3ce12c75ad43165034d9a1233fb131Shishir Agrawalimport com.android.internal.telephony.uicc.UiccCard;
79c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawalimport com.android.internal.telephony.uicc.UiccController;
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap;
838d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport java.util.List;
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Random;
85c99dab56e20222b28cbc6238645feac938f1c333Ye Wenimport java.util.concurrent.atomic.AtomicBoolean;
860d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.concurrent.atomic.AtomicInteger;
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic abstract class SMSDispatcher extends Handler {
89cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final String TAG = "SMSDispatcher";    // accessed from inner class
90cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final boolean DBG = false;
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
93ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_SIM = 1;
94ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_NETWORK = 2;
95ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_BOTH = 3;
96ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
97ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final SettingsObserver mSettingsObserver;
98ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** SMS send complete. */
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int EVENT_SEND_SMS_COMPLETE = 2;
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Retry sending a previously failed SMS message */
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_RETRY = 3;
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for sending a large number of messages. */
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Send the user confirmed SMS */
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_SEND_CONFIRMED_SMS = 5;  // accessed from inner class
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Don't send SMS (user did not confirm). */
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_STOP_SENDING = 7;        // accessed from inner class
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1200d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /** Handle status report from {@code CdmaInboundSmsHandler}. */
1210d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected static final int EVENT_HANDLE_STATUS_REPORT = 10;
1220d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Radio is ON */
1241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_RADIO_ON = 11;
1251260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** IMS registration/SMS format changed */
1271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_CHANGED = 12;
1281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */
1301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_DONE = 13;
1311260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1321260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    // other
1331260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_NEW_ICC_SMS = 14;
1341260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_ICC_CHANGED = 15;
1351260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1361a87ab3d7170d618f048c4f5af8c7504a587aaa5Jack Yu    protected Phone mPhone;
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final Context mContext;
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ContentResolver mResolver;
13922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville    protected final CommandsInterface mCi;
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final TelephonyManager mTelephonyManager;
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Maximum number of times to retry sending a failed SMS. */
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MAX_SEND_RETRIES = 3;
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Delay before next send attempt on a failed SMS, in milliseconds. */
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SEND_RETRY_DELAY = 2000;
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** single part SMS */
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SINGLE_PART_SMS = 1;
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Message sending queue limit */
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MO_MSG_QUEUE_LIMIT = 5;
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Message reference for a CONCATENATED_8_BIT_REFERENCE or
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CONCATENATED_16_BIT_REFERENCE message set.  Should be
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * incremented for each set of concatenated messages.
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Static field shared by all dispatcher objects.
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int sConcatenatedRef = new Random().nextInt(256);
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Outgoing message counter. Shared by all dispatchers. */
1601260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    private SmsUsageMonitor mUsageMonitor;
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
162ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    private ImsSMSDispatcher mImsSMSDispatcher;
163ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Number of outgoing SmsTrackers waiting for user confirmation. */
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mPendingTrackerCount;
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* Flags indicating whether the current device allows sms service */
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsCapable = true;
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsSendDisabled;
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static int getNextConcatenatedRef() {
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sConcatenatedRef += 1;
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return sConcatenatedRef;
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SMS dispatcher.
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param phone the Phone to use
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param usageMonitor the SmsUsageMonitor to use
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1811a87ab3d7170d618f048c4f5af8c7504a587aaa5Jack Yu    protected SMSDispatcher(Phone phone, SmsUsageMonitor usageMonitor,
182ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            ImsSMSDispatcher imsSMSDispatcher) {
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhone = phone;
184ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        mImsSMSDispatcher = imsSMSDispatcher;
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mContext = phone.getContext();
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mResolver = mContext.getContentResolver();
18722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi = phone.mCi;
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mUsageMonitor = usageMonitor;
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
190ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
191ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
192ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsCapable = mContext.getResources().getBoolean(
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                com.android.internal.R.bool.config_sms_capable);
196e70617d81dcd42350a737b11c25532e1d43df4ffLegler Wu        mSmsSendDisabled = !mTelephonyManager.getSmsSendCapableForPhone(
197e70617d81dcd42350a737b11c25532e1d43df4ffLegler Wu                mPhone.getPhoneId(), mSmsCapable);
198ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + " mSmsSendDisabled=" + mSmsSendDisabled);
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
202ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    /**
203ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     * Observe the secure setting for updated premium sms determination rules
204ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     */
205ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static class SettingsObserver extends ContentObserver {
206ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final AtomicInteger mPremiumSmsRule;
207ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final Context mContext;
208ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
209ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            super(handler);
210ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule = premiumSmsRule;
211ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mContext = context;
212ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            onChange(false); // load initial value;
213ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
214ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
215ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        @Override
216ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        public void onChange(boolean selfChange) {
217ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
218ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
219ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
220ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    }
221ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
2221a87ab3d7170d618f048c4f5af8c7504a587aaa5Jack Yu    protected void updatePhoneObject(Phone phone) {
2231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mPhone = phone;
2241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mUsageMonitor = phone.mSmsUsageMonitor;
2251260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() );
2261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
2271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Unregister for incoming SMS events. */
2290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    public void dispose() {
2300d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
2310d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The format of the message PDU in the associated broadcast intent.
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Note: All applications which handle incoming SMS messages by processing the
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * into the new methods in {@link android.telephony.SmsMessage} which take an
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * extra format parameter. This is required in order to correctly decode the PDU on
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * devices which require support for both 3GPP and 3GPP2 formats at the same time,
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * such as CDMA/LTE devices and GSM/CDMA world phones.
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the format of the message PDU
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract String getFormat();
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
2500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports
2510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}.
2520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param o the SmsMessage containing the status report
2530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
2540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected void handleStatusReport(Object o) {
2550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        Rlog.d(TAG, "handleStatusReport() called with no subclass.");
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* TODO: Need to figure out how to keep track of status report routing in a
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       persistent manner. If the phone process restarts (reboot or crash),
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       we will lose this list and any status reports that come in after
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       will be dropped.
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Sent messages awaiting a delivery status report. */
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles events coming from the phone stack. Overridden from handler.
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg the message to handle
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msg.what) {
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_SMS_COMPLETE:
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // An outbound SMS has been successfully transferred, or failed.
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleSendComplete((AsyncResult) msg.obj);
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_RETRY:
2801260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            Rlog.d(TAG, "SMS retry..");
2811260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            sendRetrySms((SmsTracker) msg.obj);
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleReachSentLimit((SmsTracker)(msg.obj));
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(false, (SmsTracker)(msg.obj));
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(true, (SmsTracker)(msg.obj));
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_CONFIRMED_SMS:
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.isMultipart()) {
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMultipartSms(tracker);
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
3026c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                if (mPendingTrackerCount > 1) {
3036c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                    tracker.mExpectMore = true;
3046c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                } else {
3056c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                    tracker.mExpectMore = false;
3066c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                }
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_STOP_SENDING:
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
316c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3210d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        case EVENT_HANDLE_STATUS_REPORT:
3220d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            handleStatusReport(msg.obj);
3230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            break;
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        default:
3260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
3270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
328b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    }
329b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
330b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    /**
3318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a data or text SMS.
3328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
3338215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract class SmsSender extends CarrierMessagingServiceManager {
3348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected final SmsTracker mTracker;
3358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        // Initialized in sendSmsByCarrierApp
3368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected volatile SmsSenderCallback mSenderCallback;
3378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected SmsSender(SmsTracker tracker) {
3398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mTracker = tracker;
3408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3428215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void sendSmsByCarrierApp(String carrierPackageName,
3438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                        SmsSenderCallback senderCallback) {
3448215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSenderCallback = senderCallback;
3458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
3468215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "bindService() for carrier messaging service failed");
3478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
3488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
3508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
3518215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
3528215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
3538215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
3558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
356ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang    private static int getSendSmsFlag(@Nullable PendingIntent deliveryIntent) {
357ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang        if (deliveryIntent == null) {
358ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang            return 0;
359ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang        }
360ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang        return CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS;
361ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang    }
362ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang
3638215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
3648215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a text SMS.
3658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
3668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class TextSmsSender extends SmsSender {
3678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public TextSmsSender(SmsTracker tracker) {
3688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            super(tracker);
3698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
3728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
3735d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan            HashMap<String, Object> map = mTracker.getData();
3748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            String text = (String) map.get("text");
3758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (text != null) {
3778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                try {
3788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    carrierMessagingService.sendTextSms(text, getSubId(),
379ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                            mTracker.mDestAddress, getSendSmsFlag(mTracker.mDeliveryIntent),
380ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                            mSenderCallback);
3818215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } catch (RemoteException e) {
3828215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Exception sending the SMS: " + e);
3838215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    mSenderCallback.onSendSmsComplete(
3848215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3858215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            0 /* messageRef */);
3868215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
3878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
3888215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
3898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
3918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
3928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
3948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
3968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a data SMS.
3978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
3988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class DataSmsSender extends SmsSender {
3998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public DataSmsSender(SmsTracker tracker) {
4008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            super(tracker);
4018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
4055d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan            HashMap<String, Object> map = mTracker.getData();
4068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            byte[] data = (byte[]) map.get("data");
4078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            int destPort = (int) map.get("destPort");
4088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (data != null) {
4108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                try {
4118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    carrierMessagingService.sendDataSms(data, getSubId(),
412ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                            mTracker.mDestAddress, destPort,
413ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                            getSendSmsFlag(mTracker.mDeliveryIntent), mSenderCallback);
4148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } catch (RemoteException e) {
4158215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Exception sending the SMS: " + e);
4168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    mSenderCallback.onSendSmsComplete(
4178215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
4188215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            0 /* messageRef */);
4198215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
4208215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
4218215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
4228215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
4238215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
4248215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
4258215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4268215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
4278215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4288215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
4298215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Callback for TextSmsSender and DataSmsSender from the carrier messaging service.
4308215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Once the result is ready, the carrier messaging service connection is disposed.
4318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
4328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class SmsSenderCallback extends ICarrierMessagingCallback.Stub {
4338215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final SmsSender mSmsSender;
4348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public SmsSenderCallback(SmsSender smsSender) {
4368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender = smsSender;
4378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        /**
4408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         * This method should be called only once.
4418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         */
4428215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendSmsComplete(int result, int messageRef) {
444f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            checkCallerIsPhoneOrCarrierApp();
445f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            final long identity = Binder.clearCallingIdentity();
446f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            try {
447f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                mSmsSender.disposeConnection(mContext);
448f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
449f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            } finally {
450f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                Binder.restoreCallingIdentity(identity);
451f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            }
4528215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4538215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
4568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result);
4578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4598215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4603fcaeac48c45f7fbefd2aeee8fe3094f40f9bf84Ji Yang        public void onFilterComplete(int result) {
4613fcaeac48c45f7fbefd2aeee8fe3094f40f9bf84Ji Yang            Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
4628215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4638215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4648215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
4668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
4678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onDownloadMmsComplete(int result) {
4718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
4728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
4748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private void processSendSmsResponse(SmsTracker tracker, int result, int messageRef) {
4768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (tracker == null) {
4778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "processSendSmsResponse: null tracker");
4788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            return;
4798215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4808215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4818215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        SmsResponse smsResponse = new SmsResponse(
4828215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                messageRef, null /* ackPdu */, -1 /* unknown error code */);
4838215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4848215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        switch (result) {
4858215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_OK:
4868215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP succeeded.");
4878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
4888215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                      new AsyncResult(tracker,
4898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                                      smsResponse,
4908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                                      null /* exception*/ )));
4918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
4928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_ERROR:
4938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP failed.");
4948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
4958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    new AsyncResult(tracker, smsResponse,
4968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            new CommandException(CommandException.Error.GENERIC_FAILURE))));
4978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
4988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
4998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP failed. Retry on carrier network.");
5008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendSubmitPdu(tracker);
5018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
5028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        default:
5038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Unknown result " + result + " Retry on carrier network.");
5048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendSubmitPdu(tracker);
5058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
5078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
5098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a multipart text SMS.
5108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
5118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private final class MultipartSmsSender extends CarrierMessagingServiceManager {
5128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final List<String> mParts;
5138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public final SmsTracker[] mTrackers;
5148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        // Initialized in sendSmsByCarrierApp
5158215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private volatile MultipartSmsSenderCallback mSenderCallback;
5168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5178215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) {
5188215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mParts = parts;
5198215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mTrackers = trackers;
5208215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5218215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5228215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        void sendSmsByCarrierApp(String carrierPackageName,
5238215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                 MultipartSmsSenderCallback senderCallback) {
5248215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSenderCallback = senderCallback;
5258215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
5268215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "bindService() for carrier messaging service failed");
5278215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendMultipartSmsComplete(
5288215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
5298215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        null /* smsResponse */);
5308215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
5318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
5328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5338215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
5378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            try {
5388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                carrierMessagingService.sendMultipartTextSms(
539ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                        mParts, getSubId(), mTrackers[0].mDestAddress,
540ade6a7a40779f907ba34142ad2286d532fcdebffCheuksan Wang                        getSendSmsFlag(mTrackers[0].mDeliveryIntent), mSenderCallback);
5418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } catch (RemoteException e) {
5428215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "Exception sending the SMS: " + e);
5438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendMultipartSmsComplete(
5448215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
5458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        null /* smsResponse */);
5468215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
5498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
5518215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Callback for MultipartSmsSender from the carrier messaging service.
5528215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Once the result is ready, the carrier messaging service connection is disposed.
5538215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
5548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private final class MultipartSmsSenderCallback extends ICarrierMessagingCallback.Stub {
5558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final MultipartSmsSender mSmsSender;
5568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        MultipartSmsSenderCallback(MultipartSmsSender smsSender) {
5588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender = smsSender;
5598215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5608215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5618215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5628215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendSmsComplete(int result, int messageRef) {
5638215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result);
5648215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        /**
5678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         * This method should be called only once.
5688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         */
5698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
5718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender.disposeConnection(mContext);
5728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (mSmsSender.mTrackers == null) {
5748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers.");
5758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                return;
5768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
578f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            checkCallerIsPhoneOrCarrierApp();
579f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            final long identity = Binder.clearCallingIdentity();
580f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            try {
581f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                for (int i = 0; i < mSmsSender.mTrackers.length; i++) {
582f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                    int messageRef = 0;
583f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                    if (messageRefs != null && messageRefs.length > i) {
584f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                        messageRef = messageRefs[i];
585f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                    }
586f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                    processSendSmsResponse(mSmsSender.mTrackers[i], result, messageRef);
5878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
588f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            } finally {
589f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                Binder.restoreCallingIdentity(identity);
5908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5943fcaeac48c45f7fbefd2aeee8fe3094f40f9bf84Ji Yang        public void onFilterComplete(int result) {
5953fcaeac48c45f7fbefd2aeee8fe3094f40f9bf84Ji Yang            Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
5968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
6008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
6018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
6028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
6038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
6048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onDownloadMmsComplete(int result) {
6058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
6068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
6078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
6088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
6098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
6108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Send an SMS PDU. Usually just calls {@link sendRawPdu}.
6118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
6128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract void sendSubmitPdu(SmsTracker tracker);
6138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
6148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Called when SMS send completes. Broadcasts a sentIntent on success.
6160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * On failure, either sets up retries or broadcasts a sentIntent with
6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the failure in the result code.
6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ar AsyncResult passed into the message handler.  ar.result should
6200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           an SmsResponse instance if send was successful.  ar.userObj
6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           should be an SmsTracker instance.
6220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleSendComplete(AsyncResult ar) {
6240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsTracker tracker = (SmsTracker) ar.userObj;
6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PendingIntent sentIntent = tracker.mSentIntent;
6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
627454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        if (ar.result != null) {
6285a176f73dbb2bff2ca8b8f86af86a17be6863b87Wink Saville            tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
629454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        } else {
630454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks            Rlog.d(TAG, "SmsResponse was null");
631454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        }
632454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks
6330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (ar.exception == null) {
634cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
6350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.mDeliveryIntent != null) {
6370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Expecting a status report.  Add it to the list.
6380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryPendingList.add(tracker);
6390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
640c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onSent(mContext);
6410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
642cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send failed");
6430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
6450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6461260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
6471260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // This is retry after failure over IMS but voice is not available.
6481260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // Set retry to max allowed, so no retry is sent and
6491260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.
6501260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                tracker.mRetryCount = MAX_SEND_RETRIES;
6511260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
6521260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                Rlog.d(TAG, "handleSendComplete: Skipping retry: "
6531260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" isIms()="+isIms()
6541260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mRetryCount="+tracker.mRetryCount
6551260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mImsRetry="+tracker.mImsRetry
6561260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mMessageRef="+tracker.mMessageRef
6571260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" SS= "+mPhone.getServiceState().getState());
6581260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
6591260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
6601260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            // if sms over IMS is not supported on data and voice is not available...
6611260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
662c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
6630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if ((((CommandException)(ar.exception)).getCommandError()
6640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    == CommandException.Error.SMS_FAIL_RETRY) &&
6650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                   tracker.mRetryCount < MAX_SEND_RETRIES) {
6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Retry after a delay if needed.
6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // TODO: According to TS 23.040, 9.2.3.6, we should resend
6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       with the same TP-MR as the failed message, and
6690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       TP-RD set to 1.  However, we don't have a means of
6700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       knowing the MR for the failed message (EF_SMSstatus
6710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       may or may not have the MR corresponding to this
6720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       message, depending on the failure).  Also, in some
6730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       implementations this retry is handled by the baseband.
6740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tracker.mRetryCount++;
6750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
6760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
677c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } else {
678c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                int errorCode = 0;
679c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (ar.result != null) {
680c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    errorCode = ((SmsResponse)ar.result).mErrorCode;
681c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
6820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int error = RESULT_ERROR_GENERIC_FAILURE;
6830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (((CommandException)(ar.exception)).getCommandError()
6840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        == CommandException.Error.FDN_CHECK_FAILURE) {
6850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    error = RESULT_ERROR_FDN_CHECK_FAILURE;
6860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
687c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, error, errorCode);
6880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
6930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles outbound message when the phone is not in service.
6940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
6950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ss     Current service state.  Valid values are:
6960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  OUT_OF_SERVICE
6970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  EMERGENCY_ONLY
6980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  POWER_OFF
6990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent the PendingIntent to send the error to
7000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static void handleNotInService(int ss, PendingIntent sentIntent) {
7020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (sentIntent != null) {
7030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
7040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ss == ServiceState.STATE_POWER_OFF) {
7050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_RADIO_OFF);
7060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
7070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NO_SERVICE);
7080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
7090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CanceledException ex) {}
7100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
714c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     * @param ss service state
715c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     * @return The result error based on input service state for not in service error
716c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     */
717c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected static int getNotInServiceError(int ss) {
718c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        if (ss == ServiceState.STATE_POWER_OFF) {
719c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return RESULT_ERROR_RADIO_OFF;
720c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
721c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return RESULT_ERROR_NO_SERVICE;
722c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
723c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
724c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    /**
7250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a data based SMS to a specific application port.
7260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
7280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
7290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
7300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destPort the port to deliver the message to
7310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data the body of the message to send
7320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
7330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
7340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
7350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
7360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
7370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
7380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
7390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
7400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
7410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
7420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
7430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
7440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
7450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
7460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
7470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
7480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
7490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendData(String destAddr, String scAddr, int destPort,
7510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent);
7520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a text based SMS.
755b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     *  @param destAddr the address to send the message to
7560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
7570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
7580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param text the body of the message to send
7590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
7600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
7610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
7620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
7630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
7640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
7650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
7660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
7670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
7680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
7690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
7700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
7710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
7720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
7730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
7740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
775b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param messageUri optional URI of the message if it is already stored in the system
776b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param callingPkg the calling package name
777a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang     * @param persistMessage whether to save the sent message into SMS DB for a
778a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang     *   non-default SMS app.
7790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
780b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    protected abstract void sendText(String destAddr, String scAddr, String text,
781b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri,
782a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            String callingPkg, boolean persistMessage);
7830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
78563418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * Inject an SMS PDU into the android platform.
78663418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *
78763418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param pdu is the byte array of pdu to be injected into android telephony layer
78863418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param format is the format of SMS pdu (3gpp or 3gpp2)
78963418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
79063418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  broadcast when the message is successfully received by the
79163418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  android telephony layer. This intent is broadcasted at
79263418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  the same time an SMS received from radio is responded back.
79363418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     */
79463418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni    protected abstract void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent);
79563418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni
79663418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni    /**
7973ce96a061c2c6e24f4ff3bd237e18c29fc0c0108Amit Mahajan     * Calculate the number of septets needed to encode the message. This function should only be
7983ce96a061c2c6e24f4ff3bd237e18c29fc0c0108Amit Mahajan     * called for individual segments of multipart message.
7990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
8000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param messageBody the message to encode
8010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param use7bitOnly ignore (but still count) illegal characters if true
8020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return TextEncodingDetails
8030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
8050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean use7bitOnly);
8060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a multi-part text based SMS.
809b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     *  @param destAddr the address to send the message to
8100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
8110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   the current default SMSC
8120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param parts an <code>ArrayList</code> of strings that, in order,
8130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   comprise the original message
8140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntents if not null, an <code>ArrayList</code> of
8150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
8160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been sent.
8170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   The result code will be <code>Activity.RESULT_OK<code> for success,
8180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   or one of these errors:
8190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
8200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_RADIO_OFF</code>
8210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NULL_PDU</code>
8220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NO_SERVICE</code>.
8230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
8240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
8250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
8260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntents if not null, an <code>ArrayList</code> of
8270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
8280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been delivered
8290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   to the recipient.  The raw pdu of the status report is in the
830b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param messageUri optional URI of the message if it is already stored in the system
831b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param callingPkg the calling package name
832a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang     * @param persistMessage whether to save the sent message into SMS DB for a
833a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang     *   non-default SMS app.
8340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendMultipartText(String destAddr, String scAddr,
8360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
837a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg,
838a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            boolean persistMessage) {
8394bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        final String fullMessageText = getMultipartMessageText(parts);
8400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int refNumber = getNextConcatenatedRef() & 0x00FF;
8410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgCount = parts.size();
8420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int encoding = SmsConstants.ENCODING_UNKNOWN;
8430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
8450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
8460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            TextEncodingDetails details = calculateLength(parts.get(i), false);
8470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding != details.codeUnitSize
8480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    && (encoding == SmsConstants.ENCODING_UNKNOWN
8490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            || encoding == SmsConstants.ENCODING_7BIT)) {
8500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encoding = details.codeUnitSize;
8510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            encodingForParts[i] = details;
8530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        SmsTracker[] trackers = new SmsTracker[msgCount];
8568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
857c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        // States to track at the message level (for all parts)
858c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
859c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
860c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
8610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
8620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
8630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.refNumber = refNumber;
8640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.seqNumber = i + 1;  // 1-based sequence
8650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.msgCount = msgCount;
8660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // TODO: We currently set this to true since our messaging app will never
8670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // send more than 255 parts (it converts the message to MMS well before that).
8680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // However, we should support 3rd party messaging apps that might need 16-bit
8690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // references
8700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Note:  It's not sufficient to just flip this bit to true; it will have
8710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // ripple effects (several calculations assume 8-bit ref).
8720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.isEightBits = true;
8730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader smsHeader = new SmsHeader();
8740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsHeader.concatRef = concatRef;
8750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Set the national language tables for 3GPP 7-bit encoding, if enabled.
8770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding == SmsConstants.ENCODING_7BIT) {
8780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageTable = encodingForParts[i].languageTable;
8790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
8800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent = null;
8830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntents != null && sentIntents.size() > i) {
8840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sentIntent = sentIntents.get(i);
8850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent deliveryIntent = null;
8880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (deliveryIntents != null && deliveryIntents.size() > i) {
8890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryIntent = deliveryIntents.get(i);
8900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            trackers[i] =
8938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding,
8948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        sentIntent, deliveryIntent, (i == (msgCount - 1)),
8958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        unsentPartCount, anyPartFailed, messageUri, fullMessageText);
896a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            trackers[i].mPersistMessage = persistMessage;
8978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
8988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
8998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (parts == null || trackers == null || trackers.length == 0
9008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                || trackers[0] == null) {
9018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers);
9028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            return;
9038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
9048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
9058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        String carrierPackage = getCarrierAppPackageName();
9068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (carrierPackage != null) {
9078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Found carrier package.");
9088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
9098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            smsSender.sendSmsByCarrierApp(carrierPackage, new MultipartSmsSenderCallback(smsSender));
9108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        } else {
9118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.v(TAG, "No carrier package.");
9128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            for (SmsTracker tracker : trackers) {
9138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                if (tracker != null) {
9148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    sendSubmitPdu(tracker);
9158215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } else {
9168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Null tracker.");
9178215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
9188215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
9190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
9210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9238215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Create a new SubmitPdu and return the SMS tracker.
9240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9258215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
9260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String message, SmsHeader smsHeader, int encoding,
927c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
9284bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
9294bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            String fullMessageText);
9300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Send an SMS
9331260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker will contain:
9341260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -smsc the SMSC to send the message through, or NULL for the
9350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  default SMSC
9361260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -pdu the raw PDU to send
9371260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -sentIntent if not NULL this <code>Intent</code> is
9380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
9390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
9400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:
9410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
9420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code>
9430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code>
9440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code>.
9450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
9460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
9470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
9481260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -deliveryIntent if not NULL this <code>Intent</code> is
9490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
9500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
9511260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -param destAddr the destination phone number (for short code confirmation)
9520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9531260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void sendRawPdu(SmsTracker tracker) {
9545d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan        HashMap map = tracker.getData();
9551260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        byte pdu[] = (byte[]) map.get("pdu");
9561260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
9570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mSmsSendDisabled) {
958c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Device does not support sending sms.");
959c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
9600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pdu == null) {
964c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Empty PDU");
965c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);
9660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Get calling app package name via UID from Binder call
9700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
9710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
9720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (packageNames == null || packageNames.length == 0) {
9740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Refuse to send SMS if we can't get the calling package name.
975ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");
976c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
9770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9802029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        // Get package info via packagemanager
9810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        PackageInfo appInfo;
9822029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        try {
9832029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            // XXX this is lossy- apps can share a UID
98432cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak            appInfo = pm.getPackageInfoAsUser(
98532cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak                    packageNames[0], PackageManager.GET_SIGNATURES, tracker.mUserId);
9862029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        } catch (PackageManager.NameNotFoundException e) {
987ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
988c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
9892029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            return;
9902029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        }
9910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // checkDestination() returns true if the destination is not a premium short code or the
9930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // sending app is approved to send to short codes. Otherwise, a message is sent to our
9940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // handler with the SmsTracker to request user confirmation before sending.
9950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (checkDestination(tracker)) {
9960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // check for excessive outgoing SMS usage by this app
9972029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
9980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
9990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
10000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1002a0c22039b77054d659151537896c1db90c7057f7Shishir Agrawal            sendSms(tracker);
10030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10045eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry
10055eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        if (PhoneNumberUtils.isLocalEmergencyNumber(mContext, tracker.mDestAddress)) {
10065eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry            new AsyncEmergencyContactNotifier(mContext).execute();
10075eccb26b2bcf3a51326596e1b0bb49b073d2f9fcAbhijith Shastry        }
10080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Check if destination is a potential premium short code and sender is not pre-approved to
10120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * send to short codes.
10130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
10140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the tracker for the SMS to send
10150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the destination is approved; false if user confirmation event was sent
10160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean checkDestination(SmsTracker tracker) {
1018bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan        if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION)
1019bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                == PackageManager.PERMISSION_GRANTED) {
1020bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            return true;            // app is pre-approved to send to short codes
1021bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan        } else {
1022bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            int rule = mPremiumSmsRule.get();
1023bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
1024bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
1025bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                String simCountryIso = mTelephonyManager.getSimCountryIso();
1026bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                if (simCountryIso == null || simCountryIso.length() != 2) {
1027bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso");
1028bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    simCountryIso = mTelephonyManager.getNetworkCountryIso();
1029bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                }
1030ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1031bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                smsCategory = mUsageMonitor.checkDestination(tracker.mDestAddress, simCountryIso);
10320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1033bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
1034bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                String networkCountryIso = mTelephonyManager.getNetworkCountryIso();
1035bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                if (networkCountryIso == null || networkCountryIso.length() != 2) {
1036bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso");
1037bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    networkCountryIso = mTelephonyManager.getSimCountryIso();
1038bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                }
10390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1040bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory,
1041bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                        mUsageMonitor.checkDestination(tracker.mDestAddress, networkCountryIso));
1042bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            }
10434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
1044bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE
1045bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE
1046bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) {
1047bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                return true;    // not a premium short code
1048bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            }
10490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
105015f55ca2f204e664807e047b5f898693b274bab6fionaxu            // Do not allow any premium sms during SuW
105115f55ca2f204e664807e047b5f898693b274bab6fionaxu            if (Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
105215f55ca2f204e664807e047b5f898693b274bab6fionaxu                Rlog.e(TAG, "Can't send premium sms during Setup Wizard");
105315f55ca2f204e664807e047b5f898693b274bab6fionaxu                return false;
105415f55ca2f204e664807e047b5f898693b274bab6fionaxu            }
105515f55ca2f204e664807e047b5f898693b274bab6fionaxu
1056bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            // Wait for user confirmation unless the user has set permission to always allow/deny
1057bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            int premiumSmsPermission = mUsageMonitor.getPremiumSmsPermission(
1058bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    tracker.mAppInfo.packageName);
1059bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
1060bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                // First time trying to send to premium SMS.
1061bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
1062bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            }
1063d1e1ef20799b3d6290523b613b5189dd3fe4812fAmit Mahajan
1064bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            switch (premiumSmsPermission) {
1065bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
1066bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    Rlog.d(TAG, "User approved this app to send to premium SMS");
1067bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    return true;
1068bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan
1069bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
1070bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    Rlog.w(TAG, "User denied this app from sending to premium SMS");
1071bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    sendMessage(obtainMessage(EVENT_STOP_SENDING, tracker));
1072bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    return false;   // reject this message
1073bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan
1074bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
1075bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                default:
1076bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    int event;
1077bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
1078bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                        event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
1079bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    } else {
1080bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                        event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
1081bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    }
1082bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    sendMessage(obtainMessage(event, tracker));
1083bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan                    return false;   // wait for user confirmation
1084bd5e7244c02d3af32ac260d6d240006a49b3a694Amit Mahajan            }
10850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Deny sending an SMS if the outgoing queue limit is reached. Used when the message
10900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * must be confirmed by the user due to excessive usage or potential premium SMS detected.
10910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the message to send
10920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the message was denied; false to continue with send confirmation
10930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean denyIfQueueLimitReached(SmsTracker tracker) {
10950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
10960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Deny sending message when the queue limit is reached.
1097c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Denied because queue limit reached");
1098c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
10990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;
11000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPendingTrackerCount++;
11020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return false;
11030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns the label for the specified app package name.
11070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param appPackage the package name of the app requesting to send an SMS
11080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the label for the specified app, or the package name if getApplicationInfo() fails
11090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
111032cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak    private CharSequence getAppLabel(String appPackage, @UserIdInt int userId) {
11110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
11120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
111332cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak            ApplicationInfo appInfo = pm.getApplicationInfoAsUser(appPackage, 0, userId);
11142eca414f1c7641c5b8069a09f191de7ebe692045fionaxu            return appInfo.loadSafeLabel(pm);
11150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (PackageManager.NameNotFoundException e) {
1116ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
11170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appPackage;  // fall back to package name if we can't get app label
11180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert when SMS needs confirmation due to excessive usage.
11230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker an SmsTracker for the current message.
11240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleReachSentLimit(SmsTracker tracker) {
11260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
11270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
11280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
113032cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName, tracker.mUserId);
11310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
11320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
11330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
113478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null);
11350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
11370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setTitle(R.string.sms_control_title)
11380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setIcon(R.drawable.stat_sys_warning)
11390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setMessage(messageText)
11400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
11410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_control_no), listener)
11420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
11430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
11440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
11460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
11470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert for user confirmation when sending to a potential short code.
11510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param isPremium true if the destination is known to be a premium short code
11520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the current message.
11530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) {
11550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
11560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
11570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        int detailsId;
11600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isPremium) {
11614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_premium_short_code_details;
11620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
11634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_short_code_details;
11640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
116632cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName, tracker.mUserId);
11670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
11684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
11694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                appLabel, tracker.mDestAddress));
11700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
11724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                Context.LAYOUT_INFLATER_SERVICE);
11734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
11744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
117578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
117678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                (TextView)layout.findViewById(R.id.sms_short_code_remember_undo_instruction));
117778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
117878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
11794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
11804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        messageView.setText(messageText);
11814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
118278df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
11834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_layout);
11844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView detailsView = (TextView) detailsLayout.findViewById(
11854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_message);
11864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        detailsView.setText(detailsId);
11874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        CheckBox rememberChoice = (CheckBox) layout.findViewById(
11894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_remember_choice_checkbox);
11904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        rememberChoice.setOnCheckedChangeListener(listener);
11914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
11934658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                .setView(layout)
11940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
11950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
11960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
11970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
11980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
12000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
12014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
12034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
12044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
12054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
12074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Returns the premium SMS permission for the specified package. If the package has never
12084658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}
12094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * will be returned.
12104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to query permission
12114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
12124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
12134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
12144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
12154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
12164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public int getPremiumSmsPermission(String packageName) {
12174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        return mUsageMonitor.getPremiumSmsPermission(packageName);
12184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
12194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
12214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Sets the premium SMS permission for the specified package and save the value asynchronously
12224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * to persistent storage.
12234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to set permission
12244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
12254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
12264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
12274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
12284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public void setPremiumSmsPermission(String packageName, int permission) {
12294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        mUsageMonitor.setPremiumSmsPermission(packageName, permission);
12300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the message along to the radio.
12340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the SMS message to send
12360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendSms(SmsTracker tracker);
12380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12408d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Send the SMS via the PSTN network.
12418d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *
12428d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param tracker holds the Sms tracker ready to be sent
12438d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
12448d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected abstract void sendSmsByPstn(SmsTracker tracker);
12458d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
12468d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
12471260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * Retry the message along to the radio.
12481260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     *
12491260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker holds the SMS message to send
12501260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     */
1251ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public void sendRetrySms(SmsTracker tracker) {
1252ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        // re-routing to ImsSMSDispatcher
1253ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1254ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            mImsSMSDispatcher.sendRetrySms(tracker);
1255ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1256ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null. Retry failed");
1257ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1258ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
12591260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
12601260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /**
12610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the multi-part SMS based on multipart Sms tracker
12620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the multipart Sms tracker ready to be sent
12640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void sendMultipartSms(SmsTracker tracker) {
12660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<String> parts;
12670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> sentIntents;
12680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> deliveryIntents;
12690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12705d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan        HashMap<String, Object> map = tracker.getData();
12710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String destinationAddress = (String) map.get("destination");
12730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String scAddress = (String) map.get("scaddress");
12740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        parts = (ArrayList<String>) map.get("parts");
12760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
12770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
12780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // check if in service
12800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int ss = mPhone.getServiceState().getState();
12811260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // if sms over IMS is not supported on data and voice is not available...
12821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
12830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0, count = parts.size(); i < count; i++) {
12840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                PendingIntent sentIntent = null;
12850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (sentIntents != null && sentIntents.size() > i) {
12860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent = sentIntents.get(i);
12870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
12880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, sentIntent);
12890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
12900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
12910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1293b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents,
1294a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang                null/*messageUri*/, null/*callingPkg*/, tracker.mPersistMessage);
12950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Keeps track of an SMS that has been sent to the RIL, until it has
12990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * successfully been sent, or we're done trying.
13000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
13015d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan    public static class SmsTracker {
13020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // fields need to be public for derived SmsDispatchers
13035d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan        private final HashMap<String, Object> mData;
13040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mRetryCount;
13051260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        public int mImsRetry; // nonzero indicates initial message was sent over Ims
13060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mMessageRef;
13076ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi        public boolean mExpectMore;
13081260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String mFormat;
13090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mSentIntent;
13110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mDeliveryIntent;
13120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13132029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        public final PackageInfo mAppInfo;
13140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final String mDestAddress;
13150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
131678d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal        public final SmsHeader mSmsHeader;
131778d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal
13180217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        private long mTimestamp = System.currentTimeMillis();
1319c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public Uri mMessageUri; // Uri of persisted message if we wrote one
1320c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1321c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        // Reference to states of a multipart message that this part belongs to
1322c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private AtomicInteger mUnsentPartCount;
1323c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private AtomicBoolean mAnyPartFailed;
13244bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        // The full message content of a single part message
13254bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        // or a multipart message that this part belongs to
13264bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private String mFullMessageText;
13274bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen
13284bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private int mSubId;
13290217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
133052a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen        // If this is a text message (instead of data message)
133152a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen        private boolean mIsText;
133252a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen
1333a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang        private boolean mPersistMessage;
1334a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang
133532cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak        // User who sends the SMS.
133632cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak        private final @UserIdInt int mUserId;
133732cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak
13381260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1339c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format,
134078d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal                AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
134152a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen                SmsHeader smsHeader, boolean isExpectMore, String fullMessageText, int subId,
134232cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak                boolean isText, boolean persistMessage, int userId) {
13430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mData = data;
13440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mSentIntent = sentIntent;
13450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDeliveryIntent = deliveryIntent;
13460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mRetryCount = 0;
13472029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            mAppInfo = appInfo;
13480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDestAddress = destAddr;
13491260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mFormat = format;
13506ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi            mExpectMore = isExpectMore;
13511260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mImsRetry = 0;
13521260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mMessageRef = 0;
1353c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mUnsentPartCount = unsentPartCount;
1354c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mAnyPartFailed = anyPartFailed;
1355c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mMessageUri = messageUri;
135678d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal            mSmsHeader = smsHeader;
13574bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            mFullMessageText = fullMessageText;
13584bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            mSubId = subId;
135952a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen            mIsText = isText;
1360a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            mPersistMessage = persistMessage;
136132cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak            mUserId = userId;
13620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /**
13650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * Returns whether this tracker holds a multi-part SMS.
13660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * @return true if the tracker holds a multi-part SMS; false otherwise
13670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
13680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        boolean isMultipart() {
13690217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            return mData.containsKey("parts");
13700217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        }
13710217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
13725d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan        public HashMap<String, Object> getData() {
13735d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan            return mData;
13745d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan        }
13755d5ca33a24e6b73a48b575a0e1a5e790784d0bb7Amit Mahajan
13760217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        /**
13770217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         * Update the status of this message if we persisted it
13780217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         */
13790217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        public void updateSentMessageStatus(Context context, int status) {
1380c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri != null) {
13810217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // If we wrote this message in writeSentMessage, update it now
13820217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                ContentValues values = new ContentValues(1);
13830217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                values.put(Sms.STATUS, status);
13840217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                SqliteWrapper.update(context, context.getContentResolver(),
1385c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        mMessageUri, values, null, null);
1386c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1387c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1388c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1389c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
13904bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * Set the final state of a message: FAILED or SENT
1391c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1392c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
13934bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The final message type
1394c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param errorCode The error code
1395c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
13964bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private void updateMessageState(Context context, int messageType, int errorCode) {
1397c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri == null) {
1398c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                return;
1399c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
14004bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentValues values = new ContentValues(2);
14014bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.TYPE, messageType);
1402c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            values.put(Sms.ERROR_CODE, errorCode);
1403c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final long identity = Binder.clearCallingIdentity();
1404c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            try {
1405c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
1406c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        null/*where*/, null/*selectionArgs*/) != 1) {
14074bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    Rlog.e(TAG, "Failed to move message to " + messageType);
1408c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1409c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } finally {
1410c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                Binder.restoreCallingIdentity(identity);
1411c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1412c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1413c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1414c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
141552a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen         * Persist a sent SMS if required:
141652a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen         * 1. It is a text message
141752a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen         * 2. SmsApplication tells us to persist: sent from apps that are not default-SMS app or
141852a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen         *    bluetooth
1419c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
14204bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param context
14214bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The folder to store (FAILED or SENT)
14224bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param errorCode The current error code for this SMS or SMS part
14234bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @return The telephony provider URI if stored
1424c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
14254bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) {
1426a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            if (!mIsText || !mPersistMessage ||
142752a98d0a37731f48a316bc79fbc2c5a0f00a5e58Ye Wen                    !SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) {
14284bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return null;
14294bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14304bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            Rlog.d(TAG, "Persist SMS into "
14314bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    + (messageType == Sms.MESSAGE_TYPE_FAILED ? "FAILED" : "SENT"));
14324bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentValues values = new ContentValues();
14334b09dff383ae7dfca595aeeea886a594a1947340Wink Saville            values.put(Sms.SUBSCRIPTION_ID, mSubId);
14344bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.ADDRESS, mDestAddress);
14354bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.BODY, mFullMessageText);
14364bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.DATE, System.currentTimeMillis()); // milliseconds
14374bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.SEEN, 1);
14384bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.READ, 1);
14394bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final String creator = mAppInfo != null ? mAppInfo.packageName : null;
14404bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (!TextUtils.isEmpty(creator)) {
14414bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.CREATOR, creator);
14424bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14434bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (mDeliveryIntent != null) {
14444bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.STATUS, Telephony.Sms.STATUS_PENDING);
14454bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14464bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (errorCode != 0) {
14474bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.ERROR_CODE, errorCode);
1448c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1449c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final long identity = Binder.clearCallingIdentity();
14504bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentResolver resolver = context.getContentResolver();
1451c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            try {
14524bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                final Uri uri =  resolver.insert(Telephony.Sms.Sent.CONTENT_URI, values);
14534bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                if (uri != null && messageType == Sms.MESSAGE_TYPE_FAILED) {
14544bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // Since we can't persist a message directly into FAILED box,
14554bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // we have to update the column after we persist it into SENT box.
14564bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // The gap between the state change is tiny so I would not expect
14574bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // it to cause any serious problem
14584bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // TODO: we should add a "failed" URI for this in SmsProvider?
14594bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    final ContentValues updateValues = new ContentValues(1);
14604bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    updateValues.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
14614bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    resolver.update(uri, updateValues, null/*where*/, null/*selectionArgs*/);
1462c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
14634bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return uri;
14644bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            } catch (Exception e) {
14654bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
14664bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return null;
1467c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } finally {
1468c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                Binder.restoreCallingIdentity(identity);
1469c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1470c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1471c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1472c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
14734bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * Persist or update an SMS depending on if we send a new message or a stored message
14744bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         *
14754bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param context
14764bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The message folder for this SMS, FAILED or SENT
14774bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param errorCode The current error code for this SMS or SMS part
14784bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         */
14794bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private void persistOrUpdateMessage(Context context, int messageType, int errorCode) {
14804bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (mMessageUri != null) {
14814bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                updateMessageState(context, messageType, errorCode);
14824bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            } else {
14834bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode);
14844bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14854bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        }
14864bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen
14874bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        /**
1488c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Handle a failure of a single part message or a part of a multipart message
1489c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1490c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1491c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param error The error to send back with
1492c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param errorCode
1493c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1494c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public void onFailed(Context context, int error, int errorCode) {
1495c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mAnyPartFailed != null) {
1496c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                mAnyPartFailed.set(true);
1497c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1498c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            // is single part or last part of multipart message
1499c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            boolean isSinglePartOrLastPart = true;
1500c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mUnsentPartCount != null) {
1501c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1502c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1503c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (isSinglePartOrLastPart) {
15044bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                persistOrUpdateMessage(context, Sms.MESSAGE_TYPE_FAILED, errorCode);
1505c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1506c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mSentIntent != null) {
1507c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                try {
1508fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    // Extra information to send with the sent intent
1509fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    Intent fillIn = new Intent();
1510fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    if (mMessageUri != null) {
1511fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        // Pass this to SMS apps so that they know where it is stored
1512fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra("uri", mMessageUri.toString());
1513fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    }
1514c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (errorCode != 0) {
1515c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        fillIn.putExtra("errorCode", errorCode);
1516c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1517c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1518c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        // Is multipart and last part
1519c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1520c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1521c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    mSentIntent.send(context, error, fillIn);
1522c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } catch (CanceledException ex) {
1523c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to send result");
1524c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1525c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1526c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1527c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1528c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
1529c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Handle the sent of a single part message or a part of a multipart message
1530c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1531c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1532c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1533c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public void onSent(Context context) {
1534c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            // is single part or last part of multipart message
1535c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            boolean isSinglePartOrLastPart = true;
1536c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mUnsentPartCount != null) {
1537c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1538c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1539c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (isSinglePartOrLastPart) {
15404bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                int messageType = Sms.MESSAGE_TYPE_SENT;
1541c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (mAnyPartFailed != null && mAnyPartFailed.get()) {
15424bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    messageType = Sms.MESSAGE_TYPE_FAILED;
1543c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
15444bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                persistOrUpdateMessage(context, messageType, 0/*errorCode*/);
1545c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1546c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mSentIntent != null) {
1547c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                try {
1548fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    // Extra information to send with the sent intent
1549fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    Intent fillIn = new Intent();
1550fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    if (mMessageUri != null) {
1551fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        // Pass this to SMS apps so that they know where it is stored
1552fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra("uri", mMessageUri.toString());
1553fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    }
1554c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1555c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        // Is multipart and last part
1556fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1557c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1558fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    mSentIntent.send(context, Activity.RESULT_OK, fillIn);
1559c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } catch (CanceledException ex) {
1560c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to send result");
1561c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
15620217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
15630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
15650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1566ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1567c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount,
15686ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi            AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader,
1569a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            boolean isExpectMore, String fullMessageText, boolean isText, boolean persistMessage) {
15701260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get calling app package name via UID from Binder call
15711260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageManager pm = mContext.getPackageManager();
15721260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
15731260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
15741260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get package info via packagemanager
157532cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak        final int userId = UserHandle.getCallingUserId();
15761260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageInfo appInfo = null;
15771260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (packageNames != null && packageNames.length > 0) {
15781260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            try {
15791260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // XXX this is lossy- apps can share a UID
158032cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak                appInfo = pm.getPackageInfoAsUser(
158132cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak                        packageNames[0], PackageManager.GET_SIGNATURES, userId);
15821260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            } catch (PackageManager.NameNotFoundException e) {
15831260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // error will be logged in sendRawPdu
15841260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
15851260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        }
15861260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Strip non-digits from destination phone number before checking for short codes
15871260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // and before displaying the number to the user if confirmation is required.
15881260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
1589c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format,
15904bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                unsentPartCount, anyPartFailed, messageUri, smsHeader, isExpectMore,
159132cc74b9ec7397e995f4e2275315c6f79d1e43fdTony Mak                fullMessageText, getSubId(), isText, persistMessage, userId);
1592c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1593c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1594c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
15954bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            PendingIntent deliveryIntent, String format, Uri messageUri, boolean isExpectMore,
1596a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang            String fullMessageText, boolean isText, boolean persistMessage) {
1597c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/,
15984bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                null/*anyPartFailed*/, messageUri, null/*smsHeader*/, isExpectMore,
1599a8f8c5a113a66de4854f4fb13a5825eb0705bd59Ji Yang                fullMessageText, isText, persistMessage);
16001260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
16011260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1602ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
16031260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            String text, SmsMessageBase.SubmitPduBase pdu) {
16041260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
16051260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
16061260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
16071260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("text", text);
16081260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
16091260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
16101260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
16111260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
16121260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1613ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
16141260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
16151260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
16161260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
16171260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
1618ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        map.put("destPort", destPort);
16191260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("data", data);
16201260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
16211260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
16221260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
16231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
16241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
16250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
16260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dialog listener for SMS confirmation dialog.
16270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
16280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final class ConfirmDialogListener
16294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
16304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            CompoundButton.OnCheckedChangeListener {
16310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        private final SmsTracker mTracker;
16334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mPositiveButton;
16344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mNegativeButton;
16354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private boolean mRememberChoice;    // default is unchecked
163678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        private final TextView mRememberUndoInstruction;
16370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
163878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener(SmsTracker tracker, TextView textView) {
16390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mTracker = tracker;
164078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt            mRememberUndoInstruction = textView;
16410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setPositiveButton(Button button) {
16444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mPositiveButton = button;
16454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
16464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setNegativeButton(Button button) {
16484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mNegativeButton = button;
16494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
16504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
16520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onClick(DialogInterface dialog, int which) {
16534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Always set the SMS permission so that Settings will show a permission setting
16544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // for the app (it won't be shown until after the app tries to send to a short code).
16554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
16564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (which == DialogInterface.BUTTON_POSITIVE) {
1658ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "CONFIRM sending SMS");
16592029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1660634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_SENT_BY_USER,
1661ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1662ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 : mTracker.mAppInfo.applicationInfo.uid);
16630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker));
16644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
16654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
16664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
16670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (which == DialogInterface.BUTTON_NEGATIVE) {
1668ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "DENY sending SMS");
16692029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1670634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
1671ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1672ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 :  mTracker.mAppInfo.applicationInfo.uid);
16730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
16744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
16754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
16764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
16770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
16784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            setPremiumSmsPermission(mTracker.mAppInfo.packageName, newSmsPermission);
16790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
16820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onCancel(DialogInterface dialog) {
1683ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "dialog dismissed: don't send SMS");
16840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
16850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        @Override
16884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1689ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "remember this choice: " + isChecked);
16904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mRememberChoice = isChecked;
16914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (isChecked) {
16924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
16934658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
169478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
169578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.
169678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                            setText(R.string.sms_short_code_remember_undo_instruction);
169778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,32);
169878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
16994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            } else {
17004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
17015d875796122cdd8a7004e8e3964b20b5c65a31a1Robert Greenwalt                mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
170278df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
170378df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setText("");
170478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,0);
170578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
17064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
17074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
17080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
17091260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1710ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public boolean isIms() {
1711ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1712ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.isIms();
1713ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1714ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1715ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return false;
1716ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1717ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
17181260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1719ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public String getImsSmsFormat() {
1720ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1721ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.getImsSmsFormat();
1722ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1723ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1724ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return null;
1725ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1726ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
1727c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1728c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    private String getMultipartMessageText(ArrayList<String> parts) {
1729c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final StringBuilder sb = new StringBuilder();
1730c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        for (String part : parts) {
1731c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (part != null) {
1732c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                sb.append(part);
1733c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1734c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1735c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return sb.toString();
1736c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1737b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen
17388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected String getCarrierAppPackageName() {
1739062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
17407f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal        if (card == null) {
17417f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal            return null;
17427f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal        }
17437f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal
1744934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero        List<String> carrierPackages = card.getCarrierPackageNamesForIntent(
17458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mContext.getPackageManager(), new Intent(CarrierMessagingService.SERVICE_INTERFACE));
17464256e499c8e1e0a07998dcaf1f3aa127b693fc42Madhusudhan R. Adupala        if (carrierPackages != null && carrierPackages.size() == 1) {
17474256e499c8e1e0a07998dcaf1f3aa127b693fc42Madhusudhan R. Adupala            return carrierPackages.get(0);
17484256e499c8e1e0a07998dcaf1f3aa127b693fc42Madhusudhan R. Adupala        }
17494256e499c8e1e0a07998dcaf1f3aa127b693fc42Madhusudhan R. Adupala        // If there is no carrier package which implements CarrierMessagingService, then lookup if
17504256e499c8e1e0a07998dcaf1f3aa127b693fc42Madhusudhan R. Adupala        // for a carrierImsPackage that implements CarrierMessagingService.
17514256e499c8e1e0a07998dcaf1f3aa127b693fc42Madhusudhan R. Adupala        return CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
17524256e499c8e1e0a07998dcaf1f3aa127b693fc42Madhusudhan R. Adupala                new Intent(CarrierMessagingService.SERVICE_INTERFACE));
1753c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal    }
1754c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal
1755b237a11044ed842d2865ff8c8716befb06b6ca25Wink Saville    protected int getSubId() {
175614bdfdca7a5412edf5fbdd6573e0f608233a5ae8Amit Mahajan        return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.getPhoneId());
1757b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    }
1758f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal
1759f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal    private void checkCallerIsPhoneOrCarrierApp() {
1760f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        int uid = Binder.getCallingUid();
1761f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        int appId = UserHandle.getAppId(uid);
1762f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        if (appId == Process.PHONE_UID || uid == 0) {
1763f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            return;
1764f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        }
1765f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        try {
1766f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            PackageManager pm = mContext.getPackageManager();
1767f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            ApplicationInfo ai = pm.getApplicationInfo(getCarrierAppPackageName(), 0);
1768f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            if (!UserHandle.isSameApp(ai.uid, Binder.getCallingUid())) {
1769f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal                throw new SecurityException("Caller is not phone or carrier app!");
1770f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            }
1771f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        } catch (PackageManager.NameNotFoundException re) {
1772f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal            throw new SecurityException("Caller is not phone or carrier app!");
1773f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal        }
1774f323afdb70b83e0c851ced2af7594b20412542c3Shishir Agrawal    }
17750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
1776