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