10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2009 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony.gsm;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.AsyncResult;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler;
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message;
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.Log;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.AdnRecord;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.AdnRecordCache;
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.IccConstants;
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.IccFileHandler;
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.IccUtils;
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.telephony.PhoneBase;
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap;
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Map;
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/**
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * This class implements reading and parsing USIM records.
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Refer to Spec 3GPP TS 31.102 for more details.
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * {@hide}
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class UsimPhoneBookManager extends Handler implements IccConstants {
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String LOG_TAG = "GSM";
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final boolean DBG = true;
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private PbrFile mPbrFile;
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private Boolean mIsPbrPresent;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private IccFileHandler mFh;
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private AdnRecordCache mAdnCache;
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private Object mLock = new Object();
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private ArrayList<AdnRecord> mPhoneBookRecords;
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mEmailPresentInIap = false;
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mEmailTagNumberInIap = 0;
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private ArrayList<byte[]> mIapFileRecord;
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private ArrayList<byte[]> mEmailFileRecord;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private Map<Integer, ArrayList<String>> mEmailsForAdnRec;
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mRefreshCache = false;
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_PBR_LOAD_DONE = 1;
580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_IAP_LOAD_DONE = 3;
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_EMAIL_LOAD_DONE = 4;
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_TYPE1_TAG   = 0xA8;
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_TYPE2_TAG   = 0xA9;
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_TYPE3_TAG   = 0xAA;
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFADN_TAG   = 0xC0;
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFIAP_TAG   = 0xC1;
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFEXT1_TAG  = 0xC2;
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFSNE_TAG   = 0xC3;
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFANR_TAG   = 0xC4;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFPBC_TAG   = 0xC5;
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFGRP_TAG   = 0xC6;
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFAAS_TAG   = 0xC7;
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFGSD_TAG   = 0xC8;
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFUID_TAG   = 0xC9;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFEMAIL_TAG = 0xCA;
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFCCP1_TAG  = 0xCB;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public UsimPhoneBookManager(IccFileHandler fh, AdnRecordCache cache) {
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mFh = fh;
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhoneBookRecords = new ArrayList<AdnRecord>();
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPbrFile = null;
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // We assume its present, after the first read this is updated.
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // So we don't have to read from UICC if its not present on subsequent reads.
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mIsPbrPresent = true;
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mAdnCache = cache;
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void reset() {
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhoneBookRecords.clear();
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mIapFileRecord = null;
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mEmailFileRecord = null;
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPbrFile = null;
930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mIsPbrPresent = true;
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mRefreshCache = false;
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public ArrayList<AdnRecord> loadEfFilesFromUsim() {
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        synchronized (mLock) {
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (!mPhoneBookRecords.isEmpty()) {
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (mRefreshCache) {
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mRefreshCache = false;
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    refreshCache();
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return mPhoneBookRecords;
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (!mIsPbrPresent) return null;
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Check if the PBR file is present in the cache, if not read it
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // from the USIM.
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (mPbrFile == null) {
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                readPbrFileAndWait();
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (mPbrFile == null) return null;
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int numRecs = mPbrFile.mFileIds.size();
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0; i < numRecs; i++) {
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                readAdnFileAndWait(i);
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                readEmailFileAndWait(i);
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // All EF files are loaded, post the response.
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return mPhoneBookRecords;
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void refreshCache() {
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mPbrFile == null) return;
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhoneBookRecords.clear();
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int numRecs = mPbrFile.mFileIds.size();
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < numRecs; i++) {
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            readAdnFileAndWait(i);
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void invalidateCache() {
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mRefreshCache = true;
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void readPbrFileAndWait() {
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mFh.loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mLock.wait();
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (InterruptedException e) {
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void readEmailFileAndWait(int recNum) {
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Map <Integer,Integer> fileIds;
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        fileIds = mPbrFile.mFileIds.get(recNum);
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (fileIds == null) return;
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (fileIds.containsKey(USIM_EFEMAIL_TAG)) {
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int efid = fileIds.get(USIM_EFEMAIL_TAG);
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Check if the EFEmail is a Type 1 file or a type 2 file.
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // If mEmailPresentInIap is true, its a type 2 file.
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // So we read the IAP file and then read the email records.
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // instead of reading directly.
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (mEmailPresentInIap) {
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                readIapFileAndWait(fileIds.get(USIM_EFIAP_TAG));
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (mIapFileRecord == null) {
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Log.e(LOG_TAG, "Error: IAP file is empty");
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    return;
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Read the EFEmail file.
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mFh.loadEFLinearFixedAll(fileIds.get(USIM_EFEMAIL_TAG),
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    obtainMessage(EVENT_EMAIL_LOAD_DONE));
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.wait();
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (InterruptedException e) {
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Log.e(LOG_TAG, "Interrupted Exception in readEmailFileAndWait");
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (mEmailFileRecord == null) {
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Log.e(LOG_TAG, "Error: Email file is empty");
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            updatePhoneAdnRecord();
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void readIapFileAndWait(int efid) {
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mFh.loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mLock.wait();
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (InterruptedException e) {
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(LOG_TAG, "Interrupted Exception in readIapFileAndWait");
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void updatePhoneAdnRecord() {
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mEmailFileRecord == null) return;
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int numAdnRecs = mPhoneBookRecords.size();
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mIapFileRecord != null) {
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // The number of records in the IAP file is same as the number of records in ADN file.
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // The order of the pointers in an EFIAP shall be the same as the order of file IDs
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // that appear in the TLV object indicated by Tag 'A9' in the reference file record.
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // i.e value of mEmailTagNumberInIap
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0; i < numAdnRecs; i++) {
2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                byte[] record = null;
2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                try {
2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    record = mIapFileRecord.get(i);
2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                } catch (IndexOutOfBoundsException e) {
2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    Log.e(LOG_TAG, "Error: Improper ICC card: No IAP record for ADN, continuing");
2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                int recNum = record[mEmailTagNumberInIap];
2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (recNum != -1) {
2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    String[] emails = new String[1];
2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    // SIM record numbers are 1 based
2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    emails[0] = readEmailRecord(recNum - 1);
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    AdnRecord rec = mPhoneBookRecords.get(i);
2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    if (rec != null) {
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        rec.setEmails(emails);
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    } else {
2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        // might be a record with only email
2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        rec = new AdnRecord("", "", emails);
2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    }
2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mPhoneBookRecords.set(i, rec);
2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // ICC cards can be made such that they have an IAP file but all
2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // records are empty. So we read both type 1 and type 2 file
2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // email records, just to be sure.
2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int len = mPhoneBookRecords.size();
2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Type 1 file, the number of records is the same as the number of
2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // records in the ADN file.
2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (mEmailsForAdnRec == null) {
2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            parseType1EmailFile(len);
2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < numAdnRecs; i++) {
2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> emailList = null;
2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                emailList = mEmailsForAdnRec.get(i);
2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (IndexOutOfBoundsException e) {
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (emailList == null) continue;
2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            AdnRecord rec = mPhoneBookRecords.get(i);
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String[] emails = new String[emailList.size()];
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            System.arraycopy(emailList.toArray(), 0, emails, 0, emailList.size());
2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            rec.setEmails(emails);
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPhoneBookRecords.set(i, rec);
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    void parseType1EmailFile(int numRecs) {
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mEmailsForAdnRec = new HashMap<Integer, ArrayList<String>>();
2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] emailRec = null;
2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < numRecs; i++) {
2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                emailRec = mEmailFileRecord.get(i);
2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (IndexOutOfBoundsException e) {
2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                Log.e(LOG_TAG, "Error: Improper ICC card: No email record for ADN, continuing");
2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int adnRecNum = emailRec[emailRec.length - 1];
2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (adnRecNum == -1) {
2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                continue;
2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            String email = readEmailRecord(i);
2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (email == null || email.equals("")) {
2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                continue;
2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // SIM record numbers are 1 based.
2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ArrayList<String> val = mEmailsForAdnRec.get(adnRecNum - 1);
2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (val == null) {
2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                val = new ArrayList<String>();
2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            val.add(email);
2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // SIM record numbers are 1 based.
2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mEmailsForAdnRec.put(adnRecNum - 1, val);
2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private String readEmailRecord(int recNum) {
2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        byte[] emailRec = null;
2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            emailRec = mEmailFileRecord.get(recNum);
2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (IndexOutOfBoundsException e) {
2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return null;
2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // The length of the record is X+2 byte, where X bytes is the email address
3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        String email = IccUtils.adnStringFieldToString(emailRec, 0, emailRec.length - 2);
3010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return email;
3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void readAdnFileAndWait(int recNum) {
3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        Map <Integer,Integer> fileIds;
3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        fileIds = mPbrFile.mFileIds.get(recNum);
3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (fileIds == null || fileIds.isEmpty()) return;
3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int extEf = 0;
3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // Only call fileIds.get while EFEXT1_TAG is available
3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (fileIds.containsKey(USIM_EFEXT1_TAG)) {
3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            extEf = fileIds.get(USIM_EFEXT1_TAG);
3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mAdnCache.requestLoadAllAdnLike(fileIds.get(USIM_EFADN_TAG),
3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            extEf, obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mLock.wait();
3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (InterruptedException e) {
3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void createPbrFile(ArrayList<byte[]> records) {
3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (records == null) {
3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mPbrFile = null;
3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mIsPbrPresent = false;
3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPbrFile = new PbrFile(records);
3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AsyncResult ar;
3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch(msg.what) {
3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_PBR_LOAD_DONE:
3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception == null) {
3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                createPbrFile((ArrayList<byte[]>)ar.result);
3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            synchronized (mLock) {
3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.notify();
3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_USIM_ADN_LOAD_DONE:
3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            log("Loading USIM ADN records done");
3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception == null) {
3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mPhoneBookRecords.addAll((ArrayList<AdnRecord>)ar.result);
3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            synchronized (mLock) {
3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.notify();
3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_IAP_LOAD_DONE:
3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            log("Loading USIM IAP records done");
3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception == null) {
3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mIapFileRecord = ((ArrayList<byte[]>)ar.result);
3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            synchronized (mLock) {
3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.notify();
3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_EMAIL_LOAD_DONE:
3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            log("Loading USIM Email records done");
3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception == null) {
3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mEmailFileRecord = ((ArrayList<byte[]>)ar.result);
3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            synchronized (mLock) {
3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.notify();
3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private class PbrFile {
3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // RecNum <EF Tag, efid>
3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        HashMap<Integer,Map<Integer,Integer>> mFileIds;
3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        PbrFile(ArrayList<byte[]> records) {
3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mFileIds = new HashMap<Integer, Map<Integer, Integer>>();
3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SimTlv recTlv;
3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int recNum = 0;
3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (byte[] record: records) {
3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                recTlv = new SimTlv(record, 0, record.length);
3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                parseTag(recTlv, recNum);
3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                recNum ++;
3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        void parseTag(SimTlv tlv, int recNum) {
3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SimTlv tlvEf;
3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int tag;
4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data;
4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            Map<Integer, Integer> val = new HashMap<Integer, Integer>();
4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            do {
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tag = tlv.getTag();
4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                switch(tag) {
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case USIM_TYPE1_TAG: // A8
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case USIM_TYPE3_TAG: // AA
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case USIM_TYPE2_TAG: // A9
4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    data = tlv.getData();
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    tlvEf = new SimTlv(data, 0, data.length);
4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    parseEf(tlvEf, val, tag);
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } while (tlv.nextObject());
4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mFileIds.put(recNum, val);
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        void parseEf(SimTlv tlv, Map<Integer, Integer> val, int parentTag) {
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int tag;
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data;
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int tagNumberWithinParentTag = 0;
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            do {
4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tag = tlv.getTag();
4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (parentTag == USIM_TYPE2_TAG && tag == USIM_EFEMAIL_TAG) {
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mEmailPresentInIap = true;
4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mEmailTagNumberInIap = tagNumberWithinParentTag;
4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                switch(tag) {
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFEMAIL_TAG:
4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFADN_TAG:
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFEXT1_TAG:
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFANR_TAG:
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFPBC_TAG:
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFGRP_TAG:
4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFAAS_TAG:
4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFGSD_TAG:
4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFUID_TAG:
4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFCCP1_TAG:
4380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFIAP_TAG:
4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFSNE_TAG:
4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        data = tlv.getData();
4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        val.put(tag, efid);
4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        break;
4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tagNumberWithinParentTag ++;
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } while(tlv.nextObject());
4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void log(String msg) {
4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if(DBG) Log.d(LOG_TAG, msg);
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
454