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