SMSDispatcher.java revision 5a176f73dbb2bff2ca8b8f86af86a17be6863b87
10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2006 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
197fce994eb223105829becb6c26e3af7a9739752cDianne Hackbornimport android.Manifest;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.Activity;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.AlertDialog;
227fce994eb223105829becb6c26e3af7a9739752cDianne Hackbornimport android.app.AppOpsManager;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent;
240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent.CanceledException;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.BroadcastReceiver;
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ContentResolver;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ContentValues;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Context;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.DialogInterface;
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Intent;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.ApplicationInfo;
322029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.content.pm.PackageInfo;
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.pm.PackageManager;
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.Resources;
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.database.Cursor;
36ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.database.ContentObserver;
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.database.SQLException;
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.net.Uri;
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.AsyncResult;
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Binder;
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler;
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.PowerManager;
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.SystemProperties;
45ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport android.provider.Settings;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.provider.Telephony;
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.provider.Telephony.Sms.Intents;
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.PhoneNumberUtils;
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.ServiceState;
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.SmsCbMessage;
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.SmsMessage;
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.TelephonyManager;
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Html;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.text.Spanned;
552029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport android.util.EventLog;
56ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Savilleimport android.telephony.Rlog;
574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.LayoutInflater;
584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.view.View;
5978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwaltimport android.view.ViewGroup;
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.view.WindowManager;
614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.Button;
624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CheckBox;
634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.CompoundButton;
644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.widget.TextView;
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.R;
672029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condraimport com.android.internal.telephony.EventLogTags;
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.util.HexDump;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.ByteArrayOutputStream;
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Arrays;
74ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwaltimport java.util.concurrent.atomic.AtomicInteger;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap;
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Random;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic abstract class SMSDispatcher extends Handler {
86cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final String TAG = "SMSDispatcher";    // accessed from inner class
87cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    static final boolean DBG = false;
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Permission required to receive SMS and SMS-CB messages. */
917fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn    public static final String RECEIVE_SMS_PERMISSION = Manifest.permission.RECEIVE_SMS;
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
937fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn    /** Permission required to receive ETWS and CMAS emergency broadcasts.
947fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn     *  XXX this permission is declared in the Mms app...  wha?!? */
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static final String RECEIVE_EMERGENCY_BROADCAST_PERMISSION =
967fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn            Manifest.permission.RECEIVE_EMERGENCY_BROADCAST;
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Permission required to send SMS to short codes without user confirmation. */
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String SEND_SMS_NO_CONFIRMATION_PERMISSION =
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "android.permission.SEND_SMS_NO_CONFIRMATION";
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Query projection for checking for duplicate message segments. */
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String[] PDU_PROJECTION = new String[] {
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "pdu"
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Query projection for combining concatenated message segments. */
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String[] PDU_SEQUENCE_PORT_PROJECTION = new String[] {
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "pdu",
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "sequence",
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            "destination_port"
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int PDU_COLUMN = 0;
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SEQUENCE_COLUMN = 1;
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int DESTINATION_PORT_COLUMN = 2;
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
118ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_SIM = 1;
119ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_NETWORK = 2;
120ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static final int PREMIUM_RULE_USE_BOTH = 3;
121ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final AtomicInteger mPremiumSmsRule = new AtomicInteger(PREMIUM_RULE_USE_SIM);
122ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private final SettingsObserver mSettingsObserver;
123ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** New SMS received. */
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int EVENT_NEW_SMS = 1;
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** SMS send complete. */
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final int EVENT_SEND_SMS_COMPLETE = 2;
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Retry sending a previously failed SMS message */
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_RETRY = 3;
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for sending a large number of messages. */
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_LIMIT_REACHED_CONFIRMATION = 4;
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Send the user confirmed SMS */
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_SEND_CONFIRMED_SMS = 5;  // accessed from inner class
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Don't send SMS (user did not confirm). */
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    static final int EVENT_STOP_SENDING = 7;        // accessed from inner class
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8;
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Confirmation required for third-party apps sending to an SMS short code. */
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9;
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final Phone mPhone;
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final Context mContext;
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ContentResolver mResolver;
15122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville    protected final CommandsInterface mCi;
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final SmsStorageMonitor mStorageMonitor;
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final TelephonyManager mTelephonyManager;
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final WapPushOverSms mWapPush;
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Maximum number of times to retry sending a failed SMS. */
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MAX_SEND_RETRIES = 3;
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Delay before next send attempt on a failed SMS, in milliseconds. */
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SEND_RETRY_DELAY = 2000;
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** single part SMS */
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int SINGLE_PART_SMS = 1;
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Message sending queue limit */
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int MO_MSG_QUEUE_LIMIT = 5;
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Message reference for a CONCATENATED_8_BIT_REFERENCE or
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * CONCATENATED_16_BIT_REFERENCE message set.  Should be
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * incremented for each set of concatenated messages.
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Static field shared by all dispatcher objects.
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int sConcatenatedRef = new Random().nextInt(256);
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Outgoing message counter. Shared by all dispatchers. */
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final SmsUsageMonitor mUsageMonitor;
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Number of outgoing SmsTrackers waiting for user confirmation. */
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mPendingTrackerCount;
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Wake lock to ensure device stays awake while dispatching the SMS intent. */
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private PowerManager.WakeLock mWakeLock;
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Hold the wake lock for 5 seconds, which should be enough time for
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * any receiver(s) to grab its own wake lock.
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int WAKE_LOCK_TIMEOUT = 5000;
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* Flags indicating whether the current device allows sms service */
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsCapable = true;
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsReceiveDisabled;
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected boolean mSmsSendDisabled;
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected int mRemainingMessages = -1;
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static int getNextConcatenatedRef() {
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sConcatenatedRef += 1;
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return sConcatenatedRef;
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SMS dispatcher.
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param phone the Phone to use
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param storageMonitor the SmsStorageMonitor to use
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param usageMonitor the SmsUsageMonitor to use
2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected SMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsUsageMonitor usageMonitor) {
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhone = phone;
2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mWapPush = new WapPushOverSms(phone, this);
2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mContext = phone.getContext();
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mResolver = mContext.getContentResolver();
21522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi = phone.mCi;
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mStorageMonitor = storageMonitor;
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mUsageMonitor = usageMonitor;
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
219ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mSettingsObserver = new SettingsObserver(this, mPremiumSmsRule, mContext);
220ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
221ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                Settings.Global.SMS_SHORT_CODE_RULE), false, mSettingsObserver);
2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        createWakelock();
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsCapable = mContext.getResources().getBoolean(
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                com.android.internal.R.bool.config_sms_capable);
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsReceiveDisabled = !SystemProperties.getBoolean(
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                TelephonyProperties.PROPERTY_SMS_RECEIVE, mSmsCapable);
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mSmsSendDisabled = !SystemProperties.getBoolean(
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                                TelephonyProperties.PROPERTY_SMS_SEND, mSmsCapable);
231ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + " mSmsReceiveDisabled=" + mSmsReceiveDisabled
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + " mSmsSendDisabled=" + mSmsSendDisabled);
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
236ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    /**
237ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     * Observe the secure setting for updated premium sms determination rules
238ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt     */
239ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    private static class SettingsObserver extends ContentObserver {
240ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final AtomicInteger mPremiumSmsRule;
241ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        private final Context mContext;
242ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        SettingsObserver(Handler handler, AtomicInteger premiumSmsRule, Context context) {
243ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            super(handler);
244ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule = premiumSmsRule;
245ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mContext = context;
246ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            onChange(false); // load initial value;
247ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
248ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
249ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        @Override
250ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        public void onChange(boolean selfChange) {
251ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            mPremiumSmsRule.set(Settings.Global.getInt(mContext.getContentResolver(),
252ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    Settings.Global.SMS_SHORT_CODE_RULE, PREMIUM_RULE_USE_SIM));
253ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt        }
254ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt    }
255ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Unregister for incoming SMS events. */
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public abstract void dispose();
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The format of the message PDU in the associated broadcast intent.
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Note: All applications which handle incoming SMS messages by processing the
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * into the new methods in {@link android.telephony.SmsMessage} which take an
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * extra format parameter. This is required in order to correctly decode the PDU on
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * devices which require support for both 3GPP and 3GPP2 formats at the same time,
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * such as CDMA/LTE devices and GSM/CDMA world phones.
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the format of the message PDU
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract String getFormat();
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void finalize() {
277ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        Rlog.d(TAG, "SMSDispatcher finalized");
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /* TODO: Need to figure out how to keep track of status report routing in a
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       persistent manner. If the phone process restarts (reboot or crash),
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       we will lose this list and any status reports that come in after
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       will be dropped.
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Sent messages awaiting a delivery status report. */
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles events coming from the phone stack. Overridden from handler.
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg the message to handle
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AsyncResult ar;
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msg.what) {
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_NEW_SMS:
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // A new SMS has been received by the device
301cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "New SMS Message Received");
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsMessage sms;
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception != null) {
308ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception);
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sms = (SmsMessage) ar.result;
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int result = dispatchMessage(sms.mWrappedSmsMessage);
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (result != Activity.RESULT_OK) {
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    // RESULT_OK means that message was broadcast for app(s) to handle.
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    // Any other result, we should ack here.
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    boolean handled = (result == Intents.RESULT_SMS_HANDLED);
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    notifyAndAcknowledgeLastIncomingSms(handled, result, null);
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (RuntimeException ex) {
322ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.e(TAG, "Exception dispatching message", ex);
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                notifyAndAcknowledgeLastIncomingSms(false, Intents.RESULT_SMS_GENERIC_ERROR, null);
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_SMS_COMPLETE:
3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // An outbound SMS has been successfully transferred, or failed.
3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleSendComplete((AsyncResult) msg.obj);
3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_RETRY:
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendSms((SmsTracker) msg.obj);
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_LIMIT_REACHED_CONFIRMATION:
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleReachSentLimit((SmsTracker)(msg.obj));
3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE:
3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(false, (SmsTracker)(msg.obj));
3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE:
3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleConfirmShortCode(true, (SmsTracker)(msg.obj));
3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_SEND_CONFIRMED_SMS:
3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.isMultipart()) {
3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMultipartSms(tracker);
3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_STOP_SENDING:
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        {
3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = (SmsTracker) msg.obj;
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.mSentIntent != null) {
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {
368ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "failed to send RESULT_ERROR_LIMIT_EXCEEDED");
3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPendingTrackerCount--;
3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void createWakelock() {
3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher");
3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mWakeLock.setReferenceCounted(true);
3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Grabs a wake lock and sends intent as an ordered broadcast.
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * The resultReceiver will check for errors and ACK/NACK back
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * to the RIL.
3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param intent intent to broadcast
3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param permission Receivers are required to have this permission
3907fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn     * @param appOp App op that is being performed when dispatching to a receiver
3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
3927fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn    public void dispatch(Intent intent, String permission, int appOp) {
3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // receivers time to take their own wake locks.
3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
3967fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn        mContext.sendOrderedBroadcast(intent, permission, appOp, mResultReceiver,
3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                this, Activity.RESULT_OK, null, null);
3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
401b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     * Grabs a wake lock and sends intent as an ordered broadcast.
402b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     * Used for setting a custom result receiver for CDMA SCPD.
403b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     *
404b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     * @param intent intent to broadcast
405b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     * @param permission Receivers are required to have this permission
4067fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn     * @param appOp App op that is being performed when dispatching to a receiver
407b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     * @param resultReceiver the result receiver to use
408b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby     */
4097fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn    public void dispatch(Intent intent, String permission, int appOp,
4107fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn            BroadcastReceiver resultReceiver) {
411b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
412b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        // receivers time to take their own wake locks.
413b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
4147fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn        mContext.sendOrderedBroadcast(intent, permission, appOp, resultReceiver,
415b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                this, Activity.RESULT_OK, null, null);
416b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    }
417b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
418b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    /**
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Called when SMS send completes. Broadcasts a sentIntent on success.
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * On failure, either sets up retries or broadcasts a sentIntent with
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the failure in the result code.
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ar AsyncResult passed into the message handler.  ar.result should
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           an SmsResponse instance if send was successful.  ar.userObj
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *           should be an SmsTracker instance.
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleSendComplete(AsyncResult ar) {
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsTracker tracker = (SmsTracker) ar.userObj;
4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PendingIntent sentIntent = tracker.mSentIntent;
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
431454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        if (ar.result != null) {
4325a176f73dbb2bff2ca8b8f86af86a17be6863b87Wink Saville            tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
433454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        } else {
434454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks            Rlog.d(TAG, "SmsResponse was null");
435454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks        }
436454c5783e7695feec276325920550b2d4dcc3e16Rika Brooks
4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (ar.exception == null) {
438cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);
4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (tracker.mDeliveryIntent != null) {
4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Expecting a status report.  Add it to the list.
4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryPendingList.add(tracker);
4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (mRemainingMessages > -1) {
4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        mRemainingMessages--;
4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (mRemainingMessages == 0) {
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        Intent sendNext = new Intent();
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        sendNext.putExtra(SEND_NEXT_MSG_EXTRA, true);
4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        sentIntent.send(mContext, Activity.RESULT_OK, sendNext);
4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    } else {
4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        sentIntent.send(Activity.RESULT_OK);
4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
461cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (DBG) Rlog.d(TAG, "SMS send failed");
4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ss != ServiceState.STATE_IN_SERVICE) {
4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, tracker.mSentIntent);
4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if ((((CommandException)(ar.exception)).getCommandError()
4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    == CommandException.Error.SMS_FAIL_RETRY) &&
4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                   tracker.mRetryCount < MAX_SEND_RETRIES) {
4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Retry after a delay if needed.
4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // TODO: According to TS 23.040, 9.2.3.6, we should resend
4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       with the same TP-MR as the failed message, and
4730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       TP-RD set to 1.  However, we don't have a means of
4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       knowing the MR for the failed message (EF_SMSstatus
4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       may or may not have the MR corresponding to this
4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       message, depending on the failure).  Also, in some
4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                //       implementations this retry is handled by the baseband.
4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tracker.mRetryCount++;
4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (tracker.mSentIntent != null) {
4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int error = RESULT_ERROR_GENERIC_FAILURE;
4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (((CommandException)(ar.exception)).getCommandError()
4850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        == CommandException.Error.FDN_CHECK_FAILURE) {
4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    error = RESULT_ERROR_FDN_CHECK_FAILURE;
4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Done retrying; return an error to the app.
4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Intent fillIn = new Intent();
4910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (ar.result != null) {
49222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville                        fillIn.putExtra("errorCode", ((SmsResponse)ar.result).mErrorCode);
4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (mRemainingMessages > -1) {
4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        mRemainingMessages--;
4960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (mRemainingMessages == 0) {
4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    tracker.mSentIntent.send(mContext, error, fillIn);
5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handles outbound message when the phone is not in service.
5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
5110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param ss     Current service state.  Valid values are:
5120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  OUT_OF_SERVICE
5130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  EMERGENCY_ONLY
5140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *                  POWER_OFF
5150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent the PendingIntent to send the error to
5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
5170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static void handleNotInService(int ss, PendingIntent sentIntent) {
5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (sentIntent != null) {
5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ss == ServiceState.STATE_POWER_OFF) {
5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_RADIO_OFF);
5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NO_SERVICE);
5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CanceledException ex) {}
5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dispatches an incoming SMS messages.
5310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
5320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sms the incoming message from the phone
533cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville     * @return a result code from {@link android.provider.Telephony.Sms.Intents}, or
5340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *         {@link Activity#RESULT_OK} if the message has been broadcast
5350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *         to applications
5360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
5370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public abstract int dispatchMessage(SmsMessageBase sms);
5380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
5400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dispatch a normal incoming SMS. This is called from the format-specific
5410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * {@link #dispatchMessage(SmsMessageBase)} if no format-specific handling is required.
5420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
5430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sms
544cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville     * @return {@link Activity#RESULT_OK} on success
5450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
5460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected int dispatchNormalMessage(SmsMessageBase sms) {
5470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsHeader smsHeader = sms.getUserDataHeader();
5480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // See if message is partial or port addressed.
5500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((smsHeader == null) || (smsHeader.concatRef == null)) {
5510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Message is not partial (not part of concatenated sequence).
5520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[][] pdus = new byte[1][];
5530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            pdus[0] = sms.getPdu();
5540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (smsHeader != null && smsHeader.portAddrs != null) {
5560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
5570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    // GSM-style WAP indication
5580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    return mWapPush.dispatchWapPdu(sms.getUserData());
5590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } else {
5600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    // The message was sent to a port, so concoct a URI for it.
5610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
5620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
5630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
5640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Normal short and non-port-addressed message, dispatch it.
5650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                dispatchPdus(pdus);
5660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Activity.RESULT_OK;
5680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
5690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Process the message part.
5700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
5710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;
5720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return processMessagePart(sms.getPdu(), sms.getOriginatingAddress(),
5730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    concatRef.refNumber, concatRef.seqNumber, concatRef.msgCount,
5740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sms.getTimestampMillis(), (portAddrs != null ? portAddrs.destPort : -1), false);
5750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
5790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * If this is the last part send the parts out to the application, otherwise
5800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the part is stored for later processing. Handles both 3GPP concatenated messages
5810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * as well as 3GPP2 format WAP push messages processed by
582cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville     * com.android.internal.telephony.cdma.CdmaSMSDispatcher#processCdmaWapPdu.
5830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
5840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param pdu the message PDU, or the datagram portion of a CDMA WDP datagram segment
5850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param address the originating address
5860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param referenceNumber distinguishes concatenated messages from the same sender
5870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sequenceNumber the order of this segment in the message
5880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *          (starting at 0 for CDMA WDP datagrams and 1 for concatenated messages).
5890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param messageCount the number of segments in the message
5900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param timestamp the service center timestamp in millis
5910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destPort the destination port for the message, or -1 for no destination port
5920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param isCdmaWapPush true if pdu is a CDMA WDP datagram segment and not an SM PDU
5930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
594cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville     * @return a result code from {@link android.provider.Telephony.Sms.Intents}, or
5950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *         {@link Activity#RESULT_OK} if the message has been broadcast
5960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *         to applications
5970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
5980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected int processMessagePart(byte[] pdu, String address, int referenceNumber,
5990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int sequenceNumber, int messageCount, long timestamp, int destPort,
6000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean isCdmaWapPush) {
6010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[][] pdus = null;
6020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Cursor cursor = null;
6030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
6040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // used by several query selection arguments
6050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String refNumber = Integer.toString(referenceNumber);
6060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String seqNumber = Integer.toString(sequenceNumber);
6070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Check for duplicate message segment
6090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            cursor = mResolver.query(mRawUri, PDU_PROJECTION,
6100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    "address=? AND reference_number=? AND sequence=?",
6110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    new String[] {address, refNumber, seqNumber}, null);
6120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // moveToNext() returns false if no duplicates were found
6140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (cursor.moveToNext()) {
615ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.w(TAG, "Discarding duplicate message segment from address=" + address
6160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        + " refNumber=" + refNumber + " seqNumber=" + seqNumber);
6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                String oldPduString = cursor.getString(PDU_COLUMN);
6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString);
6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (!Arrays.equals(oldPdu, pdu)) {
620ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Warning: dup message segment PDU of length " + pdu.length
6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            + " is different from existing PDU of length " + oldPdu.length);
6220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return Intents.RESULT_SMS_HANDLED;
6240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            cursor.close();
6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // not a dup, query for all other segments of this concatenated message
6280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String where = "address=? AND reference_number=?";
6290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String[] whereArgs = new String[] {address, refNumber};
6300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            cursor = mResolver.query(mRawUri, PDU_SEQUENCE_PORT_PROJECTION, where, whereArgs, null);
6310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int cursorCount = cursor.getCount();
6330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (cursorCount != messageCount - 1) {
6340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // We don't have all the parts yet, store this one away
6350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ContentValues values = new ContentValues();
6360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                values.put("date", timestamp);
6370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                values.put("pdu", HexDump.toHexString(pdu));
6380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                values.put("address", address);
6390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                values.put("reference_number", referenceNumber);
6400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                values.put("count", messageCount);
6410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                values.put("sequence", sequenceNumber);
6420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (destPort != -1) {
6430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    values.put("destination_port", destPort);
6440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mResolver.insert(mRawUri, values);
6460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return Intents.RESULT_SMS_HANDLED;
6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // All the parts are in place, deal with them
6500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            pdus = new byte[messageCount][];
6510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0; i < cursorCount; i++) {
6520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                cursor.moveToNext();
6530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int cursorSequence = cursor.getInt(SEQUENCE_COLUMN);
6540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // GSM sequence numbers start at 1; CDMA WDP datagram sequence numbers start at 0
6550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (!isCdmaWapPush) {
6560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    cursorSequence--;
6570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                pdus[cursorSequence] = HexDump.hexStringToByteArray(
6590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        cursor.getString(PDU_COLUMN));
6600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Read the destination port from the first segment (needed for CDMA WAP PDU).
6620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // It's not a bad idea to prefer the port from the first segment for 3GPP as well.
6630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (cursorSequence == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) {
6640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    destPort = cursor.getInt(DESTINATION_PORT_COLUMN);
6650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // This one isn't in the DB, so add it
6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // GSM sequence numbers start at 1; CDMA WDP datagram sequence numbers start at 0
6690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (isCdmaWapPush) {
6700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                pdus[sequenceNumber] = pdu;
6710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
6720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                pdus[sequenceNumber - 1] = pdu;
6730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Remove the parts from the database
6760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mResolver.delete(mRawUri, where, whereArgs);
6770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (SQLException e) {
678ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't access multipart SMS database", e);
6790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_GENERIC_ERROR;
6800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } finally {
6810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (cursor != null) cursor.close();
6820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Special handling for CDMA WDP datagrams
6850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isCdmaWapPush) {
6860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Build up the data stream
6870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ByteArrayOutputStream output = new ByteArrayOutputStream();
6880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0; i < messageCount; i++) {
6890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // reassemble the (WSP-)pdu
6900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                output.write(pdus[i], 0, pdus[i].length);
6910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
6920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] datagram = output.toByteArray();
6930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Dispatch the PDU to applications
6950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (destPort == SmsHeader.PORT_WAP_PUSH) {
6960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Handle the PUSH
6970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return mWapPush.dispatchWapPdu(datagram);
6980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
6990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                pdus = new byte[1][];
7000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                pdus[0] = datagram;
7010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // The messages were sent to any other WAP port
7020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                dispatchPortAddressedPdus(pdus, destPort);
7030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return Activity.RESULT_OK;
7040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Dispatch the PDUs to applications
7080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (destPort != -1) {
7090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (destPort == SmsHeader.PORT_WAP_PUSH) {
7100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Build up the data stream
7110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                ByteArrayOutputStream output = new ByteArrayOutputStream();
7120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                for (int i = 0; i < messageCount; i++) {
7130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    SmsMessage msg = SmsMessage.createFromPdu(pdus[i], getFormat());
7140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    byte[] data = msg.getUserData();
7150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    output.write(data, 0, data.length);
7160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
7170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Handle the PUSH
7180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return mWapPush.dispatchWapPdu(output.toByteArray());
7190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
7200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // The messages were sent to a port, so concoct a URI for it
7210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                dispatchPortAddressedPdus(pdus, destPort);
7220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
7230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
7240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // The messages were not sent to a port
7250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            dispatchPdus(pdus);
7260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
7270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return Activity.RESULT_OK;
7280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dispatches standard PDUs to interested applications
7320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param pdus The raw PDUs making up the message
7340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void dispatchPdus(byte[][] pdus) {
7360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
7370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        intent.putExtra("pdus", pdus);
7380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        intent.putExtra("format", getFormat());
7397fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn        dispatch(intent, RECEIVE_SMS_PERMISSION, AppOpsManager.OP_RECEIVE_SMS);
7400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dispatches port addressed PDUs to interested applications
7440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param pdus The raw PDUs making up the message
7460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param port The destination port of the messages
7470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void dispatchPortAddressedPdus(byte[][] pdus, int port) {
7490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Uri uri = Uri.parse("sms://localhost:" + port);
7500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri);
7510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        intent.putExtra("pdus", pdus);
7520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        intent.putExtra("format", getFormat());
7537fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn        dispatch(intent, RECEIVE_SMS_PERMISSION, AppOpsManager.OP_RECEIVE_SMS);
7540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
7550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a data based SMS to a specific application port.
7580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
7600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
7610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the current default SMSC
7620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destPort the port to deliver the message to
7630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data the body of the message to send
7640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
7650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
7660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
7670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
7680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
7690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
7700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
7710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
7720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
7730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
7740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
7750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
7760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
7770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
7780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
7790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
7800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
7810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
7820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendData(String destAddr, String scAddr, int destPort,
7830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent);
7840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
7850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
7860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a text based SMS.
7870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
7880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @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 text the body of the message to send
7920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>PendingIntent</code> is
7930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
7940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
7950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:<br>
7960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
7970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
7980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code><br>
7990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code><br>.
8000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
8010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  the extra "errorCode" containing a radio technology specific value,
8020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  generally only useful for troubleshooting.<br>
8030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
8040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
8050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
8060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
8070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
8080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
8090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendText(String destAddr, String scAddr,
8110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String text, PendingIntent sentIntent, PendingIntent deliveryIntent);
8120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Calculate the number of septets needed to encode the message.
8150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
8160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param messageBody the message to encode
8170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param use7bitOnly ignore (but still count) illegal characters if true
8180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return TextEncodingDetails
8190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract TextEncodingDetails calculateLength(CharSequence messageBody,
8210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean use7bitOnly);
8220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
8240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a multi-part text based SMS.
8250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
8260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the address to send the message to
8270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddr is the service center address or null to use
8280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   the current default SMSC
8290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param parts an <code>ArrayList</code> of strings that, in order,
8300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   comprise the original message
8310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntents if not null, an <code>ArrayList</code> of
8320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
8330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been sent.
8340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   The result code will be <code>Activity.RESULT_OK<code> for success,
8350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   or one of these errors:
8360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
8370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_RADIO_OFF</code>
8380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NULL_PDU</code>
8390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>RESULT_ERROR_NO_SERVICE</code>.
8400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
8410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
8420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
8430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntents if not null, an <code>ArrayList</code> of
8440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   <code>PendingIntent</code>s (one for each message part) that is
8450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   broadcast when the corresponding message part has been delivered
8460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   to the recipient.  The raw pdu of the status report is in the
8470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *   extended data ("pdu").
8480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
8490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendMultipartText(String destAddr, String scAddr,
8500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
8510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<PendingIntent> deliveryIntents) {
8520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int refNumber = getNextConcatenatedRef() & 0x00FF;
8540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgCount = parts.size();
8550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int encoding = SmsConstants.ENCODING_UNKNOWN;
8560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mRemainingMessages = msgCount;
8580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
8600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
8610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            TextEncodingDetails details = calculateLength(parts.get(i), false);
8620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding != details.codeUnitSize
8630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    && (encoding == SmsConstants.ENCODING_UNKNOWN
8640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            || encoding == SmsConstants.ENCODING_7BIT)) {
8650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                encoding = details.codeUnitSize;
8660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            encodingForParts[i] = details;
8680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
8690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < msgCount; i++) {
8710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
8720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.refNumber = refNumber;
8730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.seqNumber = i + 1;  // 1-based sequence
8740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.msgCount = msgCount;
8750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // TODO: We currently set this to true since our messaging app will never
8760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // send more than 255 parts (it converts the message to MMS well before that).
8770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // However, we should support 3rd party messaging apps that might need 16-bit
8780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // references
8790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Note:  It's not sufficient to just flip this bit to true; it will have
8800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // ripple effects (several calculations assume 8-bit ref).
8810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            concatRef.isEightBits = true;
8820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsHeader smsHeader = new SmsHeader();
8830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsHeader.concatRef = concatRef;
8840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Set the national language tables for 3GPP 7-bit encoding, if enabled.
8860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (encoding == SmsConstants.ENCODING_7BIT) {
8870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageTable = encodingForParts[i].languageTable;
8880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
8890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent = null;
8920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntents != null && sentIntents.size() > i) {
8930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sentIntent = sentIntents.get(i);
8940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
8950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
8960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent deliveryIntent = null;
8970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (deliveryIntents != null && deliveryIntents.size() > i) {
8980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryIntent = deliveryIntents.get(i);
8990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding,
9020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent, deliveryIntent, (i == (msgCount - 1)));
9030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
9060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Create a new SubmitPdu and send it.
9090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendNewSubmitPdu(String destinationAddress, String scAddress,
9110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String message, SmsHeader smsHeader, int encoding,
9120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart);
9130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
9150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send a SMS
9160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
9170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param smsc the SMSC to send the message through, or NULL for the
9180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  default SMSC
9190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param pdu the raw PDU to send
9200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sentIntent if not NULL this <code>Intent</code> is
9210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is successfully sent, or failed.
9220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The result code will be <code>Activity.RESULT_OK<code> for success,
9230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  or one of these errors:
9240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
9250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_RADIO_OFF</code>
9260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NULL_PDU</code>
9270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  <code>RESULT_ERROR_NO_SERVICE</code>.
9280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  The per-application based SMS control checks sentIntent. If sentIntent
9290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  is NULL the caller will be checked against all unknown applications,
9300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  which cause smaller number of SMS to be sent in checking period.
9310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param deliveryIntent if not NULL this <code>Intent</code> is
9320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  broadcast when the message is delivered to the recipient.  The
9330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  raw pdu of the status report is in the extended data ("pdu").
9340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param destAddr the destination phone number (for short code confirmation)
9350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
9360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
9370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent deliveryIntent, String destAddr) {
9380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mSmsSendDisabled) {
9390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
9400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
9410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NO_SERVICE);
9420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
9430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
944ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "Device does not support sending sms.");
9450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pdu == null) {
9490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
9500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
9510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_NULL_PDU);
9520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
9530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        HashMap<String, Object> map = new HashMap<String, Object>();
9580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        map.put("smsc", smsc);
9590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        map.put("pdu", pdu);
9600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Get calling app package name via UID from Binder call
9620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
9630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
9640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (packageNames == null || packageNames.length == 0) {
9660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Refuse to send SMS if we can't get the calling package name.
967ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");
9680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
9690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
9700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
9710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {
972ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "failed to send error result");
9730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
9740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
9750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
9760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
9770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9782029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        // Get package info via packagemanager
9792029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        PackageInfo appInfo = null;
9802029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        try {
9812029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            // XXX this is lossy- apps can share a UID
9822029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
9832029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        } catch (PackageManager.NameNotFoundException e) {
984ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
9852029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            if (sentIntent != null) {
9862029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                try {
9872029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                    sentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
9882029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                } catch (CanceledException ex) {
989ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "failed to send error result");
9902029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                }
9912029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            }
9922029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            return;
9932029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        }
9940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
9950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Strip non-digits from destination phone number before checking for short codes
9960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // and before displaying the number to the user if confirmation is required.
9972029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        SmsTracker tracker = new SmsTracker(map, sentIntent, deliveryIntent, appInfo,
9980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                PhoneNumberUtils.extractNetworkPortion(destAddr));
9990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // checkDestination() returns true if the destination is not a premium short code or the
10010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // sending app is approved to send to short codes. Otherwise, a message is sent to our
10020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // handler with the SmsTracker to request user confirmation before sending.
10030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (checkDestination(tracker)) {
10040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // check for excessive outgoing SMS usage by this app
10052029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
10060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
10070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
10080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int ss = mPhone.getServiceState().getState();
10110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ss != ServiceState.STATE_IN_SERVICE) {
10130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, tracker.mSentIntent);
10140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
10150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSms(tracker);
10160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Check if destination is a potential premium short code and sender is not pre-approved to
10220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * send to short codes.
10230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
10240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the tracker for the SMS to send
10250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the destination is approved; false if user confirmation event was sent
10260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    boolean checkDestination(SmsTracker tracker) {
10280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION_PERMISSION)
10290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                == PackageManager.PERMISSION_GRANTED) {
10300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;            // app is pre-approved to send to short codes
10310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
1032ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int rule = mPremiumSmsRule.get();
1033ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            int smsCategory = SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
1034ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_SIM || rule == PREMIUM_RULE_USE_BOTH) {
1035ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String simCountryIso = mTelephonyManager.getSimCountryIso();
1036ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (simCountryIso == null || simCountryIso.length() != 2) {
1037ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get SIM country Iso: trying network country Iso");
1038ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    simCountryIso = mTelephonyManager.getNetworkCountryIso();
1039ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
1040ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1041ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                smsCategory = mUsageMonitor.checkDestination(tracker.mDestAddress, simCountryIso);
1042ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            }
1043ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (rule == PREMIUM_RULE_USE_NETWORK || rule == PREMIUM_RULE_USE_BOTH) {
1044ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                String networkCountryIso = mTelephonyManager.getNetworkCountryIso();
1045ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                if (networkCountryIso == null || networkCountryIso.length() != 2) {
1046ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "Can't get Network country Iso: trying SIM country Iso");
1047ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    networkCountryIso = mTelephonyManager.getSimCountryIso();
1048ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                }
1049ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt
1050cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville                smsCategory = SmsUsageMonitor.mergeShortCodeCategories(smsCategory,
1051ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                        mUsageMonitor.checkDestination(tracker.mDestAddress, networkCountryIso));
10520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1054ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt            if (smsCategory == SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE
1055ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE
1056ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    || smsCategory == SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE) {
10574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                return true;    // not a premium short code
10584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
10594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
10604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Wait for user confirmation unless the user has set permission to always allow/deny
10614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int premiumSmsPermission = mUsageMonitor.getPremiumSmsPermission(
10624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    tracker.mAppInfo.packageName);
10634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
10644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                // First time trying to send to premium SMS.
10654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
10664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
10670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            switch (premiumSmsPermission) {
10694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW:
1070ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.d(TAG, "User approved this app to send to premium SMS");
10714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return true;
10720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
1074ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.w(TAG, "User denied this app from sending to premium SMS");
10754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(EVENT_STOP_SENDING, tracker));
10764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // reject this message
10774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
10784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
10790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                default:
10804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    int event;
1081ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt                    if (smsCategory == SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE) {
10824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE;
10834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    } else {
10844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                        event = EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE;
10854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    }
10864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    sendMessage(obtainMessage(event, tracker));
10874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    return false;   // wait for user confirmation
10880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
10890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
10900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
10910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
10920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
10930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Deny sending an SMS if the outgoing queue limit is reached. Used when the message
10940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * must be confirmed by the user due to excessive usage or potential premium SMS detected.
10950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the message to send
10960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the message was denied; false to continue with send confirmation
10970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
10980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean denyIfQueueLimitReached(SmsTracker tracker) {
10990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mPendingTrackerCount >= MO_MSG_QUEUE_LIMIT) {
11000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Deny sending message when the queue limit is reached.
11010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
1102a13eb8b86f22b0efcfb888e2491b007d3424ddddRekha Kumar                if (tracker.mSentIntent != null) {
1103a13eb8b86f22b0efcfb888e2491b007d3424ddddRekha Kumar                    tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
1104a13eb8b86f22b0efcfb888e2491b007d3424ddddRekha Kumar                }
11050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (CanceledException ex) {
1106ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
11070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
11080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;
11090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPendingTrackerCount++;
11110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return false;
11120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns the label for the specified app package name.
11160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param appPackage the package name of the app requesting to send an SMS
11170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the label for the specified app, or the package name if getApplicationInfo() fails
11180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private CharSequence getAppLabel(String appPackage) {
11200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PackageManager pm = mContext.getPackageManager();
11210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
11220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ApplicationInfo appInfo = pm.getApplicationInfo(appPackage, 0);
11230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appInfo.loadLabel(pm);
11240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (PackageManager.NameNotFoundException e) {
1125ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
11260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return appPackage;  // fall back to package name if we can't get app label
11270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert when SMS needs confirmation due to excessive usage.
11320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker an SmsTracker for the current message.
11330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleReachSentLimit(SmsTracker tracker) {
11350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
11360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
11370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11392029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
11400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
11410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
11420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
114378df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null);
11440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
11460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setTitle(R.string.sms_control_title)
11470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setIcon(R.drawable.stat_sys_warning)
11480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setMessage(messageText)
11490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_control_yes), listener)
11500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_control_no), listener)
11510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
11520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
11530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
11550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
11560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
11570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
11590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Post an alert for user confirmation when sending to a potential short code.
11600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param isPremium true if the destination is known to be a premium short code
11610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker the SmsTracker for the current message.
11620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
11630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) {
11640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (denyIfQueueLimitReached(tracker)) {
11650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;     // queue limit reached; error was returned to caller
11660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        int detailsId;
11690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (isPremium) {
11704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_premium_short_code_details;
11710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
11724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            detailsId = R.string.sms_short_code_details;
11730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
11740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11752029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName);
11760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Resources r = Resources.getSystem();
11774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
11784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                appLabel, tracker.mDestAddress));
11790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
11804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
11814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                Context.LAYOUT_INFLATER_SERVICE);
11824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
11834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
118478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
118578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                (TextView)layout.findViewById(R.id.sms_short_code_remember_undo_instruction));
118678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
118778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt
11884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
11894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        messageView.setText(messageText);
11904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
119178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ViewGroup detailsLayout = (ViewGroup) layout.findViewById(
11924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_layout);
11934658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        TextView detailsView = (TextView) detailsLayout.findViewById(
11944658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_detail_message);
11954658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        detailsView.setText(detailsId);
11964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
11974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        CheckBox rememberChoice = (CheckBox) layout.findViewById(
11984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                R.id.sms_short_code_remember_choice_checkbox);
11994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        rememberChoice.setOnCheckedChangeListener(listener);
12004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AlertDialog d = new AlertDialog.Builder(mContext)
12024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                .setView(layout)
12030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener)
12040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener)
12050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .setOnCancelListener(listener)
12060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                .create();
12070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
12090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        d.show();
12104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setPositiveButton(d.getButton(DialogInterface.BUTTON_POSITIVE));
12124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        listener.setNegativeButton(d.getButton(DialogInterface.BUTTON_NEGATIVE));
12134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
12144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
12164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Returns the premium SMS permission for the specified package. If the package has never
12174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}
12184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * will be returned.
12194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to query permission
12204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN},
12214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
12224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
12234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
12244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
12254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public int getPremiumSmsPermission(String packageName) {
12264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        return mUsageMonitor.getPremiumSmsPermission(packageName);
12274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    }
12284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
12294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    /**
12304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * Sets the premium SMS permission for the specified package and save the value asynchronously
12314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * to persistent storage.
12324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param packageName the name of the package to set permission
12334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER},
12344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or
12354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     *  {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW}
12364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby     */
12374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby    public void setPremiumSmsPermission(String packageName, int permission) {
12384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        mUsageMonitor.setPremiumSmsPermission(packageName, permission);
12390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the message along to the radio.
12430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the SMS message to send
12450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void sendSms(SmsTracker tracker);
12470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send the multi-part SMS based on multipart Sms tracker
12500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
12510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tracker holds the multipart Sms tracker ready to be sent
12520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void sendMultipartSms(SmsTracker tracker) {
12540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<String> parts;
12550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> sentIntents;
12560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<PendingIntent> deliveryIntents;
12570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        HashMap<String, Object> map = tracker.mData;
12590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String destinationAddress = (String) map.get("destination");
12610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String scAddress = (String) map.get("scaddress");
12620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        parts = (ArrayList<String>) map.get("parts");
12640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
12650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
12660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // check if in service
12680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int ss = mPhone.getServiceState().getState();
12690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (ss != ServiceState.STATE_IN_SERVICE) {
12700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0, count = parts.size(); i < count; i++) {
12710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                PendingIntent sentIntent = null;
12720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (sentIntents != null && sentIntents.size() > i) {
12730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent = sentIntents.get(i);
12740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
12750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleNotInService(ss, sentIntent);
12760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
12770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
12780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
12790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents);
12810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
12820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Send an acknowledge message.
12850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param success indicates that last message was successfully received.
12860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param result result code indicating any error
12870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param response callback message sent when operation completes.
12880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected abstract void acknowledgeLastIncomingSms(boolean success,
12900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int result, Message response);
12910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
12920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
12930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Notify interested apps if the framework has rejected an incoming SMS,
12940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * and send an acknowledge message to the network.
12950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param success indicates that last message was successfully received.
12960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param result result code indicating any error
12970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param response callback message sent when operation completes.
12980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
12990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void notifyAndAcknowledgeLastIncomingSms(boolean success,
13000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int result, Message response) {
13010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (!success) {
13020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // broadcast SMS_REJECTED_ACTION intent
13030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Intent intent = new Intent(Intents.SMS_REJECTED_ACTION);
13040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            intent.putExtra("result", result);
13050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
13067fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn            mContext.sendBroadcast(intent, Manifest.permission.RECEIVE_SMS);
13070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        acknowledgeLastIncomingSms(success, result, response);
13090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
13100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
13120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Keeps track of an SMS that has been sent to the RIL, until it has
13130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * successfully been sent, or we're done trying.
13140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
13150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
13160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected static final class SmsTracker {
13170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // fields need to be public for derived SmsDispatchers
13180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final HashMap<String, Object> mData;
13190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mRetryCount;
13200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public int mMessageRef;
13210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mSentIntent;
13230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final PendingIntent mDeliveryIntent;
13240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13252029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra        public final PackageInfo mAppInfo;
13260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public final String mDestAddress;
13270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
13292029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr) {
13300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mData = data;
13310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mSentIntent = sentIntent;
13320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDeliveryIntent = deliveryIntent;
13330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mRetryCount = 0;
13342029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra            mAppInfo = appInfo;
13350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mDestAddress = destAddr;
13360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /**
13390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * Returns whether this tracker holds a multi-part SMS.
13400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * @return true if the tracker holds a multi-part SMS; false otherwise
13410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         */
13420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        protected boolean isMultipart() {
1343cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            HashMap<String, Object> map = mData;
13440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return map.containsKey("parts");
13450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
13470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
13490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dialog listener for SMS confirmation dialog.
13500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
13510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final class ConfirmDialogListener
13524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener,
13534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            CompoundButton.OnCheckedChangeListener {
13540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        private final SmsTracker mTracker;
13564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mPositiveButton;
13574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private Button mNegativeButton;
13584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        private boolean mRememberChoice;    // default is unchecked
135978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        private final TextView mRememberUndoInstruction;
13600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
136178df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt        ConfirmDialogListener(SmsTracker tracker, TextView textView) {
13620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mTracker = tracker;
136378df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt            mRememberUndoInstruction = textView;
13640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
13650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
13664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setPositiveButton(Button button) {
13674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mPositiveButton = button;
13684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
13694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
13704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        void setNegativeButton(Button button) {
13714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mNegativeButton = button;
13724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
13734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
13740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
13750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onClick(DialogInterface dialog, int which) {
13764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // Always set the SMS permission so that Settings will show a permission setting
13774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            // for the app (it won't be shown until after the app tries to send to a short code).
13784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            int newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
13794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
13800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (which == DialogInterface.BUTTON_POSITIVE) {
1381ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "CONFIRM sending SMS");
13822029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
13832029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                EventLog.writeEvent(EventLogTags.SMS_SENT_BY_USER,
13842029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                                    mTracker.mAppInfo.signatures[0].toCharsString());
13850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS, mTracker));
13864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
13874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW;
13884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
13890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (which == DialogInterface.BUTTON_NEGATIVE) {
1390ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.d(TAG, "DENY sending SMS");
13912029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                // XXX this is lossy- apps can have more than one signature
13922029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                EventLog.writeEvent(EventLogTags.SMS_DENIED_BY_USER,
13932029d86b5aebd03f7acbd249a4e2e4f65ec37d47Geremy Condra                                    mTracker.mAppInfo.signatures[0].toCharsString());
13940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
13954658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                if (mRememberChoice) {
13964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                    newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
13974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                }
13980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
13994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            setPremiumSmsPermission(mTracker.mAppInfo.packageName, newSmsPermission);
14000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
14020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
14030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onCancel(DialogInterface dialog) {
1404ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "dialog dismissed: don't send SMS");
14050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
14060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby
14084658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        @Override
14094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1410ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "remember this choice: " + isChecked);
14114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            mRememberChoice = isChecked;
14124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            if (isChecked) {
14134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_always_allow);
14144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mNegativeButton.setText(R.string.sms_short_code_confirm_never_allow);
141578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
141678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.
141778df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                            setText(R.string.sms_short_code_remember_undo_instruction);
141878df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,32);
141978df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
14204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            } else {
14214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby                mPositiveButton.setText(R.string.sms_short_code_confirm_allow);
14225d875796122cdd8a7004e8e3964b20b5c65a31a1Robert Greenwalt                mNegativeButton.setText(R.string.sms_short_code_confirm_deny);
142378df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                if (mRememberUndoInstruction != null) {
142478df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setText("");
142578df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                    mRememberUndoInstruction.setPadding(0,0,0,0);
142678df2f47241a498bbd919c4c19a44b824e5dc2d6Robert Greenwalt                }
14274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby            }
14284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby        }
14290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
14300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
14310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
14320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        @Override
14330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        public void onReceive(Context context, Intent intent) {
1434bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka            if (intent.getAction().equals(Intents.SMS_CB_RECEIVED_ACTION) ||
1435bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                    intent.getAction().equals(Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION)) {
1436bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                // Ignore this intent. Apps will process it.
1437bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka            } else {
1438bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                // Assume the intent is one of the SMS receive intents that
1439bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                // was sent as an ordered broadcast. Check result and ACK.
1440bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                int rc = getResultCode();
1441bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                boolean success = (rc == Activity.RESULT_OK)
1442bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                        || (rc == Intents.RESULT_SMS_HANDLED);
1443bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka
1444bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                // For a multi-part message, this only ACKs the last part.
1445bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                // Previous parts were ACK'd as they were received.
1446bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka                acknowledgeLastIncomingSms(success, rc, null);
1447bb8277c9c32f77d71dcc393b9baa19a3ffbeb0a6Alex Yakavenka            }
14480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    };
14500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
14510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void dispatchBroadcastMessage(SmsCbMessage message) {
14520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (message.isEmergencyMessage()) {
14530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Intent intent = new Intent(Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION);
14540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            intent.putExtra("message", message);
1455ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "Dispatching emergency SMS CB");
14567fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn            dispatch(intent, RECEIVE_EMERGENCY_BROADCAST_PERMISSION,
14577fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn                    AppOpsManager.OP_RECEIVE_EMERGECY_SMS);
14580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
14590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Intent intent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
14600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            intent.putExtra("message", message);
1461ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "Dispatching SMS CB");
14627fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn            dispatch(intent, RECEIVE_SMS_PERMISSION, AppOpsManager.OP_RECEIVE_SMS);
14630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
14640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
14650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
1466