1c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/* 2c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Copyright (C) 2006 The Android Open Source Project 3c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 4c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Licensed under the Apache License, Version 2.0 (the "License"); 5c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * you may not use this file except in compliance with the License. 6c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * You may obtain a copy of the License at 7c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 8c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * http://www.apache.org/licenses/LICENSE-2.0 9c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 10c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Unless required by applicable law or agreed to in writing, software 11c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * distributed under the License is distributed on an "AS IS" BASIS, 12c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * See the License for the specific language governing permissions and 14c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * limitations under the License. 15c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 16c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 17c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepackage com.android.internal.telephony.gsm; 18c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 19c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.app.Activity; 20c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.app.PendingIntent; 21c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.app.PendingIntent.CanceledException; 22c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.content.Intent; 23c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.AsyncResult; 24c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.Message; 25c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.SystemProperties; 26c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.provider.Telephony.Sms; 27c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.provider.Telephony.Sms.Intents; 28c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.telephony.PhoneNumberUtils; 29c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.telephony.SmsCbLocation; 30c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.telephony.SmsCbMessage; 31c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.telephony.SmsManager; 32c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.telephony.gsm.GsmCellLocation; 33c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.util.Log; 34c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 35c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.CommandsInterface; 36c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.GsmAlphabet; 37c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.IccUtils; 38c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.PhoneBase; 39c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SmsConstants; 40c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SMSDispatcher; 41c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SmsHeader; 42c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SmsMessageBase; 43c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SmsStorageMonitor; 44c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.SmsUsageMonitor; 45c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.TelephonyProperties; 46c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 47c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport java.util.HashMap; 48c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport java.util.Iterator; 49c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 50c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepublic final class GsmSMSDispatcher extends SMSDispatcher { 51c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static final String TAG = "GSM"; 52c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 53c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** Status report received */ 54c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static final int EVENT_NEW_SMS_STATUS_REPORT = 100; 55c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 56c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** New broadcast SMS */ 57c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static final int EVENT_NEW_BROADCAST_SMS = 101; 58c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 59c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** Result of writing SM to UICC (when SMS-PP service is not available). */ 60c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static final int EVENT_WRITE_SMS_COMPLETE = 102; 61c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 62c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** Handler for SMS-PP data download messages to UICC. */ 63c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private final UsimDataDownloadHandler mDataDownloadHandler; 64c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 65c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public GsmSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor, 66c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsUsageMonitor usageMonitor) { 67c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville super(phone, storageMonitor, usageMonitor); 68c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mDataDownloadHandler = new UsimDataDownloadHandler(mCm); 69c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.setOnNewGsmSms(this, EVENT_NEW_SMS, null); 70c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); 71c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.setOnNewGsmBroadcastSms(this, EVENT_NEW_BROADCAST_SMS, null); 72c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 73c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 74c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 75c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void dispose() { 76c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.unSetOnNewGsmSms(this); 77c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.unSetOnSmsStatus(this); 78c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.unSetOnNewGsmBroadcastSms(this); 79c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 80c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 81c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 82c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected String getFormat() { 83c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return SmsConstants.FORMAT_3GPP; 84c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 85c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 86c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 87c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Handles 3GPP format-specific events coming from the phone stack. 88c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Other events are handled by {@link SMSDispatcher#handleMessage}. 89c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 90c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param msg the message to handle 91c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 92c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 93c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public void handleMessage(Message msg) { 94c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch (msg.what) { 95c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case EVENT_NEW_SMS_STATUS_REPORT: 96c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville handleStatusReport((AsyncResult) msg.obj); 97c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 98c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 99c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case EVENT_NEW_BROADCAST_SMS: 100c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville handleBroadcastSms((AsyncResult)msg.obj); 101c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 102c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 103c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case EVENT_WRITE_SMS_COMPLETE: 104c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville AsyncResult ar = (AsyncResult) msg.obj; 105c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (ar.exception == null) { 106c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, "Successfully wrote SMS-PP message to UICC"); 107c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.acknowledgeLastIncomingGsmSms(true, 0, null); 108c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 109c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, "Failed to write SMS-PP message to UICC", ar.exception); 110c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.acknowledgeLastIncomingGsmSms(false, 111c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR, null); 112c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 113c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 114c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 115c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville default: 116c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville super.handleMessage(msg); 117c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 118c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 119c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 120c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 121c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Called when a status report is received. This should correspond to 122c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * a previously successful SEND. 123c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 124c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param ar AsyncResult passed into the message handler. ar.result should 125c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * be a String representing the status report PDU, as ASCII hex. 126c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 127c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void handleStatusReport(AsyncResult ar) { 128c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String pduString = (String) ar.result; 129c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage sms = SmsMessage.newFromCDS(pduString); 130c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 131c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (sms != null) { 132c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int tpStatus = sms.getStatus(); 133c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int messageRef = sms.messageRef; 134c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { 135c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsTracker tracker = deliveryPendingList.get(i); 136c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (tracker.mMessageRef == messageRef) { 137c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Found it. Remove from list and broadcast. 138c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if(tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING ) { 139c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville deliveryPendingList.remove(i); 140c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 141c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville PendingIntent intent = tracker.mDeliveryIntent; 142c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Intent fillIn = new Intent(); 143c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString)); 144c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville fillIn.putExtra("format", SmsConstants.FORMAT_3GPP); 145c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 146c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville intent.send(mContext, Activity.RESULT_OK, fillIn); 147c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (CanceledException ex) {} 148c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 149c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Only expect to see one tracker matching this messageref 150c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 151c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 152c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 153c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 154c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null); 155c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 156c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 157c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 158c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 159c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public int dispatchMessage(SmsMessageBase smsb) { 160c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 161c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // If sms is null, means there was a parsing error. 162c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (smsb == null) { 163c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(TAG, "dispatchMessage: message is null"); 164c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return Intents.RESULT_SMS_GENERIC_ERROR; 165c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 166c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 167c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage sms = (SmsMessage) smsb; 168c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 169c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (sms.isTypeZero()) { 170c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be 171c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Displayed/Stored/Notified. They should only be acknowledged. 172c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, "Received short message type 0, Don't display or store it. Send Ack"); 173c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return Intents.RESULT_SMS_HANDLED; 174c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 175c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 176c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Send SMS-PP data download messages to UICC. See 3GPP TS 31.111 section 7.1.1. 177c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (sms.isUsimDataDownload()) { 178c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville UsimServiceTable ust = mPhone.getUsimServiceTable(); 179c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // If we receive an SMS-PP message before the UsimServiceTable has been loaded, 180c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // assume that the data download service is not present. This is very unlikely to 181c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // happen because the IMS connection will not be established until after the ISIM 182c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // records have been loaded, after the USIM service table has been loaded. 183c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (ust != null && ust.isAvailable( 184c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville UsimServiceTable.UsimService.DATA_DL_VIA_SMS_PP)) { 185c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, "Received SMS-PP data download, sending to UICC."); 186c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return mDataDownloadHandler.startDataDownload(sms); 187c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 188c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, "DATA_DL_VIA_SMS_PP service not available, storing message to UICC."); 189c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String smsc = IccUtils.bytesToHexString( 190c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( 191c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville sms.getServiceCenterAddress())); 192c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.writeSmsToSim(SmsManager.STATUS_ON_ICC_UNREAD, smsc, 193c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville IccUtils.bytesToHexString(sms.getPdu()), 194c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville obtainMessage(EVENT_WRITE_SMS_COMPLETE)); 195c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return Activity.RESULT_OK; // acknowledge after response from write to USIM 196c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 197c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 198c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 199c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (mSmsReceiveDisabled) { 200c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Device doesn't support SMS service, 201c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, "Received short message on device which doesn't support " 202c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville + "SMS service. Ignored."); 203c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return Intents.RESULT_SMS_HANDLED; 204c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 205c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 206c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Special case the message waiting indicator messages 207c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean handled = false; 208c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (sms.isMWISetMessage()) { 209c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mPhone.setVoiceMessageWaiting(1, -1); // line 1: unknown number of msgs waiting 210c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville handled = sms.isMwiDontStore(); 211c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) { 212c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled); 213c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 214c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else if (sms.isMWIClearMessage()) { 215c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mPhone.setVoiceMessageWaiting(1, 0); // line 1: no msgs waiting 216c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville handled = sms.isMwiDontStore(); 217c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) { 218c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled); 219c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 220c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 221c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 222c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (handled) { 223c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return Intents.RESULT_SMS_HANDLED; 224c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 225c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 226c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (!mStorageMonitor.isStorageAvailable() && 227c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville sms.getMessageClass() != SmsConstants.MessageClass.CLASS_0) { 228c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // It's a storable message and there's no storage available. Bail. 229c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // (See TS 23.038 for a description of class 0 messages.) 230c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return Intents.RESULT_SMS_OUT_OF_MEMORY; 231c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 232c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 233c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return dispatchNormalMessage(smsb); 234c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 235c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 236c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 237c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 238c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected void sendData(String destAddr, String scAddr, int destPort, 239c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 240c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 241c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddr, destAddr, destPort, data, (deliveryIntent != null)); 242c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (pdu != null) { 243c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent, 244c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville destAddr); 245c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 246c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(TAG, "GsmSMSDispatcher.sendData(): getSubmitPdu() returned null"); 247c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 248c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 249c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 250c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 251c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 252c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected void sendText(String destAddr, String scAddr, String text, 253c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville PendingIntent sentIntent, PendingIntent deliveryIntent) { 254c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( 255c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville scAddr, destAddr, text, (deliveryIntent != null)); 256c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (pdu != null) { 257c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent, 258c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville destAddr); 259c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 260c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null"); 261c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 262c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 263c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 264c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 265c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 266c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected GsmAlphabet.TextEncodingDetails calculateLength(CharSequence messageBody, 267c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville boolean use7bitOnly) { 268c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return SmsMessage.calculateLength(messageBody, use7bitOnly); 269c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 270c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 271c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 272c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 273c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected void sendNewSubmitPdu(String destinationAddress, String scAddress, 274c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String message, SmsHeader smsHeader, int encoding, 275c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) { 276c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, 277c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader), 278c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville encoding, smsHeader.languageTable, smsHeader.languageShiftTable); 279c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (pdu != null) { 280c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent, 281c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville destinationAddress); 282c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 283c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null"); 284c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 285c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 286c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 287c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 288c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 289c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected void sendSms(SmsTracker tracker) { 290c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville HashMap<String, Object> map = tracker.mData; 291c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 292c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte smsc[] = (byte[]) map.get("smsc"); 293c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte pdu[] = (byte[]) map.get("pdu"); 294c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 295c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); 296c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply); 297c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 298c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 299c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** {@inheritDoc} */ 300c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 301c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville protected void acknowledgeLastIncomingSms(boolean success, int result, Message response) { 302c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mCm.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response); 303c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 304c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 305c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static int resultToCause(int rc) { 306c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch (rc) { 307c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case Activity.RESULT_OK: 308c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case Intents.RESULT_SMS_HANDLED: 309c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Cause code is ignored on success. 310c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return 0; 311c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case Intents.RESULT_SMS_OUT_OF_MEMORY: 312c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return CommandsInterface.GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED; 313c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case Intents.RESULT_SMS_GENERIC_ERROR: 314c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville default: 315c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR; 316c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 317c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 318c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 319c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 320c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Holds all info about a message page needed to assemble a complete 321c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * concatenated message 322c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 323c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private static final class SmsCbConcatInfo { 324c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 325c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private final SmsCbHeader mHeader; 326c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private final SmsCbLocation mLocation; 327c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 328c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public SmsCbConcatInfo(SmsCbHeader header, SmsCbLocation location) { 329c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mHeader = header; 330c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mLocation = location; 331c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 332c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 333c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 334c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public int hashCode() { 335c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return (mHeader.getSerialNumber() * 31) + mLocation.hashCode(); 336c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 337c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 338c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville @Override 339c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean equals(Object obj) { 340c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (obj instanceof SmsCbConcatInfo) { 341c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsCbConcatInfo other = (SmsCbConcatInfo)obj; 342c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 343c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Two pages match if they have the same serial number (which includes the 344c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // geographical scope and update number), and both pages belong to the same 345c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // location (PLMN, plus LAC and CID if these are part of the geographical scope). 346c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return mHeader.getSerialNumber() == other.mHeader.getSerialNumber() 347c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville && mLocation.equals(other.mLocation); 348c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 349c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 350c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return false; 351c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 352c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 353c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 354c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Compare the location code for this message to the current location code. The match is 355c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * relative to the geographical scope of the message, which determines whether the LAC 356c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * and Cell ID are saved in mLocation or set to -1 to match all values. 357c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * 358c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param plmn the current PLMN 359c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param lac the current Location Area (GSM) or Service Area (UMTS) 360c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param cid the current Cell ID 361c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @return true if this message is valid for the current location; false otherwise 362c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 363c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville public boolean matchesLocation(String plmn, int lac, int cid) { 364c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return mLocation.isInLocationArea(plmn, lac, cid); 365c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 366c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 367c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 368c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // This map holds incomplete concatenated messages waiting for assembly 369c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private final HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap = 370c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville new HashMap<SmsCbConcatInfo, byte[][]>(); 371c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 372c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville /** 373c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Handle 3GPP format SMS-CB message. 374c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * @param ar the AsyncResult containing the received PDUs 375c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */ 376c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville private void handleBroadcastSms(AsyncResult ar) { 377c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville try { 378c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[] receivedPdu = (byte[])ar.result; 379c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 380c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (false) { 381c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville for (int i = 0; i < receivedPdu.length; i += 8) { 382c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville StringBuilder sb = new StringBuilder("SMS CB pdu data: "); 383c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville for (int j = i; j < i + 8 && j < receivedPdu.length; j++) { 384c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int b = receivedPdu[j] & 0xff; 385c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (b < 0x10) { 386c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville sb.append('0'); 387c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 388c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville sb.append(Integer.toHexString(b)).append(' '); 389c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 390c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.d(TAG, sb.toString()); 391c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 392c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 393c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 394c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsCbHeader header = new SmsCbHeader(receivedPdu); 395c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville String plmn = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC); 3960fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka int lac = -1; 3970fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka int cid = -1; 3980fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka android.telephony.CellLocation cl = mPhone.getCellLocation(); 3990fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka // Check if cell location is GsmCellLocation. This is required to support 4000fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka // dual-mode devices such as CDMA/LTE devices that require support for 4010fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka // both 3GPP and 3GPP2 format messages 4020fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka if (cl instanceof GsmCellLocation) { 4030fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka GsmCellLocation cellLocation = (GsmCellLocation)cl; 4040fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka lac = cellLocation.getLac(); 4050fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka cid = cellLocation.getCid(); 4060fd49b6b31960a768702d202a066b1088ec489a1Alex Yakavenka } 407c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 408c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsCbLocation location; 409c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville switch (header.getGeographicalScope()) { 410c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case SmsCbMessage.GEOGRAPHICAL_SCOPE_LA_WIDE: 411c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville location = new SmsCbLocation(plmn, lac, -1); 412c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 413c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 414c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE: 415c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case SmsCbMessage.GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE: 416c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville location = new SmsCbLocation(plmn, lac, cid); 417c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 418c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 419c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville case SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE: 420c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville default: 421c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville location = new SmsCbLocation(plmn); 422c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville break; 423c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 424c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 425c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville byte[][] pdus; 426c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville int pageCount = header.getNumberOfPages(); 427c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (pageCount > 1) { 428c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Multi-page message 429c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsCbConcatInfo concatInfo = new SmsCbConcatInfo(header, location); 430c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 431c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Try to find other pages of the same message 432c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville pdus = mSmsCbPageMap.get(concatInfo); 433c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 434c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (pdus == null) { 435c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // This is the first page of this message, make room for all 436c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // pages and keep until complete 437c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville pdus = new byte[pageCount][]; 438c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 439c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mSmsCbPageMap.put(concatInfo, pdus); 440c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 441c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 442c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Page parameter is one-based 443c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville pdus[header.getPageIndex() - 1] = receivedPdu; 444c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 445c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville for (int i = 0; i < pdus.length; i++) { 446c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (pdus[i] == null) { 447c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Still missing pages, exit 448c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville return; 449c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 450c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 451c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 452c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Message complete, remove and dispatch 453c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville mSmsCbPageMap.remove(concatInfo); 454c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } else { 455c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Single page message 456c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville pdus = new byte[1][]; 457c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville pdus[0] = receivedPdu; 458c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 459c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 460c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsCbMessage message = GsmSmsCbMessage.createSmsCbMessage(header, location, pdus); 461c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville dispatchBroadcastMessage(message); 462c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 463c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // Remove messages that are out of scope to prevent the map from 464c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // growing indefinitely, containing incomplete messages that were 465c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville // never assembled 466c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Iterator<SmsCbConcatInfo> iter = mSmsCbPageMap.keySet().iterator(); 467c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 468c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville while (iter.hasNext()) { 469c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville SmsCbConcatInfo info = iter.next(); 470c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville 471c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville if (!info.matchesLocation(plmn, lac, cid)) { 472c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville iter.remove(); 473c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 474c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 475c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } catch (RuntimeException e) { 476c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville Log.e(TAG, "Error in decoding SMS CB pdu", e); 477c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 478c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville } 479c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville} 480