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; 18 19 import java.util.ArrayList; 20 21 import android.os.AsyncResult; 22 import android.os.Handler; 23 import android.os.Message; 24 import android.util.Log; 25 26 27 public 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<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