SMSDispatcher.java revision 062a2a3838c8d8adf16f4d9fbde8d52450da0336
10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2006 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.Activity;
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.AlertDialog;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent.CanceledException;
228215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.content.ComponentName;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ContentResolver;
240217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.content.ContentValues;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Context;
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.DialogInterface;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Intent;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.ApplicationInfo;
292029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.content.pm.PackageInfo;
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.PackageManager;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources;
328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.content.ServiceConnection;
33ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.database.ContentObserver;
340217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.database.sqlite.SqliteWrapper;
350217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.net.Uri;
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.AsyncResult;
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Binder;
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler;
398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.os.IBinder;
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.os.RemoteException;
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.SystemProperties;
43ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.provider.Settings;
440217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.provider.Telephony;
450217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braunimport android.provider.Telephony.Sms;
468d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport android.provider.Telephony.Sms.Intents;
478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.CarrierMessagingService;
488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.ICarrierMessagingCallback;
498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.service.carrier.ICarrierMessagingService;
508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wangimport android.telephony.CarrierMessagingServiceManager;
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.PhoneNumberUtils;
520d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.Rlog;
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.ServiceState;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.TelephonyManager;
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Html;
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Spanned;
57b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wenimport android.text.TextUtils;
582029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.util.EventLog;
594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.LayoutInflater;
604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.View;
6178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwaltimport android.view.ViewGroup;
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.WindowManager;
634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.Button;
644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CheckBox;
654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CompoundButton;
664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.TextView;
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.R;
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
70a9552aa6bf3ce12c75ad43165034d9a1233fb131Shishir Agrawalimport com.android.internal.telephony.uicc.UiccCard;
71c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawalimport com.android.internal.telephony.uicc.UiccController;
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
748d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport java.util.Collections;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap;
768d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wangimport java.util.List;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Random;
78c99dab56e20222b28cbc6238645feac938f1c333Ye Wenimport java.util.concurrent.atomic.AtomicBoolean;
790d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.concurrent.atomic.AtomicInteger;
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
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
930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Permission required to send SMS to short codes without user confirmation. */
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_SMS_NO_CONFIRMATION_PERMISSION =
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "android.permission.SEND_SMS_NO_CONFIRMATION";
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
97ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_SIM = 1;
98ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_NETWORK = 2;
99ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_BOTH = 3;
100ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
101ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final SettingsObserver mSettingsObserver;
102ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** SMS send complete. */
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int EVENT_SEND_SMS_COMPLETE = 2;
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Retry sending a previously failed SMS message */
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_RETRY = 3;
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for sending a large number of messages. */
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Send the user confirmed SMS */
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_SEND_CONFIRMED_SMS = 5;  // accessed from inner class
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Don't send SMS (user did not confirm). */
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_STOP_SENDING = 7;        // accessed from inner class
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /** Handle status report from {@code CdmaInboundSmsHandler}. */
1250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected static final int EVENT_HANDLE_STATUS_REPORT = 10;
1260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
1271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Radio is ON */
1281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_RADIO_ON = 11;
1291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** IMS registration/SMS format changed */
1311260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_CHANGED = 12;
1321260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1331260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */
1341260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_IMS_STATE_DONE = 13;
1351260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1361260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    // other
1371260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_NEW_ICC_SMS = 14;
1381260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected static final int EVENT_ICC_CHANGED = 15;
1391260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1401260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected PhoneBase mPhone;
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final Context mContext;
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ContentResolver mResolver;
14322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville    protected final CommandsInterface mCi;
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final TelephonyManager mTelephonyManager;
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Maximum number of times to retry sending a failed SMS. */
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MAX_SEND_RETRIES = 3;
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Delay before next send attempt on a failed SMS, in milliseconds. */
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SEND_RETRY_DELAY = 2000;
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** single part SMS */
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SINGLE_PART_SMS = 1;
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Message sending queue limit */
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MO_MSG_QUEUE_LIMIT = 5;
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Message reference for a CONCATENATED_8_BIT_REFERENCE or
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CONCATENATED_16_BIT_REFERENCE message set.  Should be
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * incremented for each set of concatenated messages.
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Static field shared by all dispatcher objects.
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int sConcatenatedRef = new Random().nextInt(256);
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Outgoing message counter. Shared by all dispatchers. */
1641260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    private SmsUsageMonitor mUsageMonitor;
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
166ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    private ImsSMSDispatcher mImsSMSDispatcher;
167ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Number of outgoing SmsTrackers waiting for user confirmation. */
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mPendingTrackerCount;
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* Flags indicating whether the current device allows sms service */
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsCapable = true;
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsSendDisabled;
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static int getNextConcatenatedRef() {
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sConcatenatedRef += 1;
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return sConcatenatedRef;
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SMS dispatcher.
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param phone the Phone to use
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param usageMonitor the SmsUsageMonitor to use
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
185ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SMSDispatcher(PhoneBase phone, SmsUsageMonitor usageMonitor,
186ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            ImsSMSDispatcher imsSMSDispatcher) {
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhone = phone;
188ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        mImsSMSDispatcher = imsSMSDispatcher;
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mContext = phone.getContext();
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mResolver = mContext.getContentResolver();
19122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi = phone.mCi;
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mUsageMonitor = usageMonitor;
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
194ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
195ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
196ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsCapable = mContext.getResources().getBoolean(
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                com.android.internal.R.bool.config_sms_capable);
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsSendDisabled = !SystemProperties.getBoolean(
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                TelephonyProperties.PROPERTY_SMS_SEND, mSmsCapable);
202ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + " mSmsSendDisabled=" + mSmsSendDisabled);
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
206ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    /**
207ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     * Observe the secure setting for updated premium sms determination rules
208ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     */
209ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static class SettingsObserver extends ContentObserver {
210ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final AtomicInteger mPremiumSmsRule;
211ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final Context mContext;
212ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
213ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            super(handler);
214ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule = premiumSmsRule;
215ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mContext = context;
216ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            onChange(false); // load initial value;
217ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
218ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
219ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        @Override
220ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        public void onChange(boolean selfChange) {
221ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
222ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
223ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
224ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    }
225ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
2261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void updatePhoneObject(PhoneBase phone) {
2271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mPhone = phone;
2281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        mUsageMonitor = phone.mSmsUsageMonitor;
2291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        Rlog.d(TAG, "Active phone changed to " + mPhone.getPhoneName() );
2301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
2311260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Unregister for incoming SMS events. */
2330d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    public void dispose() {
2340d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
2350d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The format of the message PDU in the associated broadcast intent.
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Note: All applications which handle incoming SMS messages by processing the
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * into the new methods in {@link android.telephony.SmsMessage} which take an
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * extra format parameter. This is required in order to correctly decode the PDU on
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * devices which require support for both 3GPP and 3GPP2 formats at the same time,
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * such as CDMA/LTE devices and GSM/CDMA world phones.
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the format of the message PDU
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract String getFormat();
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
2540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Pass the Message object to subclass to handle. Currently used to pass CDMA status reports
2550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * from {@link com.android.internal.telephony.cdma.CdmaInboundSmsHandler}.
2560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param o the SmsMessage containing the status report
2570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
2580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    protected void handleStatusReport(Object o) {
2590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        Rlog.d(TAG, "handleStatusReport() called with no subclass.");
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* TODO: Need to figure out how to keep track of status report routing in a
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       persistent manner. If the phone process restarts (reboot or crash),
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       we will lose this list and any status reports that come in after
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       will be dropped.
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Sent messages awaiting a delivery status report. */
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles events coming from the phone stack. Overridden from handler.
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg the message to handle
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msg.what) {
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_SMS_COMPLETE:
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // An outbound SMS has been successfully transferred, or failed.
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleSendComplete((AsyncResult) msg.obj);
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_RETRY:
2841260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            Rlog.d(TAG, "SMS retry..");
2851260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            sendRetrySms((SmsTracker) msg.obj);
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleReachSentLimit((SmsTracker)(msg.obj));
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(false, (SmsTracker)(msg.obj));
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(true, (SmsTracker)(msg.obj));
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_CONFIRMED_SMS:
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.isMultipart()) {
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMultipartSms(tracker);
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
3066c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                if (mPendingTrackerCount > 1) {
3076c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                    tracker.mExpectMore = true;
3086c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                } else {
3096c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                    tracker.mExpectMore = false;
3106c376fea69306e22a2f11894d05cd0abfdaefed3Xia Ying                }
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_STOP_SENDING:
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
320c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        case EVENT_HANDLE_STATUS_REPORT:
3260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            handleStatusReport(msg.obj);
3270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            break;
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        default:
3300d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what);
3310d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
332b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    }
333b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
334b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    /**
3358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a data or text SMS.
3368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
3378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract class SmsSender extends CarrierMessagingServiceManager {
3388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected final SmsTracker mTracker;
3398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        // Initialized in sendSmsByCarrierApp
3408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected volatile SmsSenderCallback mSenderCallback;
3418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3428215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected SmsSender(SmsTracker tracker) {
3438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mTracker = tracker;
3448215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3468215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void sendSmsByCarrierApp(String carrierPackageName,
3478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                        SmsSenderCallback senderCallback) {
3488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSenderCallback = senderCallback;
3498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
3508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "bindService() for carrier messaging service failed");
3518215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
3528215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3538215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
3548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
3558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
3568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
3578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
3598215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3608215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
3618215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a text SMS.
3628215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
3638215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class TextSmsSender extends SmsSender {
3648215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public TextSmsSender(SmsTracker tracker) {
3658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            super(tracker);
3668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
3698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
3708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            HashMap<String, Object> map = mTracker.mData;
3718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            String text = (String) map.get("text");
3728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (text != null) {
3748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                try {
3758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    carrierMessagingService.sendTextSms(text, getSubId(),
3768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            mTracker.mDestAddress, mSenderCallback);
3778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } catch (RemoteException e) {
3788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Exception sending the SMS: " + e);
3798215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    mSenderCallback.onSendSmsComplete(
3808215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3818215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            0 /* messageRef */);
3828215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
3838215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
3848215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
3858215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
3868215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
3878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
3888215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
3908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
3928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a data SMS.
3938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
3948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class DataSmsSender extends SmsSender {
3958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public DataSmsSender(SmsTracker tracker) {
3968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            super(tracker);
3978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
3988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
3998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
4018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            HashMap<String, Object> map = mTracker.mData;
4028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            byte[] data = (byte[]) map.get("data");
4038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            int destPort = (int) map.get("destPort");
4048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (data != null) {
4068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                try {
4078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    carrierMessagingService.sendDataSms(data, getSubId(),
4088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            mTracker.mDestAddress, destPort, mSenderCallback);
4098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } catch (RemoteException e) {
4108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Exception sending the SMS: " + e);
4118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    mSenderCallback.onSendSmsComplete(
4128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
4138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            0 /* messageRef */);
4148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
4158215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
4168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendSmsComplete(
4178215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
4188215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        0 /* messageRef */);
4198215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
4208215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4218215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
4228215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4238215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
4248215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Callback for TextSmsSender and DataSmsSender from the carrier messaging service.
4258215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Once the result is ready, the carrier messaging service connection is disposed.
4268215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
4278215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected final class SmsSenderCallback extends ICarrierMessagingCallback.Stub {
4288215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final SmsSender mSmsSender;
4298215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4308215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public SmsSenderCallback(SmsSender smsSender) {
4318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender = smsSender;
4328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4338215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        /**
4358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         * This method should be called only once.
4368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         */
4378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendSmsComplete(int result, int messageRef) {
4398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender.disposeConnection(mContext);
4408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
4418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4428215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4448215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
4458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result);
4468215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onFilterComplete(boolean keepMessage) {
4508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + keepMessage);
4518215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4528215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4538215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
4558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
4568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
4598215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onDownloadMmsComplete(int result) {
4608215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
4618215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4628215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
4638215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4648215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private void processSendSmsResponse(SmsTracker tracker, int result, int messageRef) {
4658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (tracker == null) {
4668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "processSendSmsResponse: null tracker");
4678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            return;
4688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        SmsResponse smsResponse = new SmsResponse(
4718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                messageRef, null /* ackPdu */, -1 /* unknown error code */);
4728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        switch (result) {
4748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_OK:
4758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP succeeded.");
4768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
4778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                      new AsyncResult(tracker,
4788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                                      smsResponse,
4798215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                                      null /* exception*/ )));
4808215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
4818215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_ERROR:
4828215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP failed.");
4838215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
4848215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    new AsyncResult(tracker, smsResponse,
4858215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                            new CommandException(CommandException.Error.GENERIC_FAILURE))));
4868215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
4878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
4888215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Sending SMS by IP failed. Retry on carrier network.");
4898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendSubmitPdu(tracker);
4908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            break;
4918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        default:
4928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Unknown result " + result + " Retry on carrier network.");
4938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            sendSubmitPdu(tracker);
4948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
4958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
4968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
4978215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
4988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Use the carrier messaging service to send a multipart text SMS.
4998215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
5008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private final class MultipartSmsSender extends CarrierMessagingServiceManager {
5018215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final List<String> mParts;
5028215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public final SmsTracker[] mTrackers;
5038215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        // Initialized in sendSmsByCarrierApp
5048215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private volatile MultipartSmsSenderCallback mSenderCallback;
5058215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5068215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        MultipartSmsSender(ArrayList<String> parts, SmsTracker[] trackers) {
5078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mParts = parts;
5088215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mTrackers = trackers;
5098215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5108215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5118215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        void sendSmsByCarrierApp(String carrierPackageName,
5128215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                                 MultipartSmsSenderCallback senderCallback) {
5138215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSenderCallback = senderCallback;
5148215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
5158215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "bindService() for carrier messaging service failed");
5168215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendMultipartSmsComplete(
5178215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
5188215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        null /* smsResponse */);
5198215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } else {
5208215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.d(TAG, "bindService() for carrier messaging service succeeded");
5218215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5228215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5238215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5248215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5258215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
5268215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            try {
5278215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                carrierMessagingService.sendMultipartTextSms(
5288215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        mParts, getSubId(), mTrackers[0].mDestAddress, mSenderCallback);
5298215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            } catch (RemoteException e) {
5308215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "Exception sending the SMS: " + e);
5318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                mSenderCallback.onSendMultipartSmsComplete(
5328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
5338215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        null /* smsResponse */);
5348215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5358215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5368215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
5378215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
5398215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Callback for MultipartSmsSender from the carrier messaging service.
5408215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Once the result is ready, the carrier messaging service connection is disposed.
5418215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
5428215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    private final class MultipartSmsSenderCallback extends ICarrierMessagingCallback.Stub {
5438215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        private final MultipartSmsSender mSmsSender;
5448215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5458215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        MultipartSmsSenderCallback(MultipartSmsSender smsSender) {
5468215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender = smsSender;
5478215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5488215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5498215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5508215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendSmsComplete(int result, int messageRef) {
5518215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result);
5528215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5538215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5548215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        /**
5558215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         * This method should be called only once.
5568215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang         */
5578215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5588215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
5598215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mSmsSender.disposeConnection(mContext);
5608215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5618215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            if (mSmsSender.mTrackers == null) {
5628215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers.");
5638215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                return;
5648215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5658215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5668215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            for (int i = 0; i < mSmsSender.mTrackers.length; i++) {
5678215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                int messageRef = 0;
5688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                if (messageRefs != null && messageRefs.length > i) {
5698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    messageRef = messageRefs[i];
5708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
5718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                processSendSmsResponse(mSmsSender.mTrackers[i], result, messageRef);
5728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
5738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onFilterComplete(boolean keepMessage) {
5778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + keepMessage);
5788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5798215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5808215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5818215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onSendMmsComplete(int result, byte[] sendConfPdu) {
5828215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result);
5838215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5848215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5858215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        @Override
5868215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        public void onDownloadMmsComplete(int result) {
5878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result);
5888215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
5898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    }
5908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
5928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Send an SMS PDU. Usually just calls {@link sendRawPdu}.
5938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     */
5948215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract void sendSubmitPdu(SmsTracker tracker);
5958215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
5968215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    /**
5970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Called when SMS send completes. Broadcasts a sentIntent on success.
5980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * On failure, either sets up retries or broadcasts a sentIntent with
5990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the failure in the result code.
6000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
6010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ar AsyncResult passed into the message handler.  ar.result should
6020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           an SmsResponse instance if send was successful.  ar.userObj
6030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           should be an SmsTracker instance.
6040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleSendComplete(AsyncResult ar) {
6060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsTracker tracker = (SmsTracker) ar.userObj;
6070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PendingIntent sentIntent = tracker.mSentIntent;
6080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
609454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        if (ar.result != null) {
6105a176f73dbb2bff2ca8b8f86af86a17be6863b87Wink Saville            tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
611454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        } else {
612454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks            Rlog.d(TAG, "SmsResponse was null");
613454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        }
614454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks
6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (ar.exception == null) {
616cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.mDeliveryIntent != null) {
6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Expecting a status report.  Add it to the list.
6200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryPendingList.add(tracker);
6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
622c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onSent(mContext);
6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
624cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send failed");
6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
6270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {
6291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // This is retry after failure over IMS but voice is not available.
6301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // Set retry to max allowed, so no retry is sent and
6311260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.
6321260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                tracker.mRetryCount = MAX_SEND_RETRIES;
6331260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
6341260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                Rlog.d(TAG, "handleSendComplete: Skipping retry: "
6351260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" isIms()="+isIms()
6361260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mRetryCount="+tracker.mRetryCount
6371260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mImsRetry="+tracker.mImsRetry
6381260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" mMessageRef="+tracker.mMessageRef
6391260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                +" SS= "+mPhone.getServiceState().getState());
6401260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
6411260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
6421260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            // if sms over IMS is not supported on data and voice is not available...
6431260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
644c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
6450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if ((((CommandException)(ar.exception)).getCommandError()
6460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    == CommandException.Error.SMS_FAIL_RETRY) &&
6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                   tracker.mRetryCount < MAX_SEND_RETRIES) {
6480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Retry after a delay if needed.
6490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // TODO: According to TS 23.040, 9.2.3.6, we should resend
6500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       with the same TP-MR as the failed message, and
6510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       TP-RD set to 1.  However, we don't have a means of
6520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       knowing the MR for the failed message (EF_SMSstatus
6530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       may or may not have the MR corresponding to this
6540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       message, depending on the failure).  Also, in some
6550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       implementations this retry is handled by the baseband.
6560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tracker.mRetryCount++;
6570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
6580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
659c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } else {
660c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                int errorCode = 0;
661c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (ar.result != null) {
662c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    errorCode = ((SmsResponse)ar.result).mErrorCode;
663c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
6640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int error = RESULT_ERROR_GENERIC_FAILURE;
6650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (((CommandException)(ar.exception)).getCommandError()
6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        == CommandException.Error.FDN_CHECK_FAILURE) {
6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    error = RESULT_ERROR_FDN_CHECK_FAILURE;
6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
669c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                tracker.onFailed(mContext, error, errorCode);
6700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
6750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles outbound message when the phone is not in service.
6760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
6770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ss     Current service state.  Valid values are:
6780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  OUT_OF_SERVICE
6790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  EMERGENCY_ONLY
6800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  POWER_OFF
6810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent the PendingIntent to send the error to
6820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
6830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static void handleNotInService(int ss, PendingIntent sentIntent) {
6840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (sentIntent != null) {
6850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
6860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ss == ServiceState.STATE_POWER_OFF) {
6870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_RADIO_OFF);
6880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
6890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NO_SERVICE);
6900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CanceledException ex) {}
6920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
696c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     * @param ss service state
697c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     * @return The result error based on input service state for not in service error
698c99dab56e20222b28cbc6238645feac938f1c333Ye Wen     */
699c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected static int getNotInServiceError(int ss) {
700c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        if (ss == ServiceState.STATE_POWER_OFF) {
701c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return RESULT_ERROR_RADIO_OFF;
702c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
703c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return RESULT_ERROR_NO_SERVICE;
704c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
705c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
706c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    /**
7070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a data based SMS to a specific application port.
7080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
7100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
7110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
7120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destPort the port to deliver the message to
7130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data the body of the message to send
7140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
7150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
7160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
7170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
7180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
7190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
7200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
7210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
7220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
7230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
7240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
7250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
7260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
7270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
7280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
7290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
7300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
7310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendData(String destAddr, String scAddr, int destPort,
7330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent);
7340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a text based SMS.
737b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     *  @param destAddr the address to send the message to
7380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
7390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
7400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param text the body of the message to send
7410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
7420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
7430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
7440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
7450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
7460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
7470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
7480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
7490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
7500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
7510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
7520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
7530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
7540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
7550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
7560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
757b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param messageUri optional URI of the message if it is already stored in the system
758b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param callingPkg the calling package name
7590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
760b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    protected abstract void sendText(String destAddr, String scAddr, String text,
761b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri,
762b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            String callingPkg);
7630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
76563418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * Inject an SMS PDU into the android platform.
76663418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *
76763418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param pdu is the byte array of pdu to be injected into android telephony layer
76863418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param format is the format of SMS pdu (3gpp or 3gpp2)
76963418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
77063418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  broadcast when the message is successfully received by the
77163418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  android telephony layer. This intent is broadcasted at
77263418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     *  the same time an SMS received from radio is responded back.
77363418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni     */
77463418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni    protected abstract void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent);
77563418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni
77663418bbd2a9d7cc88ae24cc5ae776c01d688fc3aAnil Muthineni    /**
7770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Calculate the number of septets needed to encode the message.
7780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param messageBody the message to encode
7800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param use7bitOnly ignore (but still count) illegal characters if true
7810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return TextEncodingDetails
7820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
7840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean use7bitOnly);
7850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a multi-part text based SMS.
788b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     *  @param destAddr the address to send the message to
7890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
7900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   the current default SMSC
7910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param parts an <code>ArrayList</code> of strings that, in order,
7920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   comprise the original message
7930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntents if not null, an <code>ArrayList</code> of
7940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
7950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been sent.
7960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   The result code will be <code>Activity.RESULT_OK<code> for success,
7970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   or one of these errors:
7980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
7990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_RADIO_OFF</code>
8000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NULL_PDU</code>
8010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NO_SERVICE</code>.
8020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
8030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
8040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
8050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntents if not null, an <code>ArrayList</code> of
8060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
8070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been delivered
8080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   to the recipient.  The raw pdu of the status report is in the
809b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param messageUri optional URI of the message if it is already stored in the system
810b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen     * @param callingPkg the calling package name
8110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendMultipartText(String destAddr, String scAddr,
8130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
814b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg) {
8154bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        final String fullMessageText = getMultipartMessageText(parts);
8160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int refNumber = getNextConcatenatedRef() & 0x00FF;
8170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgCount = parts.size();
8180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int encoding = SmsConstants.ENCODING_UNKNOWN;
8190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
8210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
8220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            TextEncodingDetails details = calculateLength(parts.get(i), false);
8230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding != details.codeUnitSize
8240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    && (encoding == SmsConstants.ENCODING_UNKNOWN
8250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            || encoding == SmsConstants.ENCODING_7BIT)) {
8260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encoding = details.codeUnitSize;
8270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            encodingForParts[i] = details;
8290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        SmsTracker[] trackers = new SmsTracker[msgCount];
8328215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
833c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        // States to track at the message level (for all parts)
834c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
835c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
836c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
8370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
8380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
8390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.refNumber = refNumber;
8400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.seqNumber = i + 1;  // 1-based sequence
8410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.msgCount = msgCount;
8420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // TODO: We currently set this to true since our messaging app will never
8430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // send more than 255 parts (it converts the message to MMS well before that).
8440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // However, we should support 3rd party messaging apps that might need 16-bit
8450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // references
8460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Note:  It's not sufficient to just flip this bit to true; it will have
8470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // ripple effects (several calculations assume 8-bit ref).
8480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.isEightBits = true;
8490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader smsHeader = new SmsHeader();
8500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsHeader.concatRef = concatRef;
8510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Set the national language tables for 3GPP 7-bit encoding, if enabled.
8530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding == SmsConstants.ENCODING_7BIT) {
8540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageTable = encodingForParts[i].languageTable;
8550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
8560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent = null;
8590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntents != null && sentIntents.size() > i) {
8600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sentIntent = sentIntents.get(i);
8610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent deliveryIntent = null;
8640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (deliveryIntents != null && deliveryIntents.size() > i) {
8650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryIntent = deliveryIntents.get(i);
8660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8688215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            trackers[i] =
8698215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding,
8708215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        sentIntent, deliveryIntent, (i == (msgCount - 1)),
8718215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                        unsentPartCount, anyPartFailed, messageUri, fullMessageText);
8728215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
8738215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
8748215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (parts == null || trackers == null || trackers.length == 0
8758215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                || trackers[0] == null) {
8768215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers);
8778215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            return;
8788215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        }
8798215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang
8808215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        String carrierPackage = getCarrierAppPackageName();
8818215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        if (carrierPackage != null) {
8828215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.d(TAG, "Found carrier package.");
8838215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
8848215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            smsSender.sendSmsByCarrierApp(carrierPackage, new MultipartSmsSenderCallback(smsSender));
8858215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang        } else {
8868215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            Rlog.v(TAG, "No carrier package.");
8878215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            for (SmsTracker tracker : trackers) {
8888215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                if (tracker != null) {
8898215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    sendSubmitPdu(tracker);
8908215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                } else {
8918215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                    Rlog.e(TAG, "Null tracker.");
8928215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang                }
8938215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            }
8940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
8960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8988215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Create a new SubmitPdu and return the SMS tracker.
8990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9008215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected abstract SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
9010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String message, SmsHeader smsHeader, int encoding,
902c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
9034bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
9044bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            String fullMessageText);
9050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9078215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang     * Send an SMS
9081260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker will contain:
9091260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -smsc the SMSC to send the message through, or NULL for the
9100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  default SMSC
9111260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -pdu the raw PDU to send
9121260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -sentIntent if not NULL this <code>Intent</code> is
9130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
9140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
9150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:
9160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
9170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code>
9180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code>
9190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code>.
9200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
9210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
9220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
9231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -deliveryIntent if not NULL this <code>Intent</code> is
9240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
9250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
9261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * -param destAddr the destination phone number (for short code confirmation)
9270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    protected void sendRawPdu(SmsTracker tracker) {
9291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap map = tracker.mData;
9301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        byte pdu[] = (byte[]) map.get("pdu");
9311260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
9320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mSmsSendDisabled) {
933c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Device does not support sending sms.");
934c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
9350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pdu == null) {
939c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Empty PDU");
940c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);
9410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Get calling app package name via UID from Binder call
9450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
9460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
9470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (packageNames == null || packageNames.length == 0) {
9490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Refuse to send SMS if we can't get the calling package name.
950ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");
951c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
9520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9552029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        // Get package info via packagemanager
9560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        PackageInfo appInfo;
9572029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        try {
9582029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            // XXX this is lossy- apps can share a UID
9592029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
9602029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        } catch (PackageManager.NameNotFoundException e) {
961ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
962c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
9632029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            return;
9642029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        }
9650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // checkDestination() returns true if the destination is not a premium short code or the
9670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // sending app is approved to send to short codes. Otherwise, a message is sent to our
9680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // handler with the SmsTracker to request user confirmation before sending.
9690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (checkDestination(tracker)) {
9700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // check for excessive outgoing SMS usage by this app
9712029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
9720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
9730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
9740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
976a0c22039b77054d659151537896c1db90c7057f7Shishir Agrawal            sendSms(tracker);
9770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
9790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Check if destination is a potential premium short code and sender is not pre-approved to
9820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * send to short codes.
9830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
9840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the tracker for the SMS to send
9850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the destination is approved; false if user confirmation event was sent
9860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean checkDestination(SmsTracker tracker) {
9880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION_PERMISSION)
9890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                == PackageManager.PERMISSION_GRANTED) {
9900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;            // app is pre-approved to send to short codes
9910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
992ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int rule = mPremiumSmsRule.get();
993ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
994ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
995ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String simCountryIso = mTelephonyManager.getSimCountryIso();
996ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (simCountryIso == null || simCountryIso.length() != 2) {
997ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso");
998ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    simCountryIso = mTelephonyManager.getNetworkCountryIso();
999ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
1000ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1001ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                smsCategory = mUsageMonitor.checkDestination(tracker.mDestAddress, simCountryIso);
1002ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            }
1003ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
1004ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String networkCountryIso = mTelephonyManager.getNetworkCountryIso();
1005ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (networkCountryIso == null || networkCountryIso.length() != 2) {
1006ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso");
1007ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    networkCountryIso = mTelephonyManager.getSimCountryIso();
1008ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
1009ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1010cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville                smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory,
1011ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                        mUsageMonitor.checkDestination(tracker.mDestAddress, networkCountryIso));
10120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1014ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE
1015ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE
1016ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) {
10174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                return true;    // not a premium short code
10184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
10194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
10204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Wait for user confirmation unless the user has set permission to always allow/deny
10214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int premiumSmsPermission = mUsageMonitor.getPremiumSmsPermission(
10224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    tracker.mAppInfo.packageName);
10234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
10244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                // First time trying to send to premium SMS.
10254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
10264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
10270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            switch (premiumSmsPermission) {
10294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
1030ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.d(TAG, "User approved this app to send to premium SMS");
10314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return true;
10320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
1034ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.w(TAG, "User denied this app from sending to premium SMS");
10354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(EVENT_STOP_SENDING, tracker));
10364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // reject this message
10374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
10384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
10390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                default:
10404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    int event;
1041ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
10424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
10434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    } else {
10444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
10454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    }
10464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(event, tracker));
10474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // wait for user confirmation
10480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Deny sending an SMS if the outgoing queue limit is reached. Used when the message
10540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * must be confirmed by the user due to excessive usage or potential premium SMS detected.
10550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the message to send
10560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the message was denied; false to continue with send confirmation
10570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean denyIfQueueLimitReached(SmsTracker tracker) {
10590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
10600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Deny sending message when the queue limit is reached.
1061c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Rlog.e(TAG, "Denied because queue limit reached");
1062c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
10630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;
10640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPendingTrackerCount++;
10660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return false;
10670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns the label for the specified app package name.
10710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param appPackage the package name of the app requesting to send an SMS
10720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the label for the specified app, or the package name if getApplicationInfo() fails
10730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private CharSequence getAppLabel(String appPackage) {
10750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
10760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
10770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ApplicationInfo appInfo = pm.getApplicationInfo(appPackage, 0);
10780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appInfo.loadLabel(pm);
10790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (PackageManager.NameNotFoundException e) {
1080ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
10810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appPackage;  // fall back to package name if we can't get app label
10820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert when SMS needs confirmation due to excessive usage.
10870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker an SmsTracker for the current message.
10880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleReachSentLimit(SmsTracker tracker) {
10900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
10910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
10920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10942029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
10950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
10960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
10970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
109878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null);
10990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
11010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setTitle(R.string.sms_control_title)
11020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setIcon(R.drawable.stat_sys_warning)
11030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setMessage(messageText)
11040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
11050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_control_no), listener)
11060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
11070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
11080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
11100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
11110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert for user confirmation when sending to a potential short code.
11150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param isPremium true if the destination is known to be a premium short code
11160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the current message.
11170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) {
11190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
11200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
11210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        int detailsId;
11240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isPremium) {
11254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_premium_short_code_details;
11260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
11274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_short_code_details;
11280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11302029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
11310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
11324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
11334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                appLabel, tracker.mDestAddress));
11340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
11364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                Context.LAYOUT_INFLATER_SERVICE);
11374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
11384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
113978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
114078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                (TextView)layout.findViewById(R.id.sms_short_code_remember_undo_instruction));
114178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
114278df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
11434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
11444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        messageView.setText(messageText);
11454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
114678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
11474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_layout);
11484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView detailsView = (TextView) detailsLayout.findViewById(
11494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_message);
11504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        detailsView.setText(detailsId);
11514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        CheckBox rememberChoice = (CheckBox) layout.findViewById(
11534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_remember_choice_checkbox);
11544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        rememberChoice.setOnCheckedChangeListener(listener);
11554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
11574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                .setView(layout)
11580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
11590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
11600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
11610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
11620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
11640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
11654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
11674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
11684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
11694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
11714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Returns the premium SMS permission for the specified package. If the package has never
11724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}
11734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * will be returned.
11744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to query permission
11754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
11764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
11774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
11784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
11794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
11804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public int getPremiumSmsPermission(String packageName) {
11814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        return mUsageMonitor.getPremiumSmsPermission(packageName);
11824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
11834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
11854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Sets the premium SMS permission for the specified package and save the value asynchronously
11864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * to persistent storage.
11874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to set permission
11884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
11894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
11904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
11914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
11924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public void setPremiumSmsPermission(String packageName, int permission) {
11934658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        mUsageMonitor.setPremiumSmsPermission(packageName, permission);
11940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the message along to the radio.
11980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
11990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the SMS message to send
12000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendSms(SmsTracker tracker);
12020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12048d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * Send the SMS via the PSTN network.
12058d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     *
12068d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     * @param tracker holds the Sms tracker ready to be sent
12078d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang     */
12088d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    protected abstract void sendSmsByPstn(SmsTracker tracker);
12098d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang
12108d8e8f45200d17b78d196d8cba389fd9c547ac11Cheuksan Wang    /**
12111260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * Retry the message along to the radio.
12121260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     *
12131260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     * @param tracker holds the SMS message to send
12141260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa     */
1215ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public void sendRetrySms(SmsTracker tracker) {
1216ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        // re-routing to ImsSMSDispatcher
1217ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1218ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            mImsSMSDispatcher.sendRetrySms(tracker);
1219ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1220ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null. Retry failed");
1221ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1222ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
12231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
12241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    /**
12250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the multi-part SMS based on multipart Sms tracker
12260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the multipart Sms tracker ready to be sent
12280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void sendMultipartSms(SmsTracker tracker) {
12300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<String> parts;
12310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> sentIntents;
12320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> deliveryIntents;
12330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        HashMap<String, Object> map = tracker.mData;
12350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String destinationAddress = (String) map.get("destination");
12370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String scAddress = (String) map.get("scaddress");
12380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        parts = (ArrayList<String>) map.get("parts");
12400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
12410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
12420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // check if in service
12440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int ss = mPhone.getServiceState().getState();
12451260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // if sms over IMS is not supported on data and voice is not available...
12461260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
12470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0, count = parts.size(); i < count; i++) {
12480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                PendingIntent sentIntent = null;
12490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (sentIntents != null && sentIntents.size() > i) {
12500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent = sentIntents.get(i);
12510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
12520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, sentIntent);
12530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
12540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
12550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1257b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents,
1258b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                null/*messageUri*/, null/*callingPkg*/);
12590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Keeps track of an SMS that has been sent to the RIL, until it has
12630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * successfully been sent, or we're done trying.
12640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final class SmsTracker {
12660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // fields need to be public for derived SmsDispatchers
12670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final HashMap<String, Object> mData;
12680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mRetryCount;
12691260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        public int mImsRetry; // nonzero indicates initial message was sent over Ims
12700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mMessageRef;
12716ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi        public boolean mExpectMore;
12721260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String mFormat;
12730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mSentIntent;
12750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mDeliveryIntent;
12760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12772029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        public final PackageInfo mAppInfo;
12780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final String mDestAddress;
12790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
128078d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal        public final SmsHeader mSmsHeader;
128178d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal
12820217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        private long mTimestamp = System.currentTimeMillis();
1283c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public Uri mMessageUri; // Uri of persisted message if we wrote one
1284c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1285c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        // Reference to states of a multipart message that this part belongs to
1286c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private AtomicInteger mUnsentPartCount;
1287c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        private AtomicBoolean mAnyPartFailed;
12884bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        // The full message content of a single part message
12894bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        // or a multipart message that this part belongs to
12904bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private String mFullMessageText;
12914bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen
12924bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private int mSubId;
12930217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
12941260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1295c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format,
129678d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal                AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
12974bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                SmsHeader smsHeader, boolean isExpectMore, String fullMessageText, int subId) {
12980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mData = data;
12990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mSentIntent = sentIntent;
13000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDeliveryIntent = deliveryIntent;
13010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mRetryCount = 0;
13022029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            mAppInfo = appInfo;
13030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDestAddress = destAddr;
13041260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mFormat = format;
13056ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi            mExpectMore = isExpectMore;
13061260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mImsRetry = 0;
13071260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            mMessageRef = 0;
1308c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mUnsentPartCount = unsentPartCount;
1309c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mAnyPartFailed = anyPartFailed;
1310c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            mMessageUri = messageUri;
131178d39a9fab86a26f4f39585af5cfe2a07c756fceShishir Agrawal            mSmsHeader = smsHeader;
13124bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            mFullMessageText = fullMessageText;
13134bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            mSubId = subId;
13140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /**
13170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * Returns whether this tracker holds a multi-part SMS.
13180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * @return true if the tracker holds a multi-part SMS; false otherwise
13190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
13200d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        boolean isMultipart() {
13210217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            return mData.containsKey("parts");
13220217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        }
13230217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun
13240217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        /**
13250217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         * Update the status of this message if we persisted it
13260217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun         */
13270217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun        public void updateSentMessageStatus(Context context, int status) {
1328c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri != null) {
13290217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                // If we wrote this message in writeSentMessage, update it now
13300217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                ContentValues values = new ContentValues(1);
13310217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                values.put(Sms.STATUS, status);
13320217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun                SqliteWrapper.update(context, context.getContentResolver(),
1333c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        mMessageUri, values, null, null);
1334c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1335c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1336c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1337c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
13384bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * Set the final state of a message: FAILED or SENT
1339c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1340c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
13414bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The final message type
1342c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param errorCode The error code
1343c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
13444bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private void updateMessageState(Context context, int messageType, int errorCode) {
1345c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mMessageUri == null) {
1346c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                return;
1347c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
13484bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentValues values = new ContentValues(2);
13494bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.TYPE, messageType);
1350c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            values.put(Sms.ERROR_CODE, errorCode);
1351c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final long identity = Binder.clearCallingIdentity();
1352c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            try {
1353c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
1354c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        null/*where*/, null/*selectionArgs*/) != 1) {
13554bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    Rlog.e(TAG, "Failed to move message to " + messageType);
1356c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1357c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } finally {
1358c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                Binder.restoreCallingIdentity(identity);
1359c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1360c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1361c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1362c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
13634bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * Persist a sent SMS if required
1364c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
13654bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param context
13664bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The folder to store (FAILED or SENT)
13674bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param errorCode The current error code for this SMS or SMS part
13684bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @return The telephony provider URI if stored
1369c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
13704bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) {
13714bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (!SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) {
13724bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return null;
13734bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
13744bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            Rlog.d(TAG, "Persist SMS into "
13754bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    + (messageType == Sms.MESSAGE_TYPE_FAILED ? "FAILED" : "SENT"));
13764bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentValues values = new ContentValues();
13774b09dff383ae7dfca595aeeea886a594a1947340Wink Saville            values.put(Sms.SUBSCRIPTION_ID, mSubId);
13784bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.ADDRESS, mDestAddress);
13794bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.BODY, mFullMessageText);
13804bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.DATE, System.currentTimeMillis()); // milliseconds
13814bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.SEEN, 1);
13824bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            values.put(Sms.READ, 1);
13834bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final String creator = mAppInfo != null ? mAppInfo.packageName : null;
13844bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (!TextUtils.isEmpty(creator)) {
13854bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.CREATOR, creator);
13864bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
13874bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (mDeliveryIntent != null) {
13884bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.STATUS, Telephony.Sms.STATUS_PENDING);
13894bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
13904bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (errorCode != 0) {
13914bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                values.put(Sms.ERROR_CODE, errorCode);
1392c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1393c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final long identity = Binder.clearCallingIdentity();
13944bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            final ContentResolver resolver = context.getContentResolver();
1395c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            try {
13964bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                final Uri uri =  resolver.insert(Telephony.Sms.Sent.CONTENT_URI, values);
13974bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                if (uri != null && messageType == Sms.MESSAGE_TYPE_FAILED) {
13984bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // Since we can't persist a message directly into FAILED box,
13994bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // we have to update the column after we persist it into SENT box.
14004bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // The gap between the state change is tiny so I would not expect
14014bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // it to cause any serious problem
14024bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    // TODO: we should add a "failed" URI for this in SmsProvider?
14034bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    final ContentValues updateValues = new ContentValues(1);
14044bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    updateValues.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
14054bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    resolver.update(uri, updateValues, null/*where*/, null/*selectionArgs*/);
1406c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
14074bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return uri;
14084bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            } catch (Exception e) {
14094bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
14104bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                return null;
1411c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            } finally {
1412c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                Binder.restoreCallingIdentity(identity);
1413c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1414c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1415c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1416c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
14174bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * Persist or update an SMS depending on if we send a new message or a stored message
14184bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         *
14194bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param context
14204bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param messageType The message folder for this SMS, FAILED or SENT
14214bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         * @param errorCode The current error code for this SMS or SMS part
14224bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen         */
14234bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        private void persistOrUpdateMessage(Context context, int messageType, int errorCode) {
14244bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            if (mMessageUri != null) {
14254bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                updateMessageState(context, messageType, errorCode);
14264bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            } else {
14274bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode);
14284bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            }
14294bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        }
14304bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen
14314bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen        /**
1432c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Handle a failure of a single part message or a part of a multipart message
1433c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1434c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1435c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param error The error to send back with
1436c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param errorCode
1437c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1438c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public void onFailed(Context context, int error, int errorCode) {
1439c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mAnyPartFailed != null) {
1440c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                mAnyPartFailed.set(true);
1441c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1442c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            // is single part or last part of multipart message
1443c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            boolean isSinglePartOrLastPart = true;
1444c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mUnsentPartCount != null) {
1445c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1446c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1447c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (isSinglePartOrLastPart) {
14484bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                persistOrUpdateMessage(context, Sms.MESSAGE_TYPE_FAILED, errorCode);
1449c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1450c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mSentIntent != null) {
1451c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                try {
1452fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    // Extra information to send with the sent intent
1453fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    Intent fillIn = new Intent();
1454fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    if (mMessageUri != null) {
1455fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        // Pass this to SMS apps so that they know where it is stored
1456fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra("uri", mMessageUri.toString());
1457fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    }
1458c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (errorCode != 0) {
1459c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        fillIn.putExtra("errorCode", errorCode);
1460c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1461c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1462c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        // Is multipart and last part
1463c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1464c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1465c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    mSentIntent.send(context, error, fillIn);
1466c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } catch (CanceledException ex) {
1467c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to send result");
1468c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
1469c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1470c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1471c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1472c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        /**
1473c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * Handle the sent of a single part message or a part of a multipart message
1474c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         *
1475c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         * @param context The Context
1476c99dab56e20222b28cbc6238645feac938f1c333Ye Wen         */
1477c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        public void onSent(Context context) {
1478c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            // is single part or last part of multipart message
1479c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            boolean isSinglePartOrLastPart = true;
1480c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mUnsentPartCount != null) {
1481c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
1482c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1483c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (isSinglePartOrLastPart) {
14844bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                int messageType = Sms.MESSAGE_TYPE_SENT;
1485c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                if (mAnyPartFailed != null && mAnyPartFailed.get()) {
14864bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                    messageType = Sms.MESSAGE_TYPE_FAILED;
1487c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
14884bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                persistOrUpdateMessage(context, messageType, 0/*errorCode*/);
1489c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1490c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (mSentIntent != null) {
1491c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                try {
1492fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    // Extra information to send with the sent intent
1493fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    Intent fillIn = new Intent();
1494fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    if (mMessageUri != null) {
1495fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        // Pass this to SMS apps so that they know where it is stored
1496fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra("uri", mMessageUri.toString());
1497fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    }
1498c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    if (mUnsentPartCount != null && isSinglePartOrLastPart) {
1499c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                        // Is multipart and last part
1500fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
1501c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    }
1502fce79caf5d7628cde43c5f0cd3d369673bc15212Ye Wen                    mSentIntent.send(context, Activity.RESULT_OK, fillIn);
1503c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                } catch (CanceledException ex) {
1504c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Rlog.e(TAG, "Failed to send result");
1505c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                }
15060217e2d6e60f7edd95407c7b385a627da9f1c1e3David Braun            }
15070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
15090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1510ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
1511c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount,
15126ad88a8a2caf739e78c8d5f7f50fc7fa84a07ca7Chaitanya Saggurthi            AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader,
15134bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            boolean isExpectMore, String fullMessageText) {
15141260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get calling app package name via UID from Binder call
15151260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageManager pm = mContext.getPackageManager();
15161260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
15171260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
15181260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Get package info via packagemanager
15191260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        PackageInfo appInfo = null;
15201260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        if (packageNames != null && packageNames.length > 0) {
15211260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            try {
15221260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // XXX this is lossy- apps can share a UID
15231260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
15241260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            } catch (PackageManager.NameNotFoundException e) {
15251260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa                // error will be logged in sendRawPdu
15261260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            }
15271260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        }
15281260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // Strip non-digits from destination phone number before checking for short codes
15291260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        // and before displaying the number to the user if confirmation is required.
15301260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
1531c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format,
15324bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                unsentPartCount, anyPartFailed, messageUri, smsHeader, isExpectMore,
15334bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                fullMessageText, getSubId());
1534c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1535c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1536c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
15374bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            PendingIntent deliveryIntent, String format, Uri messageUri, boolean isExpectMore,
15384bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen            String fullMessageText) {
1539c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/,
15404bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                null/*anyPartFailed*/, messageUri, null/*smsHeader*/, isExpectMore,
15414bd1dec4138ac11a91a8ec606a27fc4c5c63f14bYe Wen                fullMessageText);
15421260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
15431260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1544ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
15451260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            String text, SmsMessageBase.SubmitPduBase pdu) {
15461260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
15471260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
15481260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
15491260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("text", text);
15501260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
15511260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
15521260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
15531260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
15541260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1555ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
15561260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa            int destPort, byte[] data, SmsMessageBase.SubmitPduBase pdu) {
15571260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        HashMap<String, Object> map = new HashMap<String, Object>();
15581260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("destAddr", destAddr);
15591260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("scAddr", scAddr);
1560ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        map.put("destPort", destPort);
15611260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("data", data);
15621260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("smsc", pdu.encodedScAddress);
15631260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        map.put("pdu", pdu.encodedMessage);
15641260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa        return map;
15651260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa    }
15661260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
15670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
15680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dialog listener for SMS confirmation dialog.
15690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
15700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final class ConfirmDialogListener
15714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
15724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            CompoundButton.OnCheckedChangeListener {
15730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
15740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        private final SmsTracker mTracker;
15754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mPositiveButton;
15764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mNegativeButton;
15774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private boolean mRememberChoice;    // default is unchecked
157878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        private final TextView mRememberUndoInstruction;
15790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
158078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener(SmsTracker tracker, TextView textView) {
15810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mTracker = tracker;
158278df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt            mRememberUndoInstruction = textView;
15830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
15840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
15854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setPositiveButton(Button button) {
15864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mPositiveButton = button;
15874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
15884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
15894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setNegativeButton(Button button) {
15904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mNegativeButton = button;
15914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
15924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
15930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
15940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onClick(DialogInterface dialog, int which) {
15954658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Always set the SMS permission so that Settings will show a permission setting
15964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // for the app (it won't be shown until after the app tries to send to a short code).
15974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
15984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
15990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (which == DialogInterface.BUTTON_POSITIVE) {
1600ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "CONFIRM sending SMS");
16012029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1602634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_SENT_BY_USER,
1603ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1604ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 : mTracker.mAppInfo.applicationInfo.uid);
16050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker));
16064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
16074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
16084658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
16090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (which == DialogInterface.BUTTON_NEGATIVE) {
1610ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "DENY sending SMS");
16112029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
1612634a24f56f54b5d2911649288147c750b67c7ae4William Luh                EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
1613ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    mTracker.mAppInfo.applicationInfo == null ?
1614ec125af4306f1be2c829c3a1d7adbf9b8cd7e659William Luh                                    -1 :  mTracker.mAppInfo.applicationInfo.uid);
16150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
16164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
16174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
16184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
16190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
16204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            setPremiumSmsPermission(mTracker.mAppInfo.packageName, newSmsPermission);
16210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
16230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
16240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onCancel(DialogInterface dialog) {
1625ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "dialog dismissed: don't send SMS");
16260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
16270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
16284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
16294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        @Override
16304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1631ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "remember this choice: " + isChecked);
16324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mRememberChoice = isChecked;
16334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (isChecked) {
16344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
16354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
163678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
163778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.
163878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                            setText(R.string.sms_short_code_remember_undo_instruction);
163978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,32);
164078df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
16414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            } else {
16424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
16435d875796122cdd8a7004e8e3964b20b5c65a31a1Robert Greenwalt                mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
164478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
164578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setText("");
164678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,0);
164778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
16484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
16494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
16500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
16511260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1652ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public boolean isIms() {
1653ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1654ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.isIms();
1655ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1656ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1657ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return false;
1658ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1659ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
16601260f1c6c909f2940989b72afe1b91fd83845eaaSukanya Rajkhowa
1661ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    public String getImsSmsFormat() {
1662ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        if (mImsSMSDispatcher != null) {
1663ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return mImsSMSDispatcher.getImsSmsFormat();
1664ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        } else {
1665ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            Rlog.e(TAG, mImsSMSDispatcher + " is null");
1666ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa            return null;
1667ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa        }
1668ace9a749c5a2a5e07527f728b7331423d16c36cdSukanya Rajkhowa    }
1669c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1670b237a11044ed842d2865ff8c8716befb06b6ca25Wink Saville    protected Uri writeOutboxMessage(int subId, String address, String text,
1671b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            boolean requireDeliveryReport, String creator) {
1672b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        final ContentValues values = new ContentValues(8);
16734b09dff383ae7dfca595aeeea886a594a1947340Wink Saville        values.put(Telephony.Sms.SUBSCRIPTION_ID, subId);
1674c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.ADDRESS, address);
1675b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        values.put(Telephony.Sms.BODY, text);
1676c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.DATE, System.currentTimeMillis()); // milliseconds
1677c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.SEEN, 1);
1678c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        values.put(Telephony.Sms.READ, 1);
1679b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        if (!TextUtils.isEmpty(creator)) {
1680b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            values.put(Telephony.Sms.CREATOR, creator);
1681b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        }
1682c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        if (requireDeliveryReport) {
1683c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            values.put(Telephony.Sms.STATUS, Telephony.Sms.STATUS_PENDING);
1684c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1685c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final long identity = Binder.clearCallingIdentity();
1686c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        try {
1687c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            final Uri uri =  mContext.getContentResolver().insert(
1688c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                    Telephony.Sms.Outbox.CONTENT_URI, values);
1689c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return uri;
1690c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        } catch (Exception e) {
1691b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
1692c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            return null;
1693c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        } finally {
1694c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            Binder.restoreCallingIdentity(identity);
1695c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1696c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1697c99dab56e20222b28cbc6238645feac938f1c333Ye Wen
1698b237a11044ed842d2865ff8c8716befb06b6ca25Wink Saville    protected void moveToOutbox(int subId, Uri messageUri, String creator) {
1699b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        final ContentValues values = new ContentValues(4);
17004b09dff383ae7dfca595aeeea886a594a1947340Wink Saville        values.put(Telephony.Sms.SUBSCRIPTION_ID, subId);
1701b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        if (!TextUtils.isEmpty(creator)) {
1702b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            // Reset creator/sender
1703b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            values.put(Telephony.Sms.CREATOR, creator);
1704b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        }
1705b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        // Reset the timestamp
1706b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        values.put(Telephony.Sms.DATE, System.currentTimeMillis()); // milliseconds
1707b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        values.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_OUTBOX);
1708b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        final long identity = Binder.clearCallingIdentity();
1709b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        try {
1710b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            if (mContext.getContentResolver().update(messageUri, values,
1711b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                    null/*where*/, null/*selectionArgs*/) != 1) {
1712b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen                Rlog.e(TAG, "moveToOutbox: failed to update message " + messageUri);
1713b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            }
1714b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        } catch (Exception e) {
1715b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            Rlog.e(TAG, "moveToOutbox: Failed to update message", e);
1716b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        } finally {
1717b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen            Binder.restoreCallingIdentity(identity);
1718b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        }
1719b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    }
1720b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen
1721c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    private String getMultipartMessageText(ArrayList<String> parts) {
1722c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        final StringBuilder sb = new StringBuilder();
1723c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        for (String part : parts) {
1724c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            if (part != null) {
1725c99dab56e20222b28cbc6238645feac938f1c333Ye Wen                sb.append(part);
1726c99dab56e20222b28cbc6238645feac938f1c333Ye Wen            }
1727c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        }
1728c99dab56e20222b28cbc6238645feac938f1c333Ye Wen        return sb.toString();
1729c99dab56e20222b28cbc6238645feac938f1c333Ye Wen    }
1730b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen
17318215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang    protected String getCarrierAppPackageName() {
1732062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal        UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
17337f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal        if (card == null) {
17347f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal            return null;
17357f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal        }
17367f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal
1737934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero        List<String> carrierPackages = card.getCarrierPackageNamesForIntent(
17388215559cd1141ac90c478fd3df75e43c9d755c6cCheuksan Wang            mContext.getPackageManager(), new Intent(CarrierMessagingService.SERVICE_INTERFACE));
17397f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal        return (carrierPackages != null && carrierPackages.size() == 1) ?
17407f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal                carrierPackages.get(0) : null;
1741c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal    }
1742c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal
1743b237a11044ed842d2865ff8c8716befb06b6ca25Wink Saville    protected int getSubId() {
1744b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen        return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.mPhoneId);
1745b29851580bba4a13ddbf7a534d8b09295eb2c60fYe Wen    }
17460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
1747