10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2011 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.gsm;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.app.Activity;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.AsyncResult;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler;
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.provider.Telephony.Sms.Intents;
240d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.PhoneNumberUtils;
25ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Savilleimport android.telephony.Rlog;
260d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport android.telephony.SmsManager;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.CommandsInterface;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.cat.ComprehensionTlvTag;
30d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.IccIoResult;
31d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.IccUtils;
320d4bcdf379842af4b6304809156971e926f374f0Jake Hambyimport com.android.internal.telephony.uicc.UsimServiceTable;
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/**
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Handler for SMS-PP data download messages.
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See 3GPP TS 31.111 section 7.1.1
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class UsimDataDownloadHandler extends Handler {
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String TAG = "UsimDataDownloadHandler";
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** BER-TLV tag for SMS-PP download. TS 31.111 section 9.1. */
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int BER_SMS_PP_DOWNLOAD_TAG      = 0xd1;
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Device identity value for UICC (destination). */
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int DEV_ID_UICC        = 0x81;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Device identity value for network (source). */
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int DEV_ID_NETWORK     = 0x83;
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Message containing new SMS-PP message to process. */
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_START_DATA_DOWNLOAD = 1;
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Response to SMS-PP download envelope command. */
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_ENVELOPE_RESPONSE = 2;
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
560d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /** Result of writing SM to UICC (when SMS-PP service is not available). */
570d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    private static final int EVENT_WRITE_SMS_COMPLETE = 3;
580d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
5922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville    private final CommandsInterface mCi;
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public UsimDataDownloadHandler(CommandsInterface commandsInterface) {
6222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi = commandsInterface;
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
660d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * Handle SMS-PP data download messages. Normally these are automatically handled by the
670d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * radio, but we may have to deal with this type of SM arriving via the IMS stack. If the
680d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * data download service is not enabled, try to write to the USIM as an SMS, and send the
690d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * UICC response as the acknowledgment to the SMSC.
700d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     *
710d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param ust the UsimServiceTable, to check if data download is enabled
720d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @param smsMessage the SMS message to process
730d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @return {@code Activity.RESULT_OK} on success; {@code RESULT_SMS_GENERIC_ERROR} on failure
740d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     */
750d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    int handleUsimDataDownload(UsimServiceTable ust, SmsMessage smsMessage) {
760d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        // If we receive an SMS-PP message before the UsimServiceTable has been loaded,
770d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        // assume that the data download service is not present. This is very unlikely to
780d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        // happen because the IMS connection will not be established until after the ISIM
790d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        // records have been loaded, after the USIM service table has been loaded.
800d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        if (ust != null && ust.isAvailable(
810d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                UsimServiceTable.UsimService.DATA_DL_VIA_SMS_PP)) {
820d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            Rlog.d(TAG, "Received SMS-PP data download, sending to UICC.");
830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            return startDataDownload(smsMessage);
840d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        } else {
850d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            Rlog.d(TAG, "DATA_DL_VIA_SMS_PP service not available, storing message to UICC.");
860d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            String smsc = IccUtils.bytesToHexString(
870d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
880d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                            smsMessage.getServiceCenterAddress()));
890d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            mCi.writeSmsToSim(SmsManager.STATUS_ON_ICC_UNREAD, smsc,
900d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    IccUtils.bytesToHexString(smsMessage.getPdu()),
910d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    obtainMessage(EVENT_WRITE_SMS_COMPLETE));
920d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            return Activity.RESULT_OK;  // acknowledge after response from write to USIM
930d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        }
940d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
950d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    }
960d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
970d4bcdf379842af4b6304809156971e926f374f0Jake Hamby    /**
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Start an SMS-PP data download for the specified message. Can be called from a different
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * thread than this Handler is running on.
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param smsMessage the message to process
1020d4bcdf379842af4b6304809156971e926f374f0Jake Hamby     * @return {@code Activity.RESULT_OK} on success; {@code RESULT_SMS_GENERIC_ERROR} on failure
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int startDataDownload(SmsMessage smsMessage) {
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (sendMessage(obtainMessage(EVENT_START_DATA_DOWNLOAD, smsMessage))) {
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Activity.RESULT_OK;  // we will send SMS ACK/ERROR based on UICC response
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
108ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "startDataDownload failed to send message to start data download.");
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_GENERIC_ERROR;
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void handleDataDownload(SmsMessage smsMessage) {
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dcs = smsMessage.getDataCodingScheme();
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int pid = smsMessage.getProtocolIdentifier();
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] pdu = smsMessage.getPdu();           // includes SC address
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int scAddressLength = pdu[0] & 0xff;
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int tpduIndex = scAddressLength + 1;        // start of TPDU
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int tpduLength = pdu.length - tpduIndex;
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int bodyLength = getEnvelopeBodyLength(scAddressLength, tpduLength);
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Add 1 byte for SMS-PP download tag and 1-2 bytes for BER-TLV length.
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // See ETSI TS 102 223 Annex C for encoding of length and tags.
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int totalLength = bodyLength + 1 + (bodyLength > 127 ? 2 : 1);
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] envelope = new byte[totalLength];
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int index = 0;
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // SMS-PP download tag and length (assumed to be < 256 bytes).
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) BER_SMS_PP_DOWNLOAD_TAG;
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (bodyLength > 127) {
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            envelope[index++] = (byte) 0x81;    // length 128-255 encoded as 0x81 + length
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) bodyLength;
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Device identities TLV
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value());
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) 2;
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) DEV_ID_NETWORK;
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) DEV_ID_UICC;
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Address TLV (if present). Encoded length is assumed to be < 127 bytes.
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (scAddressLength != 0) {
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            envelope[index++] = (byte) ComprehensionTlvTag.ADDRESS.value();
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            envelope[index++] = (byte) scAddressLength;
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            System.arraycopy(pdu, 1, envelope, index, scAddressLength);
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            index += scAddressLength;
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // SMS TPDU TLV. Length is assumed to be < 256 bytes.
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.SMS_TPDU.value());
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (tpduLength > 127) {
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            envelope[index++] = (byte) 0x81;    // length 128-255 encoded as 0x81 + length
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) tpduLength;
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        System.arraycopy(pdu, tpduIndex, envelope, index, tpduLength);
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        index += tpduLength;
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Verify that we calculated the payload size correctly.
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (index != envelope.length) {
163ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "startDataDownload() calculated incorrect envelope length, aborting.");
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR);
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String encodedEnvelope = IccUtils.bytesToHexString(envelope);
16922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi.sendEnvelopeWithStatus(encodedEnvelope, obtainMessage(
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                EVENT_SEND_ENVELOPE_RESPONSE, new int[]{ dcs, pid }));
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Return the size in bytes of the envelope to send to the UICC, excluding the
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS-PP download tag byte and length byte(s). If the size returned is <= 127,
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the BER-TLV length will be encoded in 1 byte, otherwise 2 bytes are required.
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddressLength the length of the SMSC address, or zero if not present
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tpduLength the length of the TPDU from the SMS-PP message
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the number of bytes to allocate for the envelope command
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int getEnvelopeBodyLength(int scAddressLength, int tpduLength) {
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Add 4 bytes for device identities TLV + 1 byte for SMS TPDU tag byte
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int length = tpduLength + 5;
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Add 1 byte for TPDU length, or 2 bytes if length > 127
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        length += (tpduLength > 127 ? 2 : 1);
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Add length of address tag, if present (+ 2 bytes for tag and length)
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (scAddressLength != 0) {
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            length = length + 2 + scAddressLength;
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return length;
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handle the response to the ENVELOPE command.
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param response UICC response encoded as hexadecimal digits. First two bytes are the
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  UICC SW1 and SW2 status bytes.
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void sendSmsAckForEnvelopeResponse(IccIoResult response, int dcs, int pid) {
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int sw1 = response.sw1;
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int sw2 = response.sw2;
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean success;
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) {
205ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.d(TAG, "USIM data download succeeded: " + response.toString());
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            success = true;
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else if (sw1 == 0x93 && sw2 == 0x00) {
208ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "USIM data download failed: Toolkit busy");
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY);
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else if (sw1 == 0x62 || sw1 == 0x63) {
212ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "USIM data download failed: " + response.toString());
2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            success = false;
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
215ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(TAG, "Unexpected SW1/SW2 response from UICC: " + response.toString());
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            success = false;
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] responseBytes = response.payload;
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (responseBytes == null || responseBytes.length == 0) {
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (success) {
22222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville                mCi.acknowledgeLastIncomingGsmSms(true, 0, null);
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                acknowledgeSmsWithError(
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] smsAckPdu;
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int index = 0;
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (success) {
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu = new byte[responseBytes.length + 5];
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = 0x00;      // TP-MTI, TP-UDHI
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = 0x07;      // TP-PI: TP-PID, TP-DCS, TP-UDL present
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu = new byte[responseBytes.length + 6];
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = 0x00;      // TP-MTI, TP-UDHI
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = (byte)
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR;  // TP-FCS
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = 0x07;      // TP-PI: TP-PID, TP-DCS, TP-UDL present
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        smsAckPdu[index++] = (byte) pid;
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        smsAckPdu[index++] = (byte) dcs;
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (is7bitDcs(dcs)) {
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int septetCount = responseBytes.length * 8 / 7;
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = (byte) septetCount;
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = (byte) responseBytes.length;
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        System.arraycopy(responseBytes, 0, smsAckPdu, index, responseBytes.length);
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
25622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi.acknowledgeIncomingGsmSmsWithPdu(success,
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                IccUtils.bytesToHexString(smsAckPdu), null);
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void acknowledgeSmsWithError(int cause) {
26122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville        mCi.acknowledgeLastIncomingGsmSms(false, cause, null);
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns whether the DCS is 7 bit. If so, set TP-UDL to the septet count of TP-UD;
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * otherwise, set TP-UDL to the octet count of TP-UD.
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param dcs the TP-Data-Coding-Scheme field from the original download SMS
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the DCS specifies 7 bit encoding; false otherwise
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean is7bitDcs(int dcs) {
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // See 3GPP TS 23.038 section 4
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ((dcs & 0x8C) == 0x00) || ((dcs & 0xF4) == 0xF0);
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handle UICC envelope response and send SMS acknowledgement.
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg the message to handle
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
2820d4bcdf379842af4b6304809156971e926f374f0Jake Hamby        AsyncResult ar;
2830d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msg.what) {
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case EVENT_START_DATA_DOWNLOAD:
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleDataDownload((SmsMessage) msg.obj);
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case EVENT_SEND_ENVELOPE_RESPONSE:
2900d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                ar = (AsyncResult) msg.obj;
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ar.exception != null) {
293ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(TAG, "UICC Send Envelope failure, exception: " + ar.exception);
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    acknowledgeSmsWithError(
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    return;
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int[] dcsPid = (int[]) ar.userObj;
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSmsAckForEnvelopeResponse((IccIoResult) ar.result, dcsPid[0], dcsPid[1]);
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3030d4bcdf379842af4b6304809156971e926f374f0Jake Hamby            case EVENT_WRITE_SMS_COMPLETE:
3040d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                ar = (AsyncResult) msg.obj;
3050d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                if (ar.exception == null) {
3060d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    Rlog.d(TAG, "Successfully wrote SMS-PP message to UICC");
3070d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    mCi.acknowledgeLastIncomingGsmSms(true, 0, null);
3080d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                } else {
3090d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    Rlog.d(TAG, "Failed to write SMS-PP message to UICC", ar.exception);
3100d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                    mCi.acknowledgeLastIncomingGsmSms(false,
3110d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                            CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR, null);
3120d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                }
3130d4bcdf379842af4b6304809156971e926f374f0Jake Hamby                break;
3140d4bcdf379842af4b6304809156971e926f374f0Jake Hamby
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            default:
316ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.e(TAG, "Ignoring unexpected message, what=" + msg.what);
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
320