1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony;
18
19import java.util.ArrayList;
20
21import android.os.AsyncResult;
22import android.os.Handler;
23import android.os.Looper;
24import android.os.Message;
25import android.util.Log;
26
27
28public class AdnRecordLoader extends Handler {
29    final static String LOG_TAG = "RIL_AdnRecordLoader";
30
31    //***** Instance Variables
32
33    private IccFileHandler mFh;
34    int ef;
35    int extensionEF;
36    int pendingExtLoads;
37    Message userResponse;
38    String pin2;
39
40    // For "load one"
41    int recordNumber;
42
43    // for "load all"
44    ArrayList<AdnRecord> adns; // only valid after EVENT_ADN_LOAD_ALL_DONE
45
46    // Either an AdnRecord or a reference to adns depending
47    // if this is a load one or load all operation
48    Object result;
49
50    //***** Event Constants
51
52    static final int EVENT_ADN_LOAD_DONE = 1;
53    static final int EVENT_EXT_RECORD_LOAD_DONE = 2;
54    static final int EVENT_ADN_LOAD_ALL_DONE = 3;
55    static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4;
56    static final int EVENT_UPDATE_RECORD_DONE = 5;
57
58    //***** Constructor
59
60    public AdnRecordLoader(IccFileHandler fh) {
61        // The telephony unit-test cases may create AdnRecords
62        // in secondary threads
63        super(Looper.getMainLooper());
64        mFh = fh;
65    }
66
67    /**
68     * Resulting AdnRecord is placed in response.obj.result
69     * or response.obj.exception is set
70     */
71    public void
72    loadFromEF(int ef, int extensionEF, int recordNumber,
73                Message response) {
74        this.ef = ef;
75        this.extensionEF = extensionEF;
76        this.recordNumber = recordNumber;
77        this.userResponse = response;
78
79        mFh.loadEFLinearFixed(
80                    ef, recordNumber,
81                    obtainMessage(EVENT_ADN_LOAD_DONE));
82
83    }
84
85
86    /**
87     * Resulting ArrayList&lt;adnRecord> is placed in response.obj.result
88     * or response.obj.exception is set
89     */
90    public void
91    loadAllFromEF(int ef, int extensionEF,
92                Message response) {
93        this.ef = ef;
94        this.extensionEF = extensionEF;
95        this.userResponse = response;
96
97        mFh.loadEFLinearFixedAll(
98                    ef,
99                    obtainMessage(EVENT_ADN_LOAD_ALL_DONE));
100
101    }
102
103    /**
104     * Write adn to a EF SIM record
105     * It will get the record size of EF record and compose hex adn array
106     * then write the hex array to EF record
107     *
108     * @param adn is set with alphaTag and phone number
109     * @param ef EF fileid
110     * @param extensionEF extension EF fileid
111     * @param recordNumber 1-based record index
112     * @param pin2 for CHV2 operations, must be null if pin2 is not needed
113     * @param response will be sent to its handler when completed
114     */
115    public void
116    updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber,
117            String pin2, Message response) {
118        this.ef = ef;
119        this.extensionEF = extensionEF;
120        this.recordNumber = recordNumber;
121        this.userResponse = response;
122        this.pin2 = pin2;
123
124        mFh.getEFLinearRecordSize( ef,
125            obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn));
126    }
127
128    //***** Overridden from Handler
129
130    public void
131    handleMessage(Message msg) {
132        AsyncResult ar;
133        byte data[];
134        AdnRecord adn;
135
136        try {
137            switch (msg.what) {
138                case EVENT_EF_LINEAR_RECORD_SIZE_DONE:
139                    ar = (AsyncResult)(msg.obj);
140                    adn = (AdnRecord)(ar.userObj);
141
142                    if (ar.exception != null) {
143                        throw new RuntimeException("get EF record size failed",
144                                ar.exception);
145                    }
146
147                    int[] recordSize = (int[])ar.result;
148                    // recordSize is int[3] array
149                    // int[0]  is the record length
150                    // int[1]  is the total length of the EF file
151                    // int[2]  is the number of records in the EF file
152                    // So int[0] * int[2] = int[1]
153                   if (recordSize.length != 3 || recordNumber > recordSize[2]) {
154                        throw new RuntimeException("get wrong EF record size format",
155                                ar.exception);
156                    }
157
158                    data = adn.buildAdnString(recordSize[0]);
159
160                    if(data == null) {
161                        throw new RuntimeException("wrong ADN format",
162                                ar.exception);
163                    }
164
165                    mFh.updateEFLinearFixed(ef, recordNumber,
166                            data, pin2, obtainMessage(EVENT_UPDATE_RECORD_DONE));
167
168                    pendingExtLoads = 1;
169
170                    break;
171                case EVENT_UPDATE_RECORD_DONE:
172                    ar = (AsyncResult)(msg.obj);
173                    if (ar.exception != null) {
174                        throw new RuntimeException("update EF adn record failed",
175                                ar.exception);
176                    }
177                    pendingExtLoads = 0;
178                    result = null;
179                    break;
180                case EVENT_ADN_LOAD_DONE:
181                    ar = (AsyncResult)(msg.obj);
182                    data = (byte[])(ar.result);
183
184                    if (ar.exception != null) {
185                        throw new RuntimeException("load failed", ar.exception);
186                    }
187
188                    if (false) {
189                        Log.d(LOG_TAG,"ADN EF: 0x"
190                            + Integer.toHexString(ef)
191                            + ":" + recordNumber
192                            + "\n" + IccUtils.bytesToHexString(data));
193                    }
194
195                    adn = new AdnRecord(ef, recordNumber, data);
196                    result = adn;
197
198                    if (adn.hasExtendedRecord()) {
199                        // If we have a valid value in the ext record field,
200                        // we're not done yet: we need to read the corresponding
201                        // ext record and append it
202
203                        pendingExtLoads = 1;
204
205                        mFh.loadEFLinearFixed(
206                            extensionEF, adn.extRecord,
207                            obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
208                    }
209                break;
210
211                case EVENT_EXT_RECORD_LOAD_DONE:
212                    ar = (AsyncResult)(msg.obj);
213                    data = (byte[])(ar.result);
214                    adn = (AdnRecord)(ar.userObj);
215
216                    if (ar.exception != null) {
217                        throw new RuntimeException("load failed", ar.exception);
218                    }
219
220                    Log.d(LOG_TAG,"ADN extension EF: 0x"
221                        + Integer.toHexString(extensionEF)
222                        + ":" + adn.extRecord
223                        + "\n" + IccUtils.bytesToHexString(data));
224
225                    adn.appendExtRecord(data);
226
227                    pendingExtLoads--;
228                    // result should have been set in
229                    // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE
230                break;
231
232                case EVENT_ADN_LOAD_ALL_DONE:
233                    ar = (AsyncResult)(msg.obj);
234                    ArrayList<byte[]> datas = (ArrayList<byte[]>)(ar.result);
235
236                    if (ar.exception != null) {
237                        throw new RuntimeException("load failed", ar.exception);
238                    }
239
240                    adns = new ArrayList<AdnRecord>(datas.size());
241                    result = adns;
242                    pendingExtLoads = 0;
243
244                    for(int i = 0, s = datas.size() ; i < s ; i++) {
245                        adn = new AdnRecord(ef, 1 + i, datas.get(i));
246                        adns.add(adn);
247
248                        if (adn.hasExtendedRecord()) {
249                            // If we have a valid value in the ext record field,
250                            // we're not done yet: we need to read the corresponding
251                            // ext record and append it
252
253                            pendingExtLoads++;
254
255                            mFh.loadEFLinearFixed(
256                                extensionEF, adn.extRecord,
257                                obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
258                        }
259                    }
260                break;
261            }
262        } catch (RuntimeException exc) {
263            if (userResponse != null) {
264                AsyncResult.forMessage(userResponse)
265                                .exception = exc;
266                userResponse.sendToTarget();
267                // Loading is all or nothing--either every load succeeds
268                // or we fail the whole thing.
269                userResponse = null;
270            }
271            return;
272        }
273
274        if (userResponse != null && pendingExtLoads == 0) {
275            AsyncResult.forMessage(userResponse).result
276                = result;
277
278            userResponse.sendToTarget();
279            userResponse = null;
280        }
281    }
282
283
284}
285