/frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
Java | 453 lines | 356 code | 50 blank | 47 comment | 63 complexity | bc5432e9266a9c3a1d40b124bfdefa15 MD5 | raw file
- /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.android.internal.telephony.gsm;
- import android.os.AsyncResult;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import com.android.internal.telephony.AdnRecord;
- import com.android.internal.telephony.AdnRecordCache;
- import com.android.internal.telephony.IccConstants;
- import com.android.internal.telephony.IccFileHandler;
- import com.android.internal.telephony.IccUtils;
- import com.android.internal.telephony.PhoneBase;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * This class implements reading and parsing USIM records.
- * Refer to Spec 3GPP TS 31.102 for more details.
- *
- * {@hide}
- */
- public class UsimPhoneBookManager extends Handler implements IccConstants {
- private static final String LOG_TAG = "GSM";
- private static final boolean DBG = true;
- private PbrFile mPbrFile;
- private Boolean mIsPbrPresent;
- private IccFileHandler mFh;
- private AdnRecordCache mAdnCache;
- private Object mLock = new Object();
- private ArrayList<AdnRecord> mPhoneBookRecords;
- private boolean mEmailPresentInIap = false;
- private int mEmailTagNumberInIap = 0;
- private ArrayList<byte[]> mIapFileRecord;
- private ArrayList<byte[]> mEmailFileRecord;
- private Map<Integer, ArrayList<String>> mEmailsForAdnRec;
- private boolean mRefreshCache = false;
- private static final int EVENT_PBR_LOAD_DONE = 1;
- private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
- private static final int EVENT_IAP_LOAD_DONE = 3;
- private static final int EVENT_EMAIL_LOAD_DONE = 4;
- private static final int USIM_TYPE1_TAG = 0xA8;
- private static final int USIM_TYPE2_TAG = 0xA9;
- private static final int USIM_TYPE3_TAG = 0xAA;
- private static final int USIM_EFADN_TAG = 0xC0;
- private static final int USIM_EFIAP_TAG = 0xC1;
- private static final int USIM_EFEXT1_TAG = 0xC2;
- private static final int USIM_EFSNE_TAG = 0xC3;
- private static final int USIM_EFANR_TAG = 0xC4;
- private static final int USIM_EFPBC_TAG = 0xC5;
- private static final int USIM_EFGRP_TAG = 0xC6;
- private static final int USIM_EFAAS_TAG = 0xC7;
- private static final int USIM_EFGSD_TAG = 0xC8;
- private static final int USIM_EFUID_TAG = 0xC9;
- private static final int USIM_EFEMAIL_TAG = 0xCA;
- private static final int USIM_EFCCP1_TAG = 0xCB;
- public UsimPhoneBookManager(IccFileHandler fh, AdnRecordCache cache) {
- mFh = fh;
- mPhoneBookRecords = new ArrayList<AdnRecord>();
- mPbrFile = null;
- // We assume its present, after the first read this is updated.
- // So we don't have to read from UICC if its not present on subsequent reads.
- mIsPbrPresent = true;
- mAdnCache = cache;
- }
- public void reset() {
- mPhoneBookRecords.clear();
- mIapFileRecord = null;
- mEmailFileRecord = null;
- mPbrFile = null;
- mIsPbrPresent = true;
- mRefreshCache = false;
- }
- public ArrayList<AdnRecord> loadEfFilesFromUsim() {
- synchronized (mLock) {
- if (!mPhoneBookRecords.isEmpty()) {
- if (mRefreshCache) {
- mRefreshCache = false;
- refreshCache();
- }
- return mPhoneBookRecords;
- }
- if (!mIsPbrPresent) return null;
- // Check if the PBR file is present in the cache, if not read it
- // from the USIM.
- if (mPbrFile == null) {
- readPbrFileAndWait();
- }
- if (mPbrFile == null) return null;
- int numRecs = mPbrFile.mFileIds.size();
- for (int i = 0; i < numRecs; i++) {
- readAdnFileAndWait(i);
- readEmailFileAndWait(i);
- }
- // All EF files are loaded, post the response.
- }
- return mPhoneBookRecords;
- }
- private void refreshCache() {
- if (mPbrFile == null) return;
- mPhoneBookRecords.clear();
- int numRecs = mPbrFile.mFileIds.size();
- for (int i = 0; i < numRecs; i++) {
- readAdnFileAndWait(i);
- }
- }
- public void invalidateCache() {
- mRefreshCache = true;
- }
- private void readPbrFileAndWait() {
- mFh.loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
- }
- }
- private void readEmailFileAndWait(int recNum) {
- Map <Integer,Integer> fileIds;
- fileIds = mPbrFile.mFileIds.get(recNum);
- if (fileIds == null) return;
- if (fileIds.containsKey(USIM_EFEMAIL_TAG)) {
- int efid = fileIds.get(USIM_EFEMAIL_TAG);
- // Check if the EFEmail is a Type 1 file or a type 2 file.
- // If mEmailPresentInIap is true, its a type 2 file.
- // So we read the IAP file and then read the email records.
- // instead of reading directly.
- if (mEmailPresentInIap) {
- readIapFileAndWait(fileIds.get(USIM_EFIAP_TAG));
- if (mIapFileRecord == null) {
- Log.e(LOG_TAG, "Error: IAP file is empty");
- return;
- }
- }
- // Read the EFEmail file.
- mFh.loadEFLinearFixedAll(fileIds.get(USIM_EFEMAIL_TAG),
- obtainMessage(EVENT_EMAIL_LOAD_DONE));
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "Interrupted Exception in readEmailFileAndWait");
- }
- if (mEmailFileRecord == null) {
- Log.e(LOG_TAG, "Error: Email file is empty");
- return;
- }
- updatePhoneAdnRecord();
- }
- }
- private void readIapFileAndWait(int efid) {
- mFh.loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "Interrupted Exception in readIapFileAndWait");
- }
- }
- private void updatePhoneAdnRecord() {
- if (mEmailFileRecord == null) return;
- int numAdnRecs = mPhoneBookRecords.size();
- if (mIapFileRecord != null) {
- // The number of records in the IAP file is same as the number of records in ADN file.
- // The order of the pointers in an EFIAP shall be the same as the order of file IDs
- // that appear in the TLV object indicated by Tag 'A9' in the reference file record.
- // i.e value of mEmailTagNumberInIap
- for (int i = 0; i < numAdnRecs; i++) {
- byte[] record = null;
- try {
- record = mIapFileRecord.get(i);
- } catch (IndexOutOfBoundsException e) {
- Log.e(LOG_TAG, "Error: Improper ICC card: No IAP record for ADN, continuing");
- break;
- }
- int recNum = record[mEmailTagNumberInIap];
- if (recNum != -1) {
- String[] emails = new String[1];
- // SIM record numbers are 1 based
- emails[0] = readEmailRecord(recNum - 1);
- AdnRecord rec = mPhoneBookRecords.get(i);
- if (rec != null) {
- rec.setEmails(emails);
- } else {
- // might be a record with only email
- rec = new AdnRecord("", "", emails);
- }
- mPhoneBookRecords.set(i, rec);
- }
- }
- }
- // ICC cards can be made such that they have an IAP file but all
- // records are empty. So we read both type 1 and type 2 file
- // email records, just to be sure.
- int len = mPhoneBookRecords.size();
- // Type 1 file, the number of records is the same as the number of
- // records in the ADN file.
- if (mEmailsForAdnRec == null) {
- parseType1EmailFile(len);
- }
- for (int i = 0; i < numAdnRecs; i++) {
- ArrayList<String> emailList = null;
- try {
- emailList = mEmailsForAdnRec.get(i);
- } catch (IndexOutOfBoundsException e) {
- break;
- }
- if (emailList == null) continue;
- AdnRecord rec = mPhoneBookRecords.get(i);
- String[] emails = new String[emailList.size()];
- System.arraycopy(emailList.toArray(), 0, emails, 0, emailList.size());
- rec.setEmails(emails);
- mPhoneBookRecords.set(i, rec);
- }
- }
- void parseType1EmailFile(int numRecs) {
- mEmailsForAdnRec = new HashMap<Integer, ArrayList<String>>();
- byte[] emailRec = null;
- for (int i = 0; i < numRecs; i++) {
- try {
- emailRec = mEmailFileRecord.get(i);
- } catch (IndexOutOfBoundsException e) {
- Log.e(LOG_TAG, "Error: Improper ICC card: No email record for ADN, continuing");
- break;
- }
- int adnRecNum = emailRec[emailRec.length - 1];
- if (adnRecNum == -1) {
- continue;
- }
- String email = readEmailRecord(i);
- if (email == null || email.equals("")) {
- continue;
- }
- // SIM record numbers are 1 based.
- ArrayList<String> val = mEmailsForAdnRec.get(adnRecNum - 1);
- if (val == null) {
- val = new ArrayList<String>();
- }
- val.add(email);
- // SIM record numbers are 1 based.
- mEmailsForAdnRec.put(adnRecNum - 1, val);
- }
- }
- private String readEmailRecord(int recNum) {
- byte[] emailRec = null;
- try {
- emailRec = mEmailFileRecord.get(recNum);
- } catch (IndexOutOfBoundsException e) {
- return null;
- }
- // The length of the record is X+2 byte, where X bytes is the email address
- String email = IccUtils.adnStringFieldToString(emailRec, 0, emailRec.length - 2);
- return email;
- }
- private void readAdnFileAndWait(int recNum) {
- Map <Integer,Integer> fileIds;
- fileIds = mPbrFile.mFileIds.get(recNum);
- if (fileIds == null || fileIds.isEmpty()) return;
- int extEf = 0;
- // Only call fileIds.get while EFEXT1_TAG is available
- if (fileIds.containsKey(USIM_EFEXT1_TAG)) {
- extEf = fileIds.get(USIM_EFEXT1_TAG);
- }
- mAdnCache.requestLoadAllAdnLike(fileIds.get(USIM_EFADN_TAG),
- extEf, obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
- }
- }
- private void createPbrFile(ArrayList<byte[]> records) {
- if (records == null) {
- mPbrFile = null;
- mIsPbrPresent = false;
- return;
- }
- mPbrFile = new PbrFile(records);
- }
- @Override
- public void handleMessage(Message msg) {
- AsyncResult ar;
- switch(msg.what) {
- case EVENT_PBR_LOAD_DONE:
- ar = (AsyncResult) msg.obj;
- if (ar.exception == null) {
- createPbrFile((ArrayList<byte[]>)ar.result);
- }
- synchronized (mLock) {
- mLock.notify();
- }
- break;
- case EVENT_USIM_ADN_LOAD_DONE:
- log("Loading USIM ADN records done");
- ar = (AsyncResult) msg.obj;
- if (ar.exception == null) {
- mPhoneBookRecords.addAll((ArrayList<AdnRecord>)ar.result);
- }
- synchronized (mLock) {
- mLock.notify();
- }
- break;
- case EVENT_IAP_LOAD_DONE:
- log("Loading USIM IAP records done");
- ar = (AsyncResult) msg.obj;
- if (ar.exception == null) {
- mIapFileRecord = ((ArrayList<byte[]>)ar.result);
- }
- synchronized (mLock) {
- mLock.notify();
- }
- break;
- case EVENT_EMAIL_LOAD_DONE:
- log("Loading USIM Email records done");
- ar = (AsyncResult) msg.obj;
- if (ar.exception == null) {
- mEmailFileRecord = ((ArrayList<byte[]>)ar.result);
- }
- synchronized (mLock) {
- mLock.notify();
- }
- break;
- }
- }
- private class PbrFile {
- // RecNum <EF Tag, efid>
- HashMap<Integer,Map<Integer,Integer>> mFileIds;
- PbrFile(ArrayList<byte[]> records) {
- mFileIds = new HashMap<Integer, Map<Integer, Integer>>();
- SimTlv recTlv;
- int recNum = 0;
- for (byte[] record: records) {
- recTlv = new SimTlv(record, 0, record.length);
- parseTag(recTlv, recNum);
- recNum ++;
- }
- }
- void parseTag(SimTlv tlv, int recNum) {
- SimTlv tlvEf;
- int tag;
- byte[] data;
- Map<Integer, Integer> val = new HashMap<Integer, Integer>();
- do {
- tag = tlv.getTag();
- switch(tag) {
- case USIM_TYPE1_TAG: // A8
- case USIM_TYPE3_TAG: // AA
- case USIM_TYPE2_TAG: // A9
- data = tlv.getData();
- tlvEf = new SimTlv(data, 0, data.length);
- parseEf(tlvEf, val, tag);
- break;
- }
- } while (tlv.nextObject());
- mFileIds.put(recNum, val);
- }
- void parseEf(SimTlv tlv, Map<Integer, Integer> val, int parentTag) {
- int tag;
- byte[] data;
- int tagNumberWithinParentTag = 0;
- do {
- tag = tlv.getTag();
- if (parentTag == USIM_TYPE2_TAG && tag == USIM_EFEMAIL_TAG) {
- mEmailPresentInIap = true;
- mEmailTagNumberInIap = tagNumberWithinParentTag;
- }
- switch(tag) {
- case USIM_EFEMAIL_TAG:
- case USIM_EFADN_TAG:
- case USIM_EFEXT1_TAG:
- case USIM_EFANR_TAG:
- case USIM_EFPBC_TAG:
- case USIM_EFGRP_TAG:
- case USIM_EFAAS_TAG:
- case USIM_EFGSD_TAG:
- case USIM_EFUID_TAG:
- case USIM_EFCCP1_TAG:
- case USIM_EFIAP_TAG:
- case USIM_EFSNE_TAG:
- data = tlv.getData();
- int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
- val.put(tag, efid);
- break;
- }
- tagNumberWithinParentTag ++;
- } while(tlv.nextObject());
- }
- }
- private void log(String msg) {
- if(DBG) Log.d(LOG_TAG, msg);
- }
- }