1ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby/*
2ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * Copyright (C) 2011 The Android Open Source Project
3ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby *
4ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * Licensed under the Apache License, Version 2.0 (the "License");
5ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * you may not use this file except in compliance with the License.
6ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * You may obtain a copy of the License at
7ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby *
8ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby *      http://www.apache.org/licenses/LICENSE-2.0
9ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby *
10ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * Unless required by applicable law or agreed to in writing, software
11ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * distributed under the License is distributed on an "AS IS" BASIS,
12ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * See the License for the specific language governing permissions and
14ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * limitations under the License.
15ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby */
16ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
17ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambypackage com.android.internal.telephony.gsm;
18ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
19ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport android.app.Activity;
20ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport android.os.AsyncResult;
21ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport android.os.Handler;
22ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport android.os.Message;
23ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport android.provider.Telephony.Sms.Intents;
24ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport android.util.Log;
25ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
26ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport com.android.internal.telephony.CommandsInterface;
27ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport com.android.internal.telephony.IccIoResult;
28ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport com.android.internal.telephony.IccUtils;
29ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambyimport com.android.internal.telephony.cat.ComprehensionTlvTag;
30ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
31ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby/**
32ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * Handler for SMS-PP data download messages.
33ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby * See 3GPP TS 31.111 section 7.1.1
34ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby */
35ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hambypublic class UsimDataDownloadHandler extends Handler {
36ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private static final String TAG = "UsimDataDownloadHandler";
37ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
38ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /** BER-TLV tag for SMS-PP download. TS 31.111 section 9.1. */
39ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private static final int BER_SMS_PP_DOWNLOAD_TAG      = 0xd1;
40ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
41ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /** Device identity value for UICC (destination). */
42ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private static final int DEV_ID_UICC        = 0x81;
43ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
44ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /** Device identity value for network (source). */
45ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private static final int DEV_ID_NETWORK     = 0x83;
46ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
47ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /** Message containing new SMS-PP message to process. */
48ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private static final int EVENT_START_DATA_DOWNLOAD = 1;
49ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
50ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /** Response to SMS-PP download envelope command. */
51ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private static final int EVENT_SEND_ENVELOPE_RESPONSE = 2;
52ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
53ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private final CommandsInterface mCI;
54ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
55ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    public UsimDataDownloadHandler(CommandsInterface commandsInterface) {
56ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        mCI = commandsInterface;
57ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    }
58ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
59ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /**
60ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * Start an SMS-PP data download for the specified message. Can be called from a different
61ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * thread than this Handler is running on.
62ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     *
63ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @param smsMessage the message to process
64ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @return Activity.RESULT_OK on success; Intents.RESULT_SMS_GENERIC_ERROR on failure
65ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     */
66ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    public int startDataDownload(SmsMessage smsMessage) {
67ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (sendMessage(obtainMessage(EVENT_START_DATA_DOWNLOAD, smsMessage))) {
68ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            return Activity.RESULT_OK;  // we will send SMS ACK/ERROR based on UICC response
69ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        } else {
70ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            Log.e(TAG, "startDataDownload failed to send message to start data download.");
71ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            return Intents.RESULT_SMS_GENERIC_ERROR;
72ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
73ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    }
74ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
75ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private void handleDataDownload(SmsMessage smsMessage) {
76ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int dcs = smsMessage.getDataCodingScheme();
77ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int pid = smsMessage.getProtocolIdentifier();
78ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        byte[] pdu = smsMessage.getPdu();           // includes SC address
79ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
80ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int scAddressLength = pdu[0] & 0xff;
81ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int tpduIndex = scAddressLength + 1;        // start of TPDU
82ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int tpduLength = pdu.length - tpduIndex;
83ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
84ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int bodyLength = getEnvelopeBodyLength(scAddressLength, tpduLength);
85ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
86ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // Add 1 byte for SMS-PP download tag and 1-2 bytes for BER-TLV length.
87ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // See ETSI TS 102 223 Annex C for encoding of length and tags.
88ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int totalLength = bodyLength + 1 + (bodyLength > 127 ? 2 : 1);
89ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
90ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        byte[] envelope = new byte[totalLength];
91ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int index = 0;
92ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
93ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // SMS-PP download tag and length (assumed to be < 256 bytes).
94ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        envelope[index++] = (byte) BER_SMS_PP_DOWNLOAD_TAG;
95ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (bodyLength > 127) {
96ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            envelope[index++] = (byte) 0x81;    // length 128-255 encoded as 0x81 + length
97ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
98ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        envelope[index++] = (byte) bodyLength;
99ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
100ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // Device identities TLV
101ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value());
102ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        envelope[index++] = (byte) 2;
103ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        envelope[index++] = (byte) DEV_ID_NETWORK;
104ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        envelope[index++] = (byte) DEV_ID_UICC;
105ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
106ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // Address TLV (if present). Encoded length is assumed to be < 127 bytes.
107ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (scAddressLength != 0) {
108ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            envelope[index++] = (byte) ComprehensionTlvTag.ADDRESS.value();
109ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            envelope[index++] = (byte) scAddressLength;
110ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            System.arraycopy(pdu, 1, envelope, index, scAddressLength);
111ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            index += scAddressLength;
112ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
113ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
114ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // SMS TPDU TLV. Length is assumed to be < 256 bytes.
115ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.SMS_TPDU.value());
116ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (tpduLength > 127) {
117ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            envelope[index++] = (byte) 0x81;    // length 128-255 encoded as 0x81 + length
118ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
119ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        envelope[index++] = (byte) tpduLength;
120ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        System.arraycopy(pdu, tpduIndex, envelope, index, tpduLength);
121ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        index += tpduLength;
122ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
123ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // Verify that we calculated the payload size correctly.
124ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (index != envelope.length) {
125ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            Log.e(TAG, "startDataDownload() calculated incorrect envelope length, aborting.");
126ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR);
127ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            return;
128ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
129ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
130ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        String encodedEnvelope = IccUtils.bytesToHexString(envelope);
131ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        mCI.sendEnvelopeWithStatus(encodedEnvelope, obtainMessage(
132ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                EVENT_SEND_ENVELOPE_RESPONSE, new int[]{ dcs, pid }));
133ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    }
134ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
135ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /**
136ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * Return the size in bytes of the envelope to send to the UICC, excluding the
137ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * SMS-PP download tag byte and length byte(s). If the size returned is <= 127,
138ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * the BER-TLV length will be encoded in 1 byte, otherwise 2 bytes are required.
139ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     *
140ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @param scAddressLength the length of the SMSC address, or zero if not present
141ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @param tpduLength the length of the TPDU from the SMS-PP message
142ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @return the number of bytes to allocate for the envelope command
143ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     */
144ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private static int getEnvelopeBodyLength(int scAddressLength, int tpduLength) {
145ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // Add 4 bytes for device identities TLV + 1 byte for SMS TPDU tag byte
146ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int length = tpduLength + 5;
147ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // Add 1 byte for TPDU length, or 2 bytes if length > 127
148ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        length += (tpduLength > 127 ? 2 : 1);
149ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // Add length of address tag, if present (+ 2 bytes for tag and length)
150ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (scAddressLength != 0) {
151ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            length = length + 2 + scAddressLength;
152ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
153ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        return length;
154ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    }
155ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
156ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /**
157ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * Handle the response to the ENVELOPE command.
158ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @param response UICC response encoded as hexadecimal digits. First two bytes are the
159ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     *  UICC SW1 and SW2 status bytes.
160ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     */
161ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private void sendSmsAckForEnvelopeResponse(IccIoResult response, int dcs, int pid) {
162ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int sw1 = response.sw1;
163ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int sw2 = response.sw2;
164ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
165ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        boolean success;
166ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) {
167ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            Log.d(TAG, "USIM data download succeeded: " + response.toString());
168ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            success = true;
169ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        } else if (sw1 == 0x93 && sw2 == 0x00) {
170ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            Log.e(TAG, "USIM data download failed: Toolkit busy");
171ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY);
172ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            return;
173ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        } else if (sw1 == 0x62 || sw1 == 0x63) {
174ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            Log.e(TAG, "USIM data download failed: " + response.toString());
175ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            success = false;
176ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        } else {
177ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            Log.e(TAG, "Unexpected SW1/SW2 response from UICC: " + response.toString());
178ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            success = false;
179ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
180ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
181ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        byte[] responseBytes = response.payload;
182ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (responseBytes == null || responseBytes.length == 0) {
183ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            if (success) {
184ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                mCI.acknowledgeLastIncomingGsmSms(true, 0, null);
185ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            } else {
186ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                acknowledgeSmsWithError(
187ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                        CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
188ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            }
189ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            return;
190ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
191ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
192ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        byte[] smsAckPdu;
193ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        int index = 0;
194ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (success) {
195ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu = new byte[responseBytes.length + 5];
196ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu[index++] = 0x00;      // TP-MTI, TP-UDHI
197ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu[index++] = 0x07;      // TP-PI: TP-PID, TP-DCS, TP-UDL present
198ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        } else {
199ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu = new byte[responseBytes.length + 6];
200ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu[index++] = 0x00;      // TP-MTI, TP-UDHI
201ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu[index++] = (byte)
202ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                    CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR;  // TP-FCS
203ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu[index++] = 0x07;      // TP-PI: TP-PID, TP-DCS, TP-UDL present
204ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
205ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
206ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        smsAckPdu[index++] = (byte) pid;
207ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        smsAckPdu[index++] = (byte) dcs;
208ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
209ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        if (is7bitDcs(dcs)) {
210ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            int septetCount = responseBytes.length * 8 / 7;
211ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu[index++] = (byte) septetCount;
212ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        } else {
213ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            smsAckPdu[index++] = (byte) responseBytes.length;
214ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
215ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
216ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        System.arraycopy(responseBytes, 0, smsAckPdu, index, responseBytes.length);
217ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
218ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        mCI.acknowledgeIncomingGsmSmsWithPdu(success,
219ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                IccUtils.bytesToHexString(smsAckPdu), null);
220ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    }
221ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
222ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private void acknowledgeSmsWithError(int cause) {
223ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        mCI.acknowledgeLastIncomingGsmSms(false, cause, null);
224ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    }
225ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
226ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /**
227ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * Returns whether the DCS is 7 bit. If so, set TP-UDL to the septet count of TP-UD;
228ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * otherwise, set TP-UDL to the octet count of TP-UD.
229ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @param dcs the TP-Data-Coding-Scheme field from the original download SMS
230ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @return true if the DCS specifies 7 bit encoding; false otherwise
231ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     */
232ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    private static boolean is7bitDcs(int dcs) {
233ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        // See 3GPP TS 23.038 section 4
234ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        return ((dcs & 0x8C) == 0x00) || ((dcs & 0xF4) == 0xF0);
235ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    }
236ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
237ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    /**
238ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * Handle UICC envelope response and send SMS acknowledgement.
239ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     *
240ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     * @param msg the message to handle
241ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby     */
242ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    @Override
243ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    public void handleMessage(Message msg) {
244ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        switch (msg.what) {
245ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            case EVENT_START_DATA_DOWNLOAD:
246ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                handleDataDownload((SmsMessage) msg.obj);
247ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                break;
248ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
249ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            case EVENT_SEND_ENVELOPE_RESPONSE:
250ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                AsyncResult ar = (AsyncResult) msg.obj;
251ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
252ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                if (ar.exception != null) {
253ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                    Log.e(TAG, "UICC Send Envelope failure, exception: " + ar.exception);
254ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                    acknowledgeSmsWithError(
255ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                            CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
256ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                    return;
257ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                }
258ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
259ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                int[] dcsPid = (int[]) ar.userObj;
260ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                sendSmsAckForEnvelopeResponse((IccIoResult) ar.result, dcsPid[0], dcsPid[1]);
261ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                break;
262ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby
263ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby            default:
264ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby                Log.e(TAG, "Ignoring unexpected message, what=" + msg.what);
265ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby        }
266ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby    }
267ac09d2af145b4d820a34f5e7628bc42e2e211bdbJake Hamby}
268