CdmaSMSDispatcher.java revision 22d85a8e3a575a6d01d2c788587971657dfe20c6
10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2008 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony.cdma;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.Activity;
217fce994eb223105829becb6c26e3af7a9739752cDianne Hackbornimport android.app.AppOpsManager;
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.PendingIntent.CanceledException;
24b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport android.content.BroadcastReceiver;
25b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport android.content.Context;
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Intent;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.SharedPreferences;
28b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport android.content.res.Resources;
29b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport android.os.Bundle;
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.SystemProperties;
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.preference.PreferenceManager;
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.provider.Telephony.Sms.Intents;
34b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport android.telephony.PhoneNumberUtils;
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.SmsCbMessage;
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.SmsManager;
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.cdma.CdmaSmsCbProgramData;
38b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport android.telephony.cdma.CdmaSmsCbProgramResults;
3999c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Savilleimport android.telephony.Rlog;
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.CommandsInterface;
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.GsmAlphabet;
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.SmsConstants;
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.SMSDispatcher;
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.SmsHeader;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.SmsMessageBase;
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.SmsStorageMonitor;
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.SmsUsageMonitor;
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.TelephonyProperties;
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.WspTypeDecoder;
51b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport com.android.internal.telephony.cdma.sms.BearerData;
52b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.cdma.sms.SmsEnvelope;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.cdma.sms.UserData;
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.ByteArrayOutputStream;
57b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport java.io.DataOutputStream;
58b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport java.io.IOException;
59b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hambyimport java.util.ArrayList;
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Arrays;
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap;
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillefinal class CdmaSMSDispatcher extends SMSDispatcher {
65cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    private static final String TAG = "CdmaSMSDispatcher";
66cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    private static final boolean VDBG = false;
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private byte[] mLastDispatchedSmsFingerprint;
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private byte[] mLastAcknowledgedSmsFingerprint;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final boolean mCheckForDuplicatePortsInOmadmWapPush = Resources.getSystem().getBoolean(
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            com.android.internal.R.bool.config_duplicate_port_omadm_wappush);
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    CdmaSMSDispatcher(CDMAPhone phone, SmsStorageMonitor storageMonitor,
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsUsageMonitor usageMonitor) {
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        super(phone, storageMonitor, usageMonitor);
7722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi.setOnNewCdmaSms(this, EVENT_NEW_SMS, null);
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void dispose() {
8222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi.unSetOnNewCdmaSms(this);
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected String getFormat() {
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return android.telephony.SmsMessage.FORMAT_3GPP2;
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void handleCdmaStatusReport(SmsMessage sms) {
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsTracker tracker = deliveryPendingList.get(i);
9322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville            if (tracker.mMessageRef == sms.mMessageRef) {
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Found it.  Remove from list and broadcast.
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                deliveryPendingList.remove(i);
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                PendingIntent intent = tracker.mDeliveryIntent;
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Intent fillIn = new Intent();
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                fillIn.putExtra("pdu", sms.getPdu());
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                fillIn.putExtra("format", android.telephony.SmsMessage.FORMAT_3GPP2);
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    intent.send(mContext, Activity.RESULT_OK, fillIn);
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;  // Only expect to see one tracker matching this message.
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Dispatch service category program data to the CellBroadcastReceiver app, which filters
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the broadcast alerts to display.
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param sms the SMS message containing one or more
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * {@link android.telephony.cdma.CdmaSmsCbProgramData} objects.
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void handleServiceCategoryProgramData(SmsMessage sms) {
115b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        ArrayList<CdmaSmsCbProgramData> programDataList = sms.getSmsCbProgramData();
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (programDataList == null) {
11799c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville            Rlog.e(TAG, "handleServiceCategoryProgramData: program data list is null!");
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Intent intent = new Intent(Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION);
122b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        intent.putExtra("sender", sms.getOriginatingAddress());
123b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        intent.putParcelableArrayListExtra("program_data", programDataList);
1247fce994eb223105829becb6c26e3af7a9739752cDianne Hackborn        dispatch(intent, RECEIVE_SMS_PERMISSION, AppOpsManager.OP_RECEIVE_SMS, mScpResultsReceiver);
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** {@inheritDoc} */
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int dispatchMessage(SmsMessageBase smsb) {
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // If sms is null, means there was a parsing error.
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (smsb == null) {
13399c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville            Rlog.e(TAG, "dispatchMessage: message is null");
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_GENERIC_ERROR;
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (inEcm.equals("true")) {
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Activity.RESULT_OK;
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mSmsReceiveDisabled) {
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Device doesn't support receiving SMS,
14499c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville            Rlog.d(TAG, "Received short message on device which doesn't support "
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    + "receiving SMS. Ignored.");
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_HANDLED;
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage sms = (SmsMessage) smsb;
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Handle CMAS emergency broadcast messages.
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (SmsEnvelope.MESSAGE_TYPE_BROADCAST == sms.getMessageType()) {
15399c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville            Rlog.d(TAG, "Broadcast type message");
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SmsCbMessage message = sms.parseBroadcastSms();
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (message != null) {
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                dispatchBroadcastMessage(message);
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_HANDLED;
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // See if we have a network duplicate SMS.
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mLastDispatchedSmsFingerprint = sms.getIncomingSmsFingerprint();
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mLastAcknowledgedSmsFingerprint != null &&
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Arrays.equals(mLastDispatchedSmsFingerprint, mLastAcknowledgedSmsFingerprint)) {
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_HANDLED;
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Decode BD stream and set sms variables.
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sms.parseSms();
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int teleService = sms.getTeleService();
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean handled = false;
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((SmsEnvelope.TELESERVICE_VMN == teleService) ||
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                (SmsEnvelope.TELESERVICE_MWI == teleService)) {
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // handling Voicemail
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int voicemailCount = sms.getNumOfVoicemails();
17699c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville            Rlog.d(TAG, "Voicemail count=" + voicemailCount);
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Store the voicemail count in preferences.
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mContext);
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SharedPreferences.Editor editor = sp.edit();
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount);
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            editor.apply();
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPhone.setVoiceMessageWaiting(1, voicemailCount);
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handled = true;
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else if (((SmsEnvelope.TELESERVICE_WMT == teleService) ||
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                (SmsEnvelope.TELESERVICE_WEMT == teleService)) &&
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sms.isStatusReportMessage()) {
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleCdmaStatusReport(sms);
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handled = true;
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else if (SmsEnvelope.TELESERVICE_SCPT == teleService) {
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handleServiceCategoryProgramData(sms);
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handled = true;
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else if ((sms.getUserData() == null)) {
194cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (VDBG) {
19599c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville                Rlog.d(TAG, "Received SMS without user data");
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            handled = true;
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (handled) {
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_HANDLED;
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (!mStorageMonitor.isStorageAvailable() &&
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sms.getMessageClass() != SmsConstants.MessageClass.CLASS_0) {
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // It's a storable message and there's no storage available.  Bail.
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // (See C.S0015-B v2.0 for a description of "Immediate Display"
2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // messages, which we represent as CLASS_0.)
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_OUT_OF_MEMORY;
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (SmsEnvelope.TELESERVICE_WAP == teleService) {
21322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville            return processCdmaWapPdu(sms.getUserData(), sms.mMessageRef,
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sms.getOriginatingAddress());
2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Reject (NAK) any messages with teleservice ids that have
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // not yet been handled and also do not correspond to the two
2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // kinds that are processed below.
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((SmsEnvelope.TELESERVICE_WMT != teleService) &&
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                (SmsEnvelope.TELESERVICE_WEMT != teleService) &&
2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                (SmsEnvelope.MESSAGE_TYPE_BROADCAST != sms.getMessageType())) {
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_UNSUPPORTED;
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return dispatchNormalMessage(smsb);
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Processes inbound messages that are in the WAP-WDP PDU format. See
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * wap-259-wdp-20010614-a section 6.5 for details on the WAP-WDP PDU format.
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * WDP segments are gathered until a datagram completes and gets dispatched.
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param pdu The WAP-WDP PDU segment
235cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville     * @return a result code from {@link android.provider.Telephony.Sms.Intents}, or
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *         {@link Activity#RESULT_OK} if the message has been broadcast
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *         to applications
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected int processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) {
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int index = 0;
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int msgType = (0xFF & pdu[index++]);
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (msgType != 0) {
24499c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville            Rlog.w(TAG, "Received a WAP SMS which is not WDP. Discard.");
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_HANDLED;
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int totalSegments = (0xFF & pdu[index++]);   // >= 1
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int segment = (0xFF & pdu[index++]);         // >= 0
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (segment >= totalSegments) {
25199c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville            Rlog.e(TAG, "WDP bad segment #" + segment + " expecting 0-" + (totalSegments - 1));
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_HANDLED;
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Only the first segment contains sourcePort and destination Port
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int sourcePort = 0;
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int destinationPort = 0;
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (segment == 0) {
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            //process WDP segment
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sourcePort = (0xFF & pdu[index++]) << 8;
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            sourcePort |= 0xFF & pdu[index++];
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            destinationPort = (0xFF & pdu[index++]) << 8;
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            destinationPort |= 0xFF & pdu[index++];
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Some carriers incorrectly send duplicate port fields in omadm wap pushes.
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // If configured, check for that here
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (mCheckForDuplicatePortsInOmadmWapPush) {
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (checkDuplicatePortOmadmWappush(pdu,index)) {
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    index = index + 4; // skip duplicate port fields
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Lookup all other related parts
27499c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville        Rlog.i(TAG, "Received WAP PDU. Type = " + msgType + ", originator = " + address
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + ", src-port = " + sourcePort + ", dst-port = " + destinationPort
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                + ", ID = " + referenceNumber + ", segment# = " + segment + '/' + totalSegments);
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // pass the user data portion of the PDU to the shared handler in SMSDispatcher
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] userData = new byte[pdu.length - index];
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        System.arraycopy(pdu, index, userData, 0, pdu.length - index);
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return processMessagePart(userData, address, referenceNumber, segment, totalSegments,
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                0L, destinationPort, true);
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** {@inheritDoc} */
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendData(String destAddr, String scAddr, int destPort,
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                scAddr, destAddr, destPort, data, (deliveryIntent != null));
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sendSubmitPdu(pdu, sentIntent, deliveryIntent, destAddr);
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** {@inheritDoc} */
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendText(String destAddr, String scAddr, String text,
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent, PendingIntent deliveryIntent) {
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                scAddr, destAddr, text, (deliveryIntent != null), null);
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sendSubmitPdu(pdu, sentIntent, deliveryIntent, destAddr);
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** {@inheritDoc} */
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected GsmAlphabet.TextEncodingDetails calculateLength(CharSequence messageBody,
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean use7bitOnly) {
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return SmsMessage.calculateLength(messageBody, use7bitOnly);
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** {@inheritDoc} */
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendNewSubmitPdu(String destinationAddress, String scAddress,
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String message, SmsHeader smsHeader, int encoding,
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) {
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        UserData uData = new UserData();
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.payloadStr = message;
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.userDataHeader = smsHeader;
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (encoding == SmsConstants.ENCODING_7BIT) {
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else { // assume UTF-16
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            uData.msgEncoding = UserData.ENCODING_UNICODE_16;
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        uData.msgEncodingSet = true;
3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        /* By setting the statusReportRequested bit only for the
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * last message fragment, this will result in only one
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * callback to the sender when that last fragment delivery
3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville         * has been acknowledged. */
3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destinationAddress,
3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                uData, (deliveryIntent != null) && lastPart);
3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sendSubmitPdu(submitPdu, sentIntent, deliveryIntent, destinationAddress);
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendSubmitPdu(SmsMessage.SubmitPdu pdu,
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            PendingIntent sentIntent, PendingIntent deliveryIntent, String destAddr) {
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false)) {
3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (sentIntent != null) {
3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    sentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE);
3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (CanceledException ex) {}
3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
344cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville            if (VDBG) {
34599c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville                Rlog.d(TAG, "Block SMS in Emergency Callback mode");
3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent, destAddr);
3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** {@inheritDoc} */
3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void sendSms(SmsTracker tracker) {
3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        HashMap<String, Object> map = tracker.mData;
3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // byte smsc[] = (byte[]) map.get("smsc");  // unused for CDMA
3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte pdu[] = (byte[]) map.get("pdu");
3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
36122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi.sendCdmaSms(pdu, reply);
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** {@inheritDoc} */
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected void acknowledgeLastIncomingSms(boolean success, int result, Message response) {
3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (inEcm.equals("true")) {
3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int causeCode = resultToCause(result);
37322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi.acknowledgeLastIncomingCdmaSms(success, causeCode, response);
3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (causeCode == 0) {
3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mLastAcknowledgedSmsFingerprint = mLastDispatchedSmsFingerprint;
3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mLastDispatchedSmsFingerprint = null;
3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int resultToCause(int rc) {
3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (rc) {
3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case Activity.RESULT_OK:
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case Intents.RESULT_SMS_HANDLED:
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Cause code is ignored on success.
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return 0;
3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case Intents.RESULT_SMS_OUT_OF_MEMORY:
3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return CommandsInterface.CDMA_SMS_FAIL_CAUSE_RESOURCE_SHORTAGE;
3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case Intents.RESULT_SMS_UNSUPPORTED:
3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return CommandsInterface.CDMA_SMS_FAIL_CAUSE_INVALID_TELESERVICE_ID;
3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case Intents.RESULT_SMS_GENERIC_ERROR:
3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        default:
3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return CommandsInterface.CDMA_SMS_FAIL_CAUSE_ENCODING_PROBLEM;
3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Optional check to see if the received WapPush is an OMADM notification with erroneous
3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * extra port fields.
4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * - Some carriers make this mistake.
4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * ex: MSGTYPE-TotalSegments-CurrentSegment
4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *       -SourcePortDestPort-SourcePortDestPort-OMADM PDU
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param origPdu The WAP-WDP PDU segment
4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param index Current Index while parsing the PDU.
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return True if OrigPdu is OmaDM Push Message which has duplicate ports.
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *         False if OrigPdu is NOT OmaDM Push Message which has duplicate ports.
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean checkDuplicatePortOmadmWappush(byte[] origPdu, int index) {
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        index += 4;
4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] omaPdu = new byte[origPdu.length - index];
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        System.arraycopy(origPdu, index, omaPdu, 0, omaPdu.length);
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        WspTypeDecoder pduDecoder = new WspTypeDecoder(omaPdu);
4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int wspIndex = 2;
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Process header length field
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pduDecoder.decodeUintvarInteger(wspIndex) == false) {
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return false;
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        wspIndex += pduDecoder.getDecodedDataLength(); // advance to next field
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Process content type field
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (pduDecoder.decodeContentType(wspIndex) == false) {
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return false;
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String mimeType = pduDecoder.getValueString();
4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mimeType != null && mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_SYNCML_NOTI)) {
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return true;
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return false;
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
434b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
435b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    // Receiver for Service Category Program Data results.
436b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    // We already ACK'd the original SCPD SMS, so this sends a new response SMS.
437b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    // TODO: handle retries if the RIL returns an error.
438b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    private final BroadcastReceiver mScpResultsReceiver = new BroadcastReceiver() {
439b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        @Override
440b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        public void onReceive(Context context, Intent intent) {
441b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            int rc = getResultCode();
442b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            boolean success = (rc == Activity.RESULT_OK) || (rc == Intents.RESULT_SMS_HANDLED);
443b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            if (!success) {
44499c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville                Rlog.e(TAG, "SCP results error: result code = " + rc);
445b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                return;
446b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            }
447b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            Bundle extras = getResultExtras(false);
448b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            if (extras == null) {
44999c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville                Rlog.e(TAG, "SCP results error: missing extras");
450b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                return;
451b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            }
452b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            String sender = extras.getString("sender");
453b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            if (sender == null) {
45499c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville                Rlog.e(TAG, "SCP results error: missing sender extra.");
455b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                return;
456b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            }
457b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            ArrayList<CdmaSmsCbProgramResults> results
458b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                    = extras.getParcelableArrayList("results");
459b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            if (results == null) {
46099c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville                Rlog.e(TAG, "SCP results error: missing results extra.");
461b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                return;
462b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            }
463b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
464b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            BearerData bData = new BearerData();
465b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            bData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
466b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            bData.messageId = SmsMessage.getNextMessageId();
467b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            bData.serviceCategoryProgramResults = results;
468b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            byte[] encodedBearerData = BearerData.encode(bData);
469b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby
470b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
471b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            DataOutputStream dos = new DataOutputStream(baos);
472b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            try {
473b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.writeInt(SmsEnvelope.TELESERVICE_SCPT);
474b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.writeInt(0); //servicePresent
475b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.writeInt(0); //serviceCategory
476b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
477b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                        PhoneNumberUtils.cdmaCheckAndProcessPlusCode(sender));
478b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(destAddr.digitMode);
479b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(destAddr.numberMode);
480b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(destAddr.ton); // number_type
481b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(destAddr.numberPlan);
482b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(destAddr.numberOfDigits);
483b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
484b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                // Subaddress is not supported.
485b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(0); //subaddressType
486b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(0); //subaddr_odd
487b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(0); //subaddr_nbr_of_digits
488b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(encodedBearerData.length);
489b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                dos.write(encodedBearerData, 0, encodedBearerData.length);
490b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                // Ignore the RIL response. TODO: implement retry if SMS send fails.
49122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville                mCi.sendCdmaSms(baos.toByteArray(), null);
492b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            } catch (IOException e) {
49399c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville                Rlog.e(TAG, "exception creating SCP results PDU", e);
494b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            } finally {
495b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                try {
496b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                    dos.close();
497b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                } catch (IOException ignored) {
498b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby                }
499b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby            }
500b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby        }
501b8a13d300b245e0080aa01275e232f54d5d0e09cJake Hamby    };
5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
503