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