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 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 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<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 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 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 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