10d4bcdf379842af4b6304809156971e926f374f0Jake Hamby/* 20d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Copyright (C) 2013 The Android Open Source Project 30d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * 40d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Licensed under the Apache License, Version 2.0 (the "License"); 50d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * you may not use this file except in compliance with the License. 60d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * You may obtain a copy of the License at 70d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * 80d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * http://www.apache.org/licenses/LICENSE-2.0 90d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * 100d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Unless required by applicable law or agreed to in writing, software 110d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * distributed under the License is distributed on an "AS IS" BASIS, 120d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * See the License for the specific language governing permissions and 140d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * limitations under the License. 150d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 160d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 170d4bcdf379842af4b6304809156971e926f374f0Jake Hambypackage com.android.internal.telephony; 180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 198f21e0c6528f015924d153350dd2a717d3b51f66Ji Yangimport android.content.BroadcastReceiver; 200d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.content.ContentResolver; 210d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.content.Context; 228f21e0c6528f015924d153350dd2a717d3b51f66Ji Yangimport android.content.Intent; 238f21e0c6528f015924d153350dd2a717d3b51f66Ji Yangimport android.content.IntentFilter; 240d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.database.Cursor; 250d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.database.SQLException; 268f21e0c6528f015924d153350dd2a717d3b51f66Ji Yangimport android.os.UserHandle; 27a83613955a113b805729cd415aca50707529208aAmit Mahajanimport android.os.UserManager; 280d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.Rlog; 290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 300d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.cdma.CdmaInboundSmsHandler; 310d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.gsm.GsmInboundSmsHandler; 320d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 330d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.HashMap; 340d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport java.util.HashSet; 350d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 360d4bcdf379842af4b6304809156971e926f374f0Jake Hamby/** 378f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang * Called when the credential-encrypted storage is unlocked, collecting all acknowledged messages 388f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang * and deleting any partial message segments older than 30 days. Called from a worker thread to 398f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang * avoid delaying phone app startup. The last step is to broadcast the first pending message from 408f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang * the main thread, then the remaining pending messages will be broadcast after the previous 418f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang * ordered broadcast completes. 420d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 438f21e0c6528f015924d153350dd2a717d3b51f66Ji Yangpublic class SmsBroadcastUndelivered { 440d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private static final String TAG = "SmsBroadcastUndelivered"; 450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private static final boolean DBG = InboundSmsHandler.DBG; 460d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** Delete any partial message segments older than 30 days. */ 480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby static final long PARTIAL_SEGMENT_EXPIRE_AGE = (long) (60 * 60 * 1000) * 24 * 30; 490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Query projection for dispatching pending messages at boot time. 520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Column order must match the {@code *_COLUMN} constants in {@link InboundSmsHandler}. 530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private static final String[] PDU_PENDING_MESSAGE_PROJECTION = { 550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby "pdu", 560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby "sequence", 570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby "destination_port", 580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby "date", 590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby "reference_number", 600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby "count", 610d4bcdf379842af4b6304809156971e926f374f0Jake Hamby "address", 626e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan "_id", 63af7bc32573007f2ea1185fc5cb4f3980e1ff1304fionaxu "message_body", 64af7bc32573007f2ea1185fc5cb4f3980e1ff1304fionaxu "display_originating_addr" 650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby }; 660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 678f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang private static SmsBroadcastUndelivered instance; 680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** Content resolver to use to access raw table from SmsProvider. */ 700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private final ContentResolver mResolver; 710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** Handler for 3GPP-format messages (may be null). */ 730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private final GsmInboundSmsHandler mGsmInboundSmsHandler; 740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** Handler for 3GPP2-format messages (may be null). */ 760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private final CdmaInboundSmsHandler mCdmaInboundSmsHandler; 770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 788f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang /** Broadcast receiver that processes the raw table when the user unlocks the phone for the 798f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang * first time after reboot and the credential-encrypted storage is available. 808f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang */ 818f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 828f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang @Override 838a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang public void onReceive(final Context context, Intent intent) { 848f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang Rlog.d(TAG, "Received broadcast " + intent.getAction()); 858f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 868a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang new ScanRawTableThread(context).start(); 878f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang } 888f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang } 898f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang }; 908f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang 91a83613955a113b805729cd415aca50707529208aAmit Mahajan private class ScanRawTableThread extends Thread { 928a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang private final Context context; 938a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang 948a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang private ScanRawTableThread(Context context) { 958a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang this.context = context; 968a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang } 978a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang 98a83613955a113b805729cd415aca50707529208aAmit Mahajan @Override 99a83613955a113b805729cd415aca50707529208aAmit Mahajan public void run() { 100a83613955a113b805729cd415aca50707529208aAmit Mahajan scanRawTable(); 1018a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang InboundSmsHandler.cancelNewMessageNotification(context); 102a83613955a113b805729cd415aca50707529208aAmit Mahajan } 103a83613955a113b805729cd415aca50707529208aAmit Mahajan } 104a83613955a113b805729cd415aca50707529208aAmit Mahajan 1058f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang public static void initialize(Context context, GsmInboundSmsHandler gsmInboundSmsHandler, 1068f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang CdmaInboundSmsHandler cdmaInboundSmsHandler) { 1078f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang if (instance == null) { 1088f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang instance = new SmsBroadcastUndelivered( 1098f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang context, gsmInboundSmsHandler, cdmaInboundSmsHandler); 1108f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang } 111dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang 112dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang // Tell handlers to start processing new messages and transit from the startup state to the 113dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang // idle state. This method may be called multiple times for multi-sim devices. We must make 114dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang // sure the state transition happen to all inbound sms handlers. 115dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang if (gsmInboundSmsHandler != null) { 116dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang gsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_START_ACCEPTING_SMS); 117dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang } 118dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang if (cdmaInboundSmsHandler != null) { 119dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang cdmaInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_START_ACCEPTING_SMS); 120dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang } 1218f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang } 1228f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang 1238f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang private SmsBroadcastUndelivered(Context context, GsmInboundSmsHandler gsmInboundSmsHandler, 1240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby CdmaInboundSmsHandler cdmaInboundSmsHandler) { 1250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mResolver = context.getContentResolver(); 1260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mGsmInboundSmsHandler = gsmInboundSmsHandler; 1270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mCdmaInboundSmsHandler = cdmaInboundSmsHandler; 1280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 129a83613955a113b805729cd415aca50707529208aAmit Mahajan UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 130a83613955a113b805729cd415aca50707529208aAmit Mahajan 131a83613955a113b805729cd415aca50707529208aAmit Mahajan if (userManager.isUserUnlocked()) { 1328a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang new ScanRawTableThread(context).start(); 133a83613955a113b805729cd415aca50707529208aAmit Mahajan } else { 134a83613955a113b805729cd415aca50707529208aAmit Mahajan IntentFilter userFilter = new IntentFilter(); 135a83613955a113b805729cd415aca50707529208aAmit Mahajan userFilter.addAction(Intent.ACTION_USER_UNLOCKED); 1369b813aa455186511edd03bb738334a1acca7e7b3Amit Mahajan context.registerReceiver(mBroadcastReceiver, userFilter); 137a83613955a113b805729cd415aca50707529208aAmit Mahajan } 1380d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1390d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1400d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 1410d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Scan the raw table for complete SMS messages to broadcast, and old PDUs to delete. 1420d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 1430d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private void scanRawTable() { 1448f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang if (DBG) Rlog.d(TAG, "scanning raw table for undelivered messages"); 1450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby long startTime = System.nanoTime(); 1460d4bcdf379842af4b6304809156971e926f374f0Jake Hamby HashMap<SmsReferenceKey, Integer> multiPartReceivedCount = 1470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby new HashMap<SmsReferenceKey, Integer>(4); 1480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby HashSet<SmsReferenceKey> oldMultiPartMessages = new HashSet<SmsReferenceKey>(4); 1490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Cursor cursor = null; 1500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby try { 1516e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan // query only non-deleted ones 1526e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan cursor = mResolver.query(InboundSmsHandler.sRawUri, PDU_PENDING_MESSAGE_PROJECTION, 1536e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan "deleted = 0", null, 1546e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan null); 1550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (cursor == null) { 1560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "error getting pending message cursor"); 1570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return; 1580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby boolean isCurrentFormat3gpp2 = InboundSmsHandler.isCurrentFormat3gpp2(); 1610d4bcdf379842af4b6304809156971e926f374f0Jake Hamby while (cursor.moveToNext()) { 1620d4bcdf379842af4b6304809156971e926f374f0Jake Hamby InboundSmsTracker tracker; 1630d4bcdf379842af4b6304809156971e926f374f0Jake Hamby try { 164871a2ec0bc8e8198aeb1913e7bf6cb22a7ff3604Amit Mahajan tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(cursor, 165871a2ec0bc8e8198aeb1913e7bf6cb22a7ff3604Amit Mahajan isCurrentFormat3gpp2); 1660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } catch (IllegalArgumentException e) { 1670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "error loading SmsTracker: " + e); 1680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby continue; 1690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (tracker.getMessageCount() == 1) { 1720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // deliver single-part message 1730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby broadcastSms(tracker); 1740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 1750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby SmsReferenceKey reference = new SmsReferenceKey(tracker); 1760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Integer receivedCount = multiPartReceivedCount.get(reference); 1770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (receivedCount == null) { 1780d4bcdf379842af4b6304809156971e926f374f0Jake Hamby multiPartReceivedCount.put(reference, 1); // first segment seen 1790d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (tracker.getTimestamp() < 1800d4bcdf379842af4b6304809156971e926f374f0Jake Hamby (System.currentTimeMillis() - PARTIAL_SEGMENT_EXPIRE_AGE)) { 1810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // older than 30 days; delete if we don't find all the segments 1820d4bcdf379842af4b6304809156971e926f374f0Jake Hamby oldMultiPartMessages.add(reference); 1830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1840d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 1850d4bcdf379842af4b6304809156971e926f374f0Jake Hamby int newCount = receivedCount + 1; 1860d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (newCount == tracker.getMessageCount()) { 1870d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // looks like we've got all the pieces; send a single tracker 1880d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // to state machine which will find the other pieces to broadcast 1890d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (DBG) Rlog.d(TAG, "found complete multi-part message"); 1900d4bcdf379842af4b6304809156971e926f374f0Jake Hamby broadcastSms(tracker); 1910d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // don't delete this old message until after we broadcast it 1920d4bcdf379842af4b6304809156971e926f374f0Jake Hamby oldMultiPartMessages.remove(reference); 1930d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 1940d4bcdf379842af4b6304809156971e926f374f0Jake Hamby multiPartReceivedCount.put(reference, newCount); 1950d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1960d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1970d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1980d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1990d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // Delete old incomplete message segments 2000d4bcdf379842af4b6304809156971e926f374f0Jake Hamby for (SmsReferenceKey message : oldMultiPartMessages) { 2016e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan // delete permanently 2026e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan int rows = mResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, 203f97f0535c2793c0f662a83fa6458f9d3241bd904fionaxu message.getDeleteWhere(), message.getDeleteWhereArgs()); 2040d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (rows == 0) { 2050d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "No rows were deleted from raw table!"); 2060d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else if (DBG) { 2070d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.d(TAG, "Deleted " + rows + " rows from raw table for incomplete " 2080d4bcdf379842af4b6304809156971e926f374f0Jake Hamby + message.mMessageCount + " part message"); 2090d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2100d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2110d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } catch (SQLException e) { 2120d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "error reading pending SMS messages", e); 2130d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } finally { 2140d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (cursor != null) { 2150d4bcdf379842af4b6304809156971e926f374f0Jake Hamby cursor.close(); 2160d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2170d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (DBG) Rlog.d(TAG, "finished scanning raw table in " 2180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby + ((System.nanoTime() - startTime) / 1000000) + " ms"); 2190d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2200d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2210d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2220d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 2230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Send tracker to appropriate (3GPP or 3GPP2) inbound SMS handler for broadcast. 2240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 2250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private void broadcastSms(InboundSmsTracker tracker) { 2260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby InboundSmsHandler handler; 2270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (tracker.is3gpp2()) { 2280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby handler = mCdmaInboundSmsHandler; 2290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 2300d4bcdf379842af4b6304809156971e926f374f0Jake Hamby handler = mGsmInboundSmsHandler; 2310d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2320d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (handler != null) { 2330d4bcdf379842af4b6304809156971e926f374f0Jake Hamby handler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_SMS, tracker); 2340d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 2350d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "null handler for " + tracker.getFormat() + " format, can't deliver."); 2360d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2370d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2380d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2390d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 2400d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Used as the HashMap key for matching concatenated message segments. 2410d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 2420d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private static class SmsReferenceKey { 2430d4bcdf379842af4b6304809156971e926f374f0Jake Hamby final String mAddress; 2440d4bcdf379842af4b6304809156971e926f374f0Jake Hamby final int mReferenceNumber; 2450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby final int mMessageCount; 246f97f0535c2793c0f662a83fa6458f9d3241bd904fionaxu final String mQuery; 2470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby SmsReferenceKey(InboundSmsTracker tracker) { 2490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mAddress = tracker.getAddress(); 2500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mReferenceNumber = tracker.getReferenceNumber(); 2510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mMessageCount = tracker.getMessageCount(); 252f97f0535c2793c0f662a83fa6458f9d3241bd904fionaxu mQuery = tracker.getQueryForSegments(); 253f97f0535c2793c0f662a83fa6458f9d3241bd904fionaxu 2540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby String[] getDeleteWhereArgs() { 2570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return new String[]{mAddress, Integer.toString(mReferenceNumber), 2580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Integer.toString(mMessageCount)}; 2590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 261f97f0535c2793c0f662a83fa6458f9d3241bd904fionaxu String getDeleteWhere() { 262f97f0535c2793c0f662a83fa6458f9d3241bd904fionaxu return mQuery; 263f97f0535c2793c0f662a83fa6458f9d3241bd904fionaxu } 264f97f0535c2793c0f662a83fa6458f9d3241bd904fionaxu 2650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby @Override 2660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby public int hashCode() { 2670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return ((mReferenceNumber * 31) + mMessageCount) * 31 + mAddress.hashCode(); 2680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby @Override 2710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby public boolean equals(Object o) { 2720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (o instanceof SmsReferenceKey) { 2730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby SmsReferenceKey other = (SmsReferenceKey) o; 2740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return other.mAddress.equals(mAddress) 2750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby && (other.mReferenceNumber == mReferenceNumber) 2760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby && (other.mMessageCount == mMessageCount); 2770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2780d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return false; 2790d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2800d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby} 282