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;
240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.Log;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.CommandsInterface;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.IccIoResult;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.IccUtils;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.cat.ComprehensionTlvTag;
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/**
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Handler for SMS-PP data download messages.
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See 3GPP TS 31.111 section 7.1.1
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class UsimDataDownloadHandler extends Handler {
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String TAG = "UsimDataDownloadHandler";
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** BER-TLV tag for SMS-PP download. TS 31.111 section 9.1. */
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int BER_SMS_PP_DOWNLOAD_TAG      = 0xd1;
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Device identity value for UICC (destination). */
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int DEV_ID_UICC        = 0x81;
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Device identity value for network (source). */
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int DEV_ID_NETWORK     = 0x83;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Message containing new SMS-PP message to process. */
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_START_DATA_DOWNLOAD = 1;
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /** Response to SMS-PP download envelope command. */
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_SEND_ENVELOPE_RESPONSE = 2;
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private final CommandsInterface mCI;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public UsimDataDownloadHandler(CommandsInterface commandsInterface) {
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mCI = commandsInterface;
570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Start an SMS-PP data download for the specified message. Can be called from a different
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * thread than this Handler is running on.
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param smsMessage the message to process
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return Activity.RESULT_OK on success; Intents.RESULT_SMS_GENERIC_ERROR on failure
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int startDataDownload(SmsMessage smsMessage) {
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (sendMessage(obtainMessage(EVENT_START_DATA_DOWNLOAD, smsMessage))) {
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Activity.RESULT_OK;  // we will send SMS ACK/ERROR based on UICC response
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(TAG, "startDataDownload failed to send message to start data download.");
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return Intents.RESULT_SMS_GENERIC_ERROR;
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void handleDataDownload(SmsMessage smsMessage) {
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int dcs = smsMessage.getDataCodingScheme();
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int pid = smsMessage.getProtocolIdentifier();
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] pdu = smsMessage.getPdu();           // includes SC address
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int scAddressLength = pdu[0] & 0xff;
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int tpduIndex = scAddressLength + 1;        // start of TPDU
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int tpduLength = pdu.length - tpduIndex;
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int bodyLength = getEnvelopeBodyLength(scAddressLength, tpduLength);
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Add 1 byte for SMS-PP download tag and 1-2 bytes for BER-TLV length.
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // See ETSI TS 102 223 Annex C for encoding of length and tags.
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int totalLength = bodyLength + 1 + (bodyLength > 127 ? 2 : 1);
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] envelope = new byte[totalLength];
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int index = 0;
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // SMS-PP download tag and length (assumed to be < 256 bytes).
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) BER_SMS_PP_DOWNLOAD_TAG;
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (bodyLength > 127) {
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            envelope[index++] = (byte) 0x81;    // length 128-255 encoded as 0x81 + length
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) bodyLength;
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Device identities TLV
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value());
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) 2;
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) DEV_ID_NETWORK;
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) DEV_ID_UICC;
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Address TLV (if present). Encoded length is assumed to be < 127 bytes.
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (scAddressLength != 0) {
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            envelope[index++] = (byte) ComprehensionTlvTag.ADDRESS.value();
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            envelope[index++] = (byte) scAddressLength;
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            System.arraycopy(pdu, 1, envelope, index, scAddressLength);
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            index += scAddressLength;
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // SMS TPDU TLV. Length is assumed to be < 256 bytes.
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.SMS_TPDU.value());
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (tpduLength > 127) {
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            envelope[index++] = (byte) 0x81;    // length 128-255 encoded as 0x81 + length
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        envelope[index++] = (byte) tpduLength;
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        System.arraycopy(pdu, tpduIndex, envelope, index, tpduLength);
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        index += tpduLength;
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Verify that we calculated the payload size correctly.
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (index != envelope.length) {
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(TAG, "startDataDownload() calculated incorrect envelope length, aborting.");
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR);
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String encodedEnvelope = IccUtils.bytesToHexString(envelope);
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mCI.sendEnvelopeWithStatus(encodedEnvelope, obtainMessage(
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                EVENT_SEND_ENVELOPE_RESPONSE, new int[]{ dcs, pid }));
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Return the size in bytes of the envelope to send to the UICC, excluding the
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * SMS-PP download tag byte and length byte(s). If the size returned is <= 127,
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * the BER-TLV length will be encoded in 1 byte, otherwise 2 bytes are required.
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param scAddressLength the length of the SMSC address, or zero if not present
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tpduLength the length of the TPDU from the SMS-PP message
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return the number of bytes to allocate for the envelope command
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static int getEnvelopeBodyLength(int scAddressLength, int tpduLength) {
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Add 4 bytes for device identities TLV + 1 byte for SMS TPDU tag byte
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int length = tpduLength + 5;
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Add 1 byte for TPDU length, or 2 bytes if length > 127
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        length += (tpduLength > 127 ? 2 : 1);
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Add length of address tag, if present (+ 2 bytes for tag and length)
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (scAddressLength != 0) {
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            length = length + 2 + scAddressLength;
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return length;
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handle the response to the ENVELOPE command.
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param response UICC response encoded as hexadecimal digits. First two bytes are the
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *  UICC SW1 and SW2 status bytes.
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void sendSmsAckForEnvelopeResponse(IccIoResult response, int dcs, int pid) {
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int sw1 = response.sw1;
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int sw2 = response.sw2;
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        boolean success;
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) {
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.d(TAG, "USIM data download succeeded: " + response.toString());
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            success = true;
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else if (sw1 == 0x93 && sw2 == 0x00) {
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(TAG, "USIM data download failed: Toolkit busy");
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY);
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else if (sw1 == 0x62 || sw1 == 0x63) {
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(TAG, "USIM data download failed: " + response.toString());
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            success = false;
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(TAG, "Unexpected SW1/SW2 response from UICC: " + response.toString());
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            success = false;
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] responseBytes = response.payload;
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (responseBytes == null || responseBytes.length == 0) {
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (success) {
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mCI.acknowledgeLastIncomingGsmSms(true, 0, null);
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                acknowledgeSmsWithError(
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] smsAckPdu;
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int index = 0;
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (success) {
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu = new byte[responseBytes.length + 5];
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = 0x00;      // TP-MTI, TP-UDHI
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = 0x07;      // TP-PI: TP-PID, TP-DCS, TP-UDL present
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu = new byte[responseBytes.length + 6];
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = 0x00;      // TP-MTI, TP-UDHI
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = (byte)
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR;  // TP-FCS
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = 0x07;      // TP-PI: TP-PID, TP-DCS, TP-UDL present
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        smsAckPdu[index++] = (byte) pid;
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        smsAckPdu[index++] = (byte) dcs;
2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (is7bitDcs(dcs)) {
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int septetCount = responseBytes.length * 8 / 7;
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = (byte) septetCount;
2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } else {
2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            smsAckPdu[index++] = (byte) responseBytes.length;
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        System.arraycopy(responseBytes, 0, smsAckPdu, index, responseBytes.length);
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mCI.acknowledgeIncomingGsmSmsWithPdu(success,
2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                IccUtils.bytesToHexString(smsAckPdu), null);
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void acknowledgeSmsWithError(int cause) {
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mCI.acknowledgeLastIncomingGsmSms(false, cause, null);
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Returns whether the DCS is 7 bit. If so, set TP-UDL to the septet count of TP-UD;
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * otherwise, set TP-UDL to the octet count of TP-UD.
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param dcs the TP-Data-Coding-Scheme field from the original download SMS
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return true if the DCS specifies 7 bit encoding; false otherwise
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static boolean is7bitDcs(int dcs) {
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // See 3GPP TS 23.038 section 4
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return ((dcs & 0x8C) == 0x00) || ((dcs & 0xF4) == 0xF0);
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Handle UICC envelope response and send SMS acknowledgement.
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param msg the message to handle
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch (msg.what) {
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case EVENT_START_DATA_DOWNLOAD:
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                handleDataDownload((SmsMessage) msg.obj);
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case EVENT_SEND_ENVELOPE_RESPONSE:
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                AsyncResult ar = (AsyncResult) msg.obj;
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (ar.exception != null) {
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Log.e(TAG, "UICC Send Envelope failure, exception: " + ar.exception);
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    acknowledgeSmsWithError(
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    return;
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int[] dcsPid = (int[]) ar.userObj;
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                sendSmsAckForEnvelopeResponse((IccIoResult) ar.result, dcsPid[0], dcsPid[1]);
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            default:
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Log.e(TAG, "Ignoring unexpected message, what=" + msg.what);
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
268