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 
17 package com.android.internal.telephony.uicc;
18 
19 import java.util.ArrayList;
20 
21 import android.os.AsyncResult;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.Message;
25 import android.telephony.Rlog;
26 
27 public class AdnRecordLoader extends Handler {
28     final static String LOG_TAG = "AdnRecordLoader";
29     final static boolean VDBG = false;
30 
31     //***** Instance Variables
32 
33     private IccFileHandler mFh;
34     int mEf;
35     int mExtensionEF;
36     int mPendingExtLoads;
37     Message mUserResponse;
38     String mPin2;
39 
40     // For "load one"
41     int mRecordNumber;
42 
43     // for "load all"
44     ArrayList<AdnRecord> mAdns; // 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 mResult;
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 
AdnRecordLoader(IccFileHandler fh)60     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
loadFromEF(int ef, int extensionEF, int recordNumber, Message response)72     loadFromEF(int ef, int extensionEF, int recordNumber,
73                 Message response) {
74         mEf = ef;
75         mExtensionEF = extensionEF;
76         mRecordNumber = recordNumber;
77         mUserResponse = 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
loadAllFromEF(int ef, int extensionEF, Message response)91     loadAllFromEF(int ef, int extensionEF,
92                 Message response) {
93         mEf = ef;
94         mExtensionEF = extensionEF;
95         mUserResponse = 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
updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber, String pin2, Message response)116     updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber,
117             String pin2, Message response) {
118         mEf = ef;
119         mExtensionEF = extensionEF;
120         mRecordNumber = recordNumber;
121         mUserResponse = response;
122         mPin2 = pin2;
123 
124         mFh.getEFLinearRecordSize( ef,
125             obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn));
126     }
127 
128     //***** Overridden from Handler
129 
130     @Override
131     public void
handleMessage(Message msg)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 || mRecordNumber > 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                     mFh.updateEFLinearFixed(mEf, mRecordNumber,
167                             data, mPin2, obtainMessage(EVENT_UPDATE_RECORD_DONE));
168 
169                     mPendingExtLoads = 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                     mPendingExtLoads = 0;
179                     mResult = 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 (VDBG) {
190                         Rlog.d(LOG_TAG,"ADN EF: 0x"
191                             + Integer.toHexString(mEf)
192                             + ":" + mRecordNumber
193                             + "\n" + IccUtils.bytesToHexString(data));
194                     }
195 
196                     adn = new AdnRecord(mEf, mRecordNumber, data);
197                     mResult = 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                         mPendingExtLoads = 1;
205 
206                         mFh.loadEFLinearFixed(
207                             mExtensionEF, adn.mExtRecord,
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                     Rlog.d(LOG_TAG,"ADN extension EF: 0x"
222                         + Integer.toHexString(mExtensionEF)
223                         + ":" + adn.mExtRecord
224                         + "\n" + IccUtils.bytesToHexString(data));
225 
226                     adn.appendExtRecord(data);
227 
228                     mPendingExtLoads--;
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                     mAdns = new ArrayList<AdnRecord>(datas.size());
242                     mResult = mAdns;
243                     mPendingExtLoads = 0;
244 
245                     for(int i = 0, s = datas.size() ; i < s ; i++) {
246                         adn = new AdnRecord(mEf, 1 + i, datas.get(i));
247                         mAdns.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                             mPendingExtLoads++;
255 
256                             mFh.loadEFLinearFixed(
257                                 mExtensionEF, adn.mExtRecord,
258                                 obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
259                         }
260                     }
261                 break;
262             }
263         } catch (RuntimeException exc) {
264             if (mUserResponse != null) {
265                 AsyncResult.forMessage(mUserResponse)
266                                 .exception = exc;
267                 mUserResponse.sendToTarget();
268                 // Loading is all or nothing--either every load succeeds
269                 // or we fail the whole thing.
270                 mUserResponse = null;
271             }
272             return;
273         }
274 
275         if (mUserResponse != null && mPendingExtLoads == 0) {
276             AsyncResult.forMessage(mUserResponse).result
277                 = mResult;
278 
279             mUserResponse.sendToTarget();
280             mUserResponse = null;
281         }
282     }
283 
284 
285 }
286