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", 636e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan "message_body" 640d4bcdf379842af4b6304809156971e926f374f0Jake Hamby }; 650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 668f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang private static SmsBroadcastUndelivered instance; 670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** Content resolver to use to access raw table from SmsProvider. */ 690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private final ContentResolver mResolver; 700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** Handler for 3GPP-format messages (may be null). */ 720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private final GsmInboundSmsHandler mGsmInboundSmsHandler; 730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** Handler for 3GPP2-format messages (may be null). */ 750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private final CdmaInboundSmsHandler mCdmaInboundSmsHandler; 760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 778f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang /** Broadcast receiver that processes the raw table when the user unlocks the phone for the 788f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang * first time after reboot and the credential-encrypted storage is available. 798f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang */ 808f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 818f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang @Override 828a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang public void onReceive(final Context context, Intent intent) { 838f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang Rlog.d(TAG, "Received broadcast " + intent.getAction()); 848f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 858a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang new ScanRawTableThread(context).start(); 868f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang } 878f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang } 888f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang }; 898f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang 90a83613955a113b805729cd415aca50707529208aAmit Mahajan private class ScanRawTableThread extends Thread { 918a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang private final Context context; 928a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang 938a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang private ScanRawTableThread(Context context) { 948a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang this.context = context; 958a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang } 968a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang 97a83613955a113b805729cd415aca50707529208aAmit Mahajan @Override 98a83613955a113b805729cd415aca50707529208aAmit Mahajan public void run() { 99a83613955a113b805729cd415aca50707529208aAmit Mahajan scanRawTable(); 1008a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang InboundSmsHandler.cancelNewMessageNotification(context); 101a83613955a113b805729cd415aca50707529208aAmit Mahajan } 102a83613955a113b805729cd415aca50707529208aAmit Mahajan } 103a83613955a113b805729cd415aca50707529208aAmit Mahajan 1048f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang public static void initialize(Context context, GsmInboundSmsHandler gsmInboundSmsHandler, 1058f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang CdmaInboundSmsHandler cdmaInboundSmsHandler) { 1068f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang if (instance == null) { 1078f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang instance = new SmsBroadcastUndelivered( 1088f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang context, gsmInboundSmsHandler, cdmaInboundSmsHandler); 1098f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang } 110dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang 111dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang // Tell handlers to start processing new messages and transit from the startup state to the 112dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang // idle state. This method may be called multiple times for multi-sim devices. We must make 113dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang // sure the state transition happen to all inbound sms handlers. 114dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang if (gsmInboundSmsHandler != null) { 115dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang gsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_START_ACCEPTING_SMS); 116dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang } 117dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang if (cdmaInboundSmsHandler != null) { 118dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang cdmaInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_START_ACCEPTING_SMS); 119dc7411e9fc8ac029a7bad8b85b0f24642a1774b6Ji Yang } 1208f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang } 1218f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang 1228f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang private SmsBroadcastUndelivered(Context context, GsmInboundSmsHandler gsmInboundSmsHandler, 1230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby CdmaInboundSmsHandler cdmaInboundSmsHandler) { 1240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mResolver = context.getContentResolver(); 1250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mGsmInboundSmsHandler = gsmInboundSmsHandler; 1260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mCdmaInboundSmsHandler = cdmaInboundSmsHandler; 1270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 128a83613955a113b805729cd415aca50707529208aAmit Mahajan UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 129a83613955a113b805729cd415aca50707529208aAmit Mahajan 130a83613955a113b805729cd415aca50707529208aAmit Mahajan if (userManager.isUserUnlocked()) { 1318a54cdb7fdac1b325213a775939ccfc50dc65425Ji Yang new ScanRawTableThread(context).start(); 132a83613955a113b805729cd415aca50707529208aAmit Mahajan } else { 133a83613955a113b805729cd415aca50707529208aAmit Mahajan IntentFilter userFilter = new IntentFilter(); 134a83613955a113b805729cd415aca50707529208aAmit Mahajan userFilter.addAction(Intent.ACTION_USER_UNLOCKED); 1359b813aa455186511edd03bb738334a1acca7e7b3Amit Mahajan context.registerReceiver(mBroadcastReceiver, userFilter); 136a83613955a113b805729cd415aca50707529208aAmit Mahajan } 1370d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1380d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1390d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 1400d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Scan the raw table for complete SMS messages to broadcast, and old PDUs to delete. 1410d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 1420d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private void scanRawTable() { 1438f21e0c6528f015924d153350dd2a717d3b51f66Ji Yang if (DBG) Rlog.d(TAG, "scanning raw table for undelivered messages"); 1440d4bcdf379842af4b6304809156971e926f374f0Jake Hamby long startTime = System.nanoTime(); 1450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby HashMap<SmsReferenceKey, Integer> multiPartReceivedCount = 1460d4bcdf379842af4b6304809156971e926f374f0Jake Hamby new HashMap<SmsReferenceKey, Integer>(4); 1470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby HashSet<SmsReferenceKey> oldMultiPartMessages = new HashSet<SmsReferenceKey>(4); 1480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Cursor cursor = null; 1490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby try { 1506e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan // query only non-deleted ones 1516e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan cursor = mResolver.query(InboundSmsHandler.sRawUri, PDU_PENDING_MESSAGE_PROJECTION, 1526e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan "deleted = 0", null, 1536e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan null); 1540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (cursor == null) { 1550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "error getting pending message cursor"); 1560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return; 1570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby boolean isCurrentFormat3gpp2 = InboundSmsHandler.isCurrentFormat3gpp2(); 1600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby while (cursor.moveToNext()) { 1610d4bcdf379842af4b6304809156971e926f374f0Jake Hamby InboundSmsTracker tracker; 1620d4bcdf379842af4b6304809156971e926f374f0Jake Hamby try { 163871a2ec0bc8e8198aeb1913e7bf6cb22a7ff3604Amit Mahajan tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(cursor, 164871a2ec0bc8e8198aeb1913e7bf6cb22a7ff3604Amit Mahajan isCurrentFormat3gpp2); 1650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } catch (IllegalArgumentException e) { 1660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "error loading SmsTracker: " + e); 1670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby continue; 1680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 1700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (tracker.getMessageCount() == 1) { 1710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // deliver single-part message 1720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby broadcastSms(tracker); 1730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 1740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby SmsReferenceKey reference = new SmsReferenceKey(tracker); 1750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Integer receivedCount = multiPartReceivedCount.get(reference); 1760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (receivedCount == null) { 1770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby multiPartReceivedCount.put(reference, 1); // first segment seen 1780d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (tracker.getTimestamp() < 1790d4bcdf379842af4b6304809156971e926f374f0Jake Hamby (System.currentTimeMillis() - PARTIAL_SEGMENT_EXPIRE_AGE)) { 1800d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // older than 30 days; delete if we don't find all the segments 1810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby oldMultiPartMessages.add(reference); 1820d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 1840d4bcdf379842af4b6304809156971e926f374f0Jake Hamby int newCount = receivedCount + 1; 1850d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (newCount == tracker.getMessageCount()) { 1860d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // looks like we've got all the pieces; send a single tracker 1870d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // to state machine which will find the other pieces to broadcast 1880d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (DBG) Rlog.d(TAG, "found complete multi-part message"); 1890d4bcdf379842af4b6304809156971e926f374f0Jake Hamby broadcastSms(tracker); 1900d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // don't delete this old message until after we broadcast it 1910d4bcdf379842af4b6304809156971e926f374f0Jake Hamby oldMultiPartMessages.remove(reference); 1920d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 1930d4bcdf379842af4b6304809156971e926f374f0Jake Hamby multiPartReceivedCount.put(reference, newCount); 1940d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1950d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1960d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1970d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 1980d4bcdf379842af4b6304809156971e926f374f0Jake Hamby // Delete old incomplete message segments 1990d4bcdf379842af4b6304809156971e926f374f0Jake Hamby for (SmsReferenceKey message : oldMultiPartMessages) { 2006e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan // delete permanently 2016e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan int rows = mResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, 2026e4abd849e12860a7459f7ec74496ca02b9d7ee0Amit Mahajan InboundSmsHandler.SELECT_BY_REFERENCE, message.getDeleteWhereArgs()); 2030d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (rows == 0) { 2040d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "No rows were deleted from raw table!"); 2050d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else if (DBG) { 2060d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.d(TAG, "Deleted " + rows + " rows from raw table for incomplete " 2070d4bcdf379842af4b6304809156971e926f374f0Jake Hamby + message.mMessageCount + " part message"); 2080d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2090d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2100d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } catch (SQLException e) { 2110d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "error reading pending SMS messages", e); 2120d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } finally { 2130d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (cursor != null) { 2140d4bcdf379842af4b6304809156971e926f374f0Jake Hamby cursor.close(); 2150d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2160d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (DBG) Rlog.d(TAG, "finished scanning raw table in " 2170d4bcdf379842af4b6304809156971e926f374f0Jake Hamby + ((System.nanoTime() - startTime) / 1000000) + " ms"); 2180d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2190d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2200d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2210d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 2220d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Send tracker to appropriate (3GPP or 3GPP2) inbound SMS handler for broadcast. 2230d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 2240d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private void broadcastSms(InboundSmsTracker tracker) { 2250d4bcdf379842af4b6304809156971e926f374f0Jake Hamby InboundSmsHandler handler; 2260d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (tracker.is3gpp2()) { 2270d4bcdf379842af4b6304809156971e926f374f0Jake Hamby handler = mCdmaInboundSmsHandler; 2280d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 2290d4bcdf379842af4b6304809156971e926f374f0Jake Hamby handler = mGsmInboundSmsHandler; 2300d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2310d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (handler != null) { 2320d4bcdf379842af4b6304809156971e926f374f0Jake Hamby handler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_SMS, tracker); 2330d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } else { 2340d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Rlog.e(TAG, "null handler for " + tracker.getFormat() + " format, can't deliver."); 2350d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2360d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2370d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2380d4bcdf379842af4b6304809156971e926f374f0Jake Hamby /** 2390d4bcdf379842af4b6304809156971e926f374f0Jake Hamby * Used as the HashMap key for matching concatenated message segments. 2400d4bcdf379842af4b6304809156971e926f374f0Jake Hamby */ 2410d4bcdf379842af4b6304809156971e926f374f0Jake Hamby private static class SmsReferenceKey { 2420d4bcdf379842af4b6304809156971e926f374f0Jake Hamby final String mAddress; 2430d4bcdf379842af4b6304809156971e926f374f0Jake Hamby final int mReferenceNumber; 2440d4bcdf379842af4b6304809156971e926f374f0Jake Hamby final int mMessageCount; 2450d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2460d4bcdf379842af4b6304809156971e926f374f0Jake Hamby SmsReferenceKey(InboundSmsTracker tracker) { 2470d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mAddress = tracker.getAddress(); 2480d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mReferenceNumber = tracker.getReferenceNumber(); 2490d4bcdf379842af4b6304809156971e926f374f0Jake Hamby mMessageCount = tracker.getMessageCount(); 2500d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2510d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2520d4bcdf379842af4b6304809156971e926f374f0Jake Hamby String[] getDeleteWhereArgs() { 2530d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return new String[]{mAddress, Integer.toString(mReferenceNumber), 2540d4bcdf379842af4b6304809156971e926f374f0Jake Hamby Integer.toString(mMessageCount)}; 2550d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby @Override 2580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby public int hashCode() { 2590d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return ((mReferenceNumber * 31) + mMessageCount) * 31 + mAddress.hashCode(); 2600d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2610d4bcdf379842af4b6304809156971e926f374f0Jake Hamby 2620d4bcdf379842af4b6304809156971e926f374f0Jake Hamby @Override 2630d4bcdf379842af4b6304809156971e926f374f0Jake Hamby public boolean equals(Object o) { 2640d4bcdf379842af4b6304809156971e926f374f0Jake Hamby if (o instanceof SmsReferenceKey) { 2650d4bcdf379842af4b6304809156971e926f374f0Jake Hamby SmsReferenceKey other = (SmsReferenceKey) o; 2660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return other.mAddress.equals(mAddress) 2670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby && (other.mReferenceNumber == mReferenceNumber) 2680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby && (other.mMessageCount == mMessageCount); 2690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby return false; 2710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby } 2730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby} 274