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