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