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;
22ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Savilleimport android.telephony.Rlog;
23a62d723815dad650884714e801421b6d7cb34f91Jack Yuimport android.util.SparseArray;
24a62d723815dad650884714e801421b6d7cb34f91Jack Yuimport android.util.SparseIntArray;
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
26d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.AdnRecord;
27d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.AdnRecordCache;
28d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.IccConstants;
29d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.IccFileHandler;
30d720945f2be5ea5fe0faf67e67d9ea0e184eba67Alex Yakavenkaimport com.android.internal.telephony.uicc.IccUtils;
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/**
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * This class implements reading and parsing USIM records.
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Refer to Spec 3GPP TS 31.102 for more details.
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * {@hide}
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class UsimPhoneBookManager extends Handler implements IccConstants {
40cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    private static final String LOG_TAG = "UsimPhoneBookManager";
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final boolean DBG = true;
42a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private ArrayList<PbrRecord> mPbrRecords;
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private Boolean mIsPbrPresent;
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private IccFileHandler mFh;
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private AdnRecordCache mAdnCache;
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private Object mLock = new Object();
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private ArrayList<AdnRecord> mPhoneBookRecords;
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private ArrayList<byte[]> mIapFileRecord;
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private ArrayList<byte[]> mEmailFileRecord;
50a62d723815dad650884714e801421b6d7cb34f91Jack Yu
51a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // email list for each ADN record. The key would be
52a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // ADN's efid << 8 + record #
53a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private SparseArray<ArrayList<String>> mEmailsForAdnRec;
54a62d723815dad650884714e801421b6d7cb34f91Jack Yu
55a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // SFI to ADN Efid mapping table
56a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private SparseIntArray mSfiEfidTable;
57a62d723815dad650884714e801421b6d7cb34f91Jack Yu
580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mRefreshCache = false;
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
60a62d723815dad650884714e801421b6d7cb34f91Jack Yu
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_PBR_LOAD_DONE = 1;
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_IAP_LOAD_DONE = 3;
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int EVENT_EMAIL_LOAD_DONE = 4;
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_TYPE1_TAG   = 0xA8;
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_TYPE2_TAG   = 0xA9;
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_TYPE3_TAG   = 0xAA;
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFADN_TAG   = 0xC0;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFIAP_TAG   = 0xC1;
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFEXT1_TAG  = 0xC2;
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFSNE_TAG   = 0xC3;
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFANR_TAG   = 0xC4;
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFPBC_TAG   = 0xC5;
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFGRP_TAG   = 0xC6;
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFAAS_TAG   = 0xC7;
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFGSD_TAG   = 0xC8;
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFUID_TAG   = 0xC9;
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFEMAIL_TAG = 0xCA;
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final int USIM_EFCCP1_TAG  = 0xCB;
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
82a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private static final int INVALID_SFI = -1;
8396cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu    private static final byte INVALID_BYTE = -1;
84a62d723815dad650884714e801421b6d7cb34f91Jack Yu
85a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // class File represent a PBR record TLV object which points to the rest of the phonebook EFs
86a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private class File {
87a62d723815dad650884714e801421b6d7cb34f91Jack Yu        // Phonebook reference file constructed tag defined in 3GPP TS 31.102
88a62d723815dad650884714e801421b6d7cb34f91Jack Yu        // section 4.4.2.1 table 4.1
89a62d723815dad650884714e801421b6d7cb34f91Jack Yu        private final int mParentTag;
90a62d723815dad650884714e801421b6d7cb34f91Jack Yu        // EFID of the file
91a62d723815dad650884714e801421b6d7cb34f91Jack Yu        private final int mEfid;
92a62d723815dad650884714e801421b6d7cb34f91Jack Yu        // SFI (Short File Identification) of the file. 0xFF indicates invalid SFI.
93a62d723815dad650884714e801421b6d7cb34f91Jack Yu        private final int mSfi;
94a62d723815dad650884714e801421b6d7cb34f91Jack Yu        // The order of this tag showing in the PBR record.
95a62d723815dad650884714e801421b6d7cb34f91Jack Yu        private final int mIndex;
96a62d723815dad650884714e801421b6d7cb34f91Jack Yu
97a62d723815dad650884714e801421b6d7cb34f91Jack Yu        File(int parentTag, int efid, int sfi, int index) {
98a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mParentTag = parentTag;
99a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mEfid = efid;
100a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mSfi = sfi;
101a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mIndex = index;
102a62d723815dad650884714e801421b6d7cb34f91Jack Yu        }
103a62d723815dad650884714e801421b6d7cb34f91Jack Yu
104a62d723815dad650884714e801421b6d7cb34f91Jack Yu        public int getParentTag() { return mParentTag; }
105a62d723815dad650884714e801421b6d7cb34f91Jack Yu        public int getEfid() { return mEfid; }
106a62d723815dad650884714e801421b6d7cb34f91Jack Yu        public int getSfi() { return mSfi; }
107a62d723815dad650884714e801421b6d7cb34f91Jack Yu        public int getIndex() { return mIndex; }
108a62d723815dad650884714e801421b6d7cb34f91Jack Yu    }
109a62d723815dad650884714e801421b6d7cb34f91Jack Yu
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public UsimPhoneBookManager(IccFileHandler fh, AdnRecordCache cache) {
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mFh = fh;
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhoneBookRecords = new ArrayList<AdnRecord>();
113a62d723815dad650884714e801421b6d7cb34f91Jack Yu        mPbrRecords = null;
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // We assume its present, after the first read this is updated.
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // So we don't have to read from UICC if its not present on subsequent reads.
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mIsPbrPresent = true;
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mAdnCache = cache;
118a62d723815dad650884714e801421b6d7cb34f91Jack Yu        mEmailsForAdnRec = new SparseArray<ArrayList<String>>();
119a62d723815dad650884714e801421b6d7cb34f91Jack Yu        mSfiEfidTable = new SparseIntArray();
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void reset() {
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhoneBookRecords.clear();
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mIapFileRecord = null;
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mEmailFileRecord = null;
126a62d723815dad650884714e801421b6d7cb34f91Jack Yu        mPbrRecords = null;
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mIsPbrPresent = true;
1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mRefreshCache = false;
129a62d723815dad650884714e801421b6d7cb34f91Jack Yu        mEmailsForAdnRec.clear();
130a62d723815dad650884714e801421b6d7cb34f91Jack Yu        mSfiEfidTable.clear();
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
133a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Load all phonebook related EFs from the SIM.
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public ArrayList<AdnRecord> loadEfFilesFromUsim() {
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        synchronized (mLock) {
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (!mPhoneBookRecords.isEmpty()) {
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (mRefreshCache) {
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    mRefreshCache = false;
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    refreshCache();
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return mPhoneBookRecords;
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (!mIsPbrPresent) return null;
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Check if the PBR file is present in the cache, if not read it
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // from the USIM.
148a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (mPbrRecords == null) {
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                readPbrFileAndWait();
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
152a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (mPbrRecords == null)
153a62d723815dad650884714e801421b6d7cb34f91Jack Yu                return null;
154a62d723815dad650884714e801421b6d7cb34f91Jack Yu
155a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int numRecs = mPbrRecords.size();
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
157a62d723815dad650884714e801421b6d7cb34f91Jack Yu            log("loadEfFilesFromUsim: Loading adn and emails");
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            for (int i = 0; i < numRecs; i++) {
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                readAdnFileAndWait(i);
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                readEmailFileAndWait(i);
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
162a62d723815dad650884714e801421b6d7cb34f91Jack Yu
163a62d723815dad650884714e801421b6d7cb34f91Jack Yu            updatePhoneAdnRecord();
164a62d723815dad650884714e801421b6d7cb34f91Jack Yu            // All EF files are loaded, return all the records
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return mPhoneBookRecords;
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
169a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Refresh the phonebook cache.
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void refreshCache() {
171a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (mPbrRecords == null) return;
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mPhoneBookRecords.clear();
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
174a62d723815dad650884714e801421b6d7cb34f91Jack Yu        int numRecs = mPbrRecords.size();
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < numRecs; i++) {
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            readAdnFileAndWait(i);
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
180a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Invalidate the phonebook cache.
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void invalidateCache() {
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mRefreshCache = true;
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
185a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Read the phonebook reference file EF_PBR.
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void readPbrFileAndWait() {
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mFh.loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mLock.wait();
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (InterruptedException e) {
191ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
195a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Read EF_EMAIL which contains the email records.
196a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private void readEmailFileAndWait(int recId) {
197a62d723815dad650884714e801421b6d7cb34f91Jack Yu        SparseArray<File> files;
198a62d723815dad650884714e801421b6d7cb34f91Jack Yu        files = mPbrRecords.get(recId).mFileIds;
199a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (files == null) return;
200a62d723815dad650884714e801421b6d7cb34f91Jack Yu
201a62d723815dad650884714e801421b6d7cb34f91Jack Yu        File email = files.get(USIM_EFEMAIL_TAG);
202a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (email != null) {
203a62d723815dad650884714e801421b6d7cb34f91Jack Yu
204a62d723815dad650884714e801421b6d7cb34f91Jack Yu            /**
205a62d723815dad650884714e801421b6d7cb34f91Jack Yu             * Check if the EF_EMAIL is a Type 1 file or a type 2 file.
206a62d723815dad650884714e801421b6d7cb34f91Jack Yu             * If mEmailPresentInIap is true, its a type 2 file.
207a62d723815dad650884714e801421b6d7cb34f91Jack Yu             * So we read the IAP file and then read the email records.
208a62d723815dad650884714e801421b6d7cb34f91Jack Yu             * instead of reading directly.
209a62d723815dad650884714e801421b6d7cb34f91Jack Yu             */
210a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (email.getParentTag() == USIM_TYPE2_TAG) {
211a62d723815dad650884714e801421b6d7cb34f91Jack Yu                if (files.get(USIM_EFIAP_TAG) == null) {
212a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    Rlog.e(LOG_TAG, "Can't locate EF_IAP in EF_PBR.");
213a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    return;
214a62d723815dad650884714e801421b6d7cb34f91Jack Yu                }
215a62d723815dad650884714e801421b6d7cb34f91Jack Yu
216a62d723815dad650884714e801421b6d7cb34f91Jack Yu                log("EF_IAP exists. Loading EF_IAP to retrieve the index.");
217a62d723815dad650884714e801421b6d7cb34f91Jack Yu                readIapFileAndWait(files.get(USIM_EFIAP_TAG).getEfid());
2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (mIapFileRecord == null) {
219ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(LOG_TAG, "Error: IAP file is empty");
2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    return;
2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
222a62d723815dad650884714e801421b6d7cb34f91Jack Yu
223a62d723815dad650884714e801421b6d7cb34f91Jack Yu                log("EF_EMAIL order in PBR record: " + email.getIndex());
224a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
225a62d723815dad650884714e801421b6d7cb34f91Jack Yu
226a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int emailEfid = email.getEfid();
227a62d723815dad650884714e801421b6d7cb34f91Jack Yu            log("EF_EMAIL exists in PBR. efid = 0x" +
228a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    Integer.toHexString(emailEfid).toUpperCase());
229a62d723815dad650884714e801421b6d7cb34f91Jack Yu
230a62d723815dad650884714e801421b6d7cb34f91Jack Yu            /**
231a62d723815dad650884714e801421b6d7cb34f91Jack Yu             * Make sure this EF_EMAIL was never read earlier. Sometimes two PBR record points
232a62d723815dad650884714e801421b6d7cb34f91Jack Yu             */
233a62d723815dad650884714e801421b6d7cb34f91Jack Yu            // to the same EF_EMAIL
234a62d723815dad650884714e801421b6d7cb34f91Jack Yu            for (int i = 0; i < recId; i++) {
235a62d723815dad650884714e801421b6d7cb34f91Jack Yu                if (mPbrRecords.get(i) != null) {
236a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    SparseArray<File> previousFileIds = mPbrRecords.get(i).mFileIds;
237a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    if (previousFileIds != null) {
238a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        File id = previousFileIds.get(USIM_EFEMAIL_TAG);
239a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        if (id != null && id.getEfid() == emailEfid) {
240a62d723815dad650884714e801421b6d7cb34f91Jack Yu                            log("Skipped this EF_EMAIL which was loaded earlier");
241a62d723815dad650884714e801421b6d7cb34f91Jack Yu                            return;
242a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        }
243a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    }
244a62d723815dad650884714e801421b6d7cb34f91Jack Yu                }
2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
246a62d723815dad650884714e801421b6d7cb34f91Jack Yu
2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            // Read the EFEmail file.
248a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mFh.loadEFLinearFixedAll(emailEfid,
2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    obtainMessage(EVENT_EMAIL_LOAD_DONE));
2500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.wait();
2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (InterruptedException e) {
253ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.e(LOG_TAG, "Interrupted Exception in readEmailFileAndWait");
2540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (mEmailFileRecord == null) {
257ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                Rlog.e(LOG_TAG, "Error: Email file is empty");
2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return;
2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
260a62d723815dad650884714e801421b6d7cb34f91Jack Yu
261a62d723815dad650884714e801421b6d7cb34f91Jack Yu            // Build email list
262a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (email.getParentTag() == USIM_TYPE2_TAG && mIapFileRecord != null) {
263a62d723815dad650884714e801421b6d7cb34f91Jack Yu                // If the tag is type 2 and EF_IAP exists, we need to build tpe 2 email list
264a62d723815dad650884714e801421b6d7cb34f91Jack Yu                buildType2EmailList(recId);
265a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
266a62d723815dad650884714e801421b6d7cb34f91Jack Yu            else {
267a62d723815dad650884714e801421b6d7cb34f91Jack Yu                // If one the followings is true, we build type 1 email list
268a62d723815dad650884714e801421b6d7cb34f91Jack Yu                // 1. EF_IAP does not exist or it is failed to load
269a62d723815dad650884714e801421b6d7cb34f91Jack Yu                // 2. ICC cards can be made such that they have an IAP file but all
270a62d723815dad650884714e801421b6d7cb34f91Jack Yu                //    records are empty. In that case buildType2EmailList will fail and
271a62d723815dad650884714e801421b6d7cb34f91Jack Yu                //    we need to build type 1 email list.
272a62d723815dad650884714e801421b6d7cb34f91Jack Yu
273a62d723815dad650884714e801421b6d7cb34f91Jack Yu                // Build type 1 email list
274a62d723815dad650884714e801421b6d7cb34f91Jack Yu                buildType1EmailList(recId);
275a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
277a62d723815dad650884714e801421b6d7cb34f91Jack Yu    }
278a62d723815dad650884714e801421b6d7cb34f91Jack Yu
279a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Build type 1 email list
280a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private void buildType1EmailList(int recId) {
281a62d723815dad650884714e801421b6d7cb34f91Jack Yu        /**
282a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * If this is type 1, the number of records in EF_EMAIL would be same as the record number
283a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * in the master/reference file.
284a62d723815dad650884714e801421b6d7cb34f91Jack Yu         */
285a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (mPbrRecords.get(recId) == null)
286a62d723815dad650884714e801421b6d7cb34f91Jack Yu            return;
287a62d723815dad650884714e801421b6d7cb34f91Jack Yu
288a62d723815dad650884714e801421b6d7cb34f91Jack Yu        int numRecs = mPbrRecords.get(recId).mMasterFileRecordNum;
289a62d723815dad650884714e801421b6d7cb34f91Jack Yu        log("Building type 1 email list. recId = "
290a62d723815dad650884714e801421b6d7cb34f91Jack Yu                + recId + ", numRecs = " + numRecs);
291a62d723815dad650884714e801421b6d7cb34f91Jack Yu
292a62d723815dad650884714e801421b6d7cb34f91Jack Yu        byte[] emailRec;
293a62d723815dad650884714e801421b6d7cb34f91Jack Yu        for (int i = 0; i < numRecs; i++) {
294a62d723815dad650884714e801421b6d7cb34f91Jack Yu            try {
295a62d723815dad650884714e801421b6d7cb34f91Jack Yu                emailRec = mEmailFileRecord.get(i);
296a62d723815dad650884714e801421b6d7cb34f91Jack Yu            } catch (IndexOutOfBoundsException e) {
297a62d723815dad650884714e801421b6d7cb34f91Jack Yu                Rlog.e(LOG_TAG, "Error: Improper ICC card: No email record for ADN, continuing");
298a62d723815dad650884714e801421b6d7cb34f91Jack Yu                break;
299a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
300a62d723815dad650884714e801421b6d7cb34f91Jack Yu
301a62d723815dad650884714e801421b6d7cb34f91Jack Yu            /**
302a62d723815dad650884714e801421b6d7cb34f91Jack Yu             *  3GPP TS 31.102 4.4.2.13 EF_EMAIL (e-mail address)
303a62d723815dad650884714e801421b6d7cb34f91Jack Yu             *
304a62d723815dad650884714e801421b6d7cb34f91Jack Yu             *  The fields below are mandatory if and only if the file
305a62d723815dad650884714e801421b6d7cb34f91Jack Yu             *  is not type 1 (as specified in EF_PBR)
306a62d723815dad650884714e801421b6d7cb34f91Jack Yu             *
307a62d723815dad650884714e801421b6d7cb34f91Jack Yu             *  Byte [X + 1]: ADN file SFI (Short File Identification)
308a62d723815dad650884714e801421b6d7cb34f91Jack Yu             *  Byte [X + 2]: ADN file Record Identifier
309a62d723815dad650884714e801421b6d7cb34f91Jack Yu             */
310a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int sfi = emailRec[emailRec.length - 2];
311a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int adnRecId = emailRec[emailRec.length - 1];
312a62d723815dad650884714e801421b6d7cb34f91Jack Yu
313a62d723815dad650884714e801421b6d7cb34f91Jack Yu            String email = readEmailRecord(i);
314a62d723815dad650884714e801421b6d7cb34f91Jack Yu
315a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (email == null || email.equals("")) {
316a62d723815dad650884714e801421b6d7cb34f91Jack Yu                continue;
317a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
318a62d723815dad650884714e801421b6d7cb34f91Jack Yu
319a62d723815dad650884714e801421b6d7cb34f91Jack Yu            // Get the associated ADN's efid first.
320a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int adnEfid = 0;
321a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (sfi == INVALID_SFI || mSfiEfidTable.get(sfi) == 0) {
322a62d723815dad650884714e801421b6d7cb34f91Jack Yu
323a62d723815dad650884714e801421b6d7cb34f91Jack Yu                // If SFI is invalid or cannot be mapped to any ADN, use the ADN's efid
324a62d723815dad650884714e801421b6d7cb34f91Jack Yu                // in the same PBR files.
325a62d723815dad650884714e801421b6d7cb34f91Jack Yu                File file = mPbrRecords.get(recId).mFileIds.get(USIM_EFADN_TAG);
326a62d723815dad650884714e801421b6d7cb34f91Jack Yu                if (file == null)
327a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    continue;
328a62d723815dad650884714e801421b6d7cb34f91Jack Yu                adnEfid = file.getEfid();
329a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
330a62d723815dad650884714e801421b6d7cb34f91Jack Yu            else {
331a62d723815dad650884714e801421b6d7cb34f91Jack Yu                adnEfid = mSfiEfidTable.get(sfi);
332a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
333a62d723815dad650884714e801421b6d7cb34f91Jack Yu            /**
334a62d723815dad650884714e801421b6d7cb34f91Jack Yu             * SIM record numbers are 1 based.
335a62d723815dad650884714e801421b6d7cb34f91Jack Yu             * The key is constructed by efid and record index.
336a62d723815dad650884714e801421b6d7cb34f91Jack Yu             */
337a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int index = (((adnEfid & 0xFFFF) << 8) | ((adnRecId - 1) & 0xFF));
338a62d723815dad650884714e801421b6d7cb34f91Jack Yu            ArrayList<String> emailList = mEmailsForAdnRec.get(index);
339a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (emailList == null) {
340a62d723815dad650884714e801421b6d7cb34f91Jack Yu                emailList = new ArrayList<String>();
341a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
342a62d723815dad650884714e801421b6d7cb34f91Jack Yu            log("Adding email #" + i + " list to index 0x" +
343a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    Integer.toHexString(index).toUpperCase());
344a62d723815dad650884714e801421b6d7cb34f91Jack Yu            emailList.add(email);
345a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mEmailsForAdnRec.put(index, emailList);
346a62d723815dad650884714e801421b6d7cb34f91Jack Yu        }
347a62d723815dad650884714e801421b6d7cb34f91Jack Yu    }
348a62d723815dad650884714e801421b6d7cb34f91Jack Yu
349a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Build type 2 email list
350a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private boolean buildType2EmailList(int recId) {
351a62d723815dad650884714e801421b6d7cb34f91Jack Yu
352a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (mPbrRecords.get(recId) == null)
353a62d723815dad650884714e801421b6d7cb34f91Jack Yu            return false;
354a62d723815dad650884714e801421b6d7cb34f91Jack Yu
355a62d723815dad650884714e801421b6d7cb34f91Jack Yu        int numRecs = mPbrRecords.get(recId).mMasterFileRecordNum;
356a62d723815dad650884714e801421b6d7cb34f91Jack Yu        log("Building type 2 email list. recId = "
357a62d723815dad650884714e801421b6d7cb34f91Jack Yu                + recId + ", numRecs = " + numRecs);
358a62d723815dad650884714e801421b6d7cb34f91Jack Yu
359a62d723815dad650884714e801421b6d7cb34f91Jack Yu        /**
360a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * 3GPP TS 31.102 4.4.2.1 EF_PBR (Phone Book Reference file) table 4.1
361a62d723815dad650884714e801421b6d7cb34f91Jack Yu
362a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * The number of records in the IAP file is same as the number of records in the master
363a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * file (e.g EF_ADN). The order of the pointers in an EF_IAP shall be the same as the
364a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * order of file IDs that appear in the TLV object indicated by Tag 'A9' in the
365a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * reference file record (e.g value of mEmailTagNumberInIap)
366a62d723815dad650884714e801421b6d7cb34f91Jack Yu         */
367a62d723815dad650884714e801421b6d7cb34f91Jack Yu
368a62d723815dad650884714e801421b6d7cb34f91Jack Yu        File adnFile = mPbrRecords.get(recId).mFileIds.get(USIM_EFADN_TAG);
369a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (adnFile == null) {
370a62d723815dad650884714e801421b6d7cb34f91Jack Yu            Rlog.e(LOG_TAG, "Error: Improper ICC card: EF_ADN does not exist in PBR files");
371a62d723815dad650884714e801421b6d7cb34f91Jack Yu            return false;
372a62d723815dad650884714e801421b6d7cb34f91Jack Yu        }
373a62d723815dad650884714e801421b6d7cb34f91Jack Yu        int adnEfid = adnFile.getEfid();
374a62d723815dad650884714e801421b6d7cb34f91Jack Yu
375a62d723815dad650884714e801421b6d7cb34f91Jack Yu        for (int i = 0; i < numRecs; i++) {
376a62d723815dad650884714e801421b6d7cb34f91Jack Yu            byte[] record;
377a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int emailRecId;
378a62d723815dad650884714e801421b6d7cb34f91Jack Yu            try {
379a62d723815dad650884714e801421b6d7cb34f91Jack Yu                record = mIapFileRecord.get(i);
380a62d723815dad650884714e801421b6d7cb34f91Jack Yu                emailRecId =
381a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        record[mPbrRecords.get(recId).mFileIds.get(USIM_EFEMAIL_TAG).getIndex()];
382a62d723815dad650884714e801421b6d7cb34f91Jack Yu            } catch (IndexOutOfBoundsException e) {
383a62d723815dad650884714e801421b6d7cb34f91Jack Yu                Rlog.e(LOG_TAG, "Error: Improper ICC card: Corrupted EF_IAP");
384a62d723815dad650884714e801421b6d7cb34f91Jack Yu                continue;
385a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
387a62d723815dad650884714e801421b6d7cb34f91Jack Yu            String email = readEmailRecord(emailRecId - 1);
388a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (email != null && !email.equals("")) {
389a62d723815dad650884714e801421b6d7cb34f91Jack Yu                // The key is constructed by efid and record index.
390a62d723815dad650884714e801421b6d7cb34f91Jack Yu                int index = (((adnEfid & 0xFFFF) << 8) | (i & 0xFF));
391a62d723815dad650884714e801421b6d7cb34f91Jack Yu                ArrayList<String> emailList = mEmailsForAdnRec.get(index);
392a62d723815dad650884714e801421b6d7cb34f91Jack Yu                if (emailList == null) {
393a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    emailList = new ArrayList<String>();
394a62d723815dad650884714e801421b6d7cb34f91Jack Yu                }
395a62d723815dad650884714e801421b6d7cb34f91Jack Yu                emailList.add(email);
396a62d723815dad650884714e801421b6d7cb34f91Jack Yu                log("Adding email list to index 0x" +
397a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        Integer.toHexString(index).toUpperCase());
398a62d723815dad650884714e801421b6d7cb34f91Jack Yu                mEmailsForAdnRec.put(index, emailList);
399a62d723815dad650884714e801421b6d7cb34f91Jack Yu            }
400a62d723815dad650884714e801421b6d7cb34f91Jack Yu        }
401a62d723815dad650884714e801421b6d7cb34f91Jack Yu        return true;
4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
404a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Read Phonebook Index Admistration EF_IAP file
4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void readIapFileAndWait(int efid) {
4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mFh.loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mLock.wait();
4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (InterruptedException e) {
410ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, "Interrupted Exception in readIapFileAndWait");
4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void updatePhoneAdnRecord() {
4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
416a62d723815dad650884714e801421b6d7cb34f91Jack Yu        int numAdnRecs = mPhoneBookRecords.size();
4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        for (int i = 0; i < numAdnRecs; i++) {
4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            AdnRecord rec = mPhoneBookRecords.get(i);
4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
422a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int adnEfid = rec.getEfid();
423a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int adnRecId = rec.getRecId();
4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
425a62d723815dad650884714e801421b6d7cb34f91Jack Yu            int index = (((adnEfid & 0xFFFF) << 8) | ((adnRecId - 1) & 0xFF));
426a62d723815dad650884714e801421b6d7cb34f91Jack Yu
427a62d723815dad650884714e801421b6d7cb34f91Jack Yu            ArrayList<String> emailList;
4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            try {
429a62d723815dad650884714e801421b6d7cb34f91Jack Yu                emailList = mEmailsForAdnRec.get(index);
4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } catch (IndexOutOfBoundsException e) {
4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                continue;
4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
434a62d723815dad650884714e801421b6d7cb34f91Jack Yu            if (emailList == null)
4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                continue;
4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
437a62d723815dad650884714e801421b6d7cb34f91Jack Yu            String[] emails = new String[emailList.size()];
438a62d723815dad650884714e801421b6d7cb34f91Jack Yu            System.arraycopy(emailList.toArray(), 0, emails, 0, emailList.size());
439a62d723815dad650884714e801421b6d7cb34f91Jack Yu            rec.setEmails(emails);
440a62d723815dad650884714e801421b6d7cb34f91Jack Yu            log("Adding email list to ADN (0x" +
441a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    Integer.toHexString(mPhoneBookRecords.get(i).getEfid()).toUpperCase() +
442a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    ") record #" + mPhoneBookRecords.get(i).getRecId());
443a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mPhoneBookRecords.set(i, rec);
4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
447a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Read email from the record of EF_EMAIL
448a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private String readEmailRecord(int recId) {
449a62d723815dad650884714e801421b6d7cb34f91Jack Yu        byte[] emailRec;
4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
451a62d723815dad650884714e801421b6d7cb34f91Jack Yu            emailRec = mEmailFileRecord.get(recId);
4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (IndexOutOfBoundsException e) {
4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return null;
4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        // The length of the record is X+2 byte, where X bytes is the email address
457a62d723815dad650884714e801421b6d7cb34f91Jack Yu        return IccUtils.adnStringFieldToString(emailRec, 0, emailRec.length - 2);
4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
460a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Read EF_ADN file
461a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private void readAdnFileAndWait(int recId) {
462a62d723815dad650884714e801421b6d7cb34f91Jack Yu        SparseArray<File> files;
463a62d723815dad650884714e801421b6d7cb34f91Jack Yu        files = mPbrRecords.get(recId).mFileIds;
464a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (files == null || files.size() == 0) return;
4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int extEf = 0;
467a62d723815dad650884714e801421b6d7cb34f91Jack Yu        // Only call fileIds.get while EF_EXT1_TAG is available
468a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (files.get(USIM_EFEXT1_TAG) != null) {
469a62d723815dad650884714e801421b6d7cb34f91Jack Yu            extEf = files.get(USIM_EFEXT1_TAG).getEfid();
4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
472a62d723815dad650884714e801421b6d7cb34f91Jack Yu        if (files.get(USIM_EFADN_TAG) == null)
473a62d723815dad650884714e801421b6d7cb34f91Jack Yu            return;
474a62d723815dad650884714e801421b6d7cb34f91Jack Yu
475a62d723815dad650884714e801421b6d7cb34f91Jack Yu        int previousSize = mPhoneBookRecords.size();
476a62d723815dad650884714e801421b6d7cb34f91Jack Yu        mAdnCache.requestLoadAllAdnLike(files.get(USIM_EFADN_TAG).getEfid(),
4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            extEf, obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mLock.wait();
4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (InterruptedException e) {
481ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
483a62d723815dad650884714e801421b6d7cb34f91Jack Yu
484a62d723815dad650884714e801421b6d7cb34f91Jack Yu        /**
485a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * The recent added ADN record # would be the reference record size
486a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * for the rest of EFs associated within this PBR.
487a62d723815dad650884714e801421b6d7cb34f91Jack Yu         */
488a62d723815dad650884714e801421b6d7cb34f91Jack Yu        mPbrRecords.get(recId).mMasterFileRecordNum = mPhoneBookRecords.size() - previousSize;
4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
491a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // Create the phonebook reference file based on EF_PBR
4920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void createPbrFile(ArrayList<byte[]> records) {
4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        if (records == null) {
494a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mPbrRecords = null;
4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            mIsPbrPresent = false;
4960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return;
4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
498a62d723815dad650884714e801421b6d7cb34f91Jack Yu
49996cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu        mPbrRecords = new ArrayList<PbrRecord>();
500a62d723815dad650884714e801421b6d7cb34f91Jack Yu        for (int i = 0; i < records.size(); i++) {
50196cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu            // Some cards have two records but the 2nd record is filled with all invalid char 0xff.
50296cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu            // So we need to check if the record is valid or not before adding into the PBR records.
50396cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu            if (records.get(i)[0] != INVALID_BYTE) {
50496cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu                mPbrRecords.add(new PbrRecord(records.get(i)));
50596cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu            }
506a62d723815dad650884714e801421b6d7cb34f91Jack Yu        }
507a62d723815dad650884714e801421b6d7cb34f91Jack Yu
508a62d723815dad650884714e801421b6d7cb34f91Jack Yu        for (PbrRecord record : mPbrRecords) {
50996cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu            File file = record.mFileIds.get(USIM_EFADN_TAG);
51096cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu            // If the file does not contain EF_ADN, we'll just skip it.
51196cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu            if (file != null) {
51296cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu                int sfi = file.getSfi();
51396cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu                if (sfi != INVALID_SFI) {
51496cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu                    mSfiEfidTable.put(sfi, record.mFileIds.get(USIM_EFADN_TAG).getEfid());
51596cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu                }
51696cf37fcb4f67cbf52df84ca307c76ff9f463791Jack Yu            }
517a62d723815dad650884714e801421b6d7cb34f91Jack Yu        }
5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    @Override
5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public void handleMessage(Message msg) {
5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        AsyncResult ar;
5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        switch(msg.what) {
5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_PBR_LOAD_DONE:
5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception == null) {
5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                createPbrFile((ArrayList<byte[]>)ar.result);
5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            synchronized (mLock) {
5310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.notify();
5320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
5340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_USIM_ADN_LOAD_DONE:
5350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            log("Loading USIM ADN records done");
5360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
5370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception == null) {
5380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mPhoneBookRecords.addAll((ArrayList<AdnRecord>)ar.result);
5390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            synchronized (mLock) {
5410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.notify();
5420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
5440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_IAP_LOAD_DONE:
5450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            log("Loading USIM IAP records done");
5460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
5470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception == null) {
5480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mIapFileRecord = ((ArrayList<byte[]>)ar.result);
5490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            synchronized (mLock) {
5510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.notify();
5520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
5540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        case EVENT_EMAIL_LOAD_DONE:
5550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            log("Loading USIM Email records done");
5560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ar = (AsyncResult) msg.obj;
5570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ar.exception == null) {
5580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mEmailFileRecord = ((ArrayList<byte[]>)ar.result);
5590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
5610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            synchronized (mLock) {
5620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                mLock.notify();
5630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
5640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            break;
5650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
5670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
568a62d723815dad650884714e801421b6d7cb34f91Jack Yu    // PbrRecord represents a record in EF_PBR
569a62d723815dad650884714e801421b6d7cb34f91Jack Yu    private class PbrRecord {
570a62d723815dad650884714e801421b6d7cb34f91Jack Yu        // TLV tags
571a62d723815dad650884714e801421b6d7cb34f91Jack Yu        private SparseArray<File> mFileIds;
572a62d723815dad650884714e801421b6d7cb34f91Jack Yu
573a62d723815dad650884714e801421b6d7cb34f91Jack Yu        /**
574a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * 3GPP TS 31.102 4.4.2.1 EF_PBR (Phone Book Reference file)
575a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * If this is type 1 files, files that contain as many records as the
576a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * reference/master file (EF_ADN, EF_ADN1) and are linked on record number
577a62d723815dad650884714e801421b6d7cb34f91Jack Yu         * bases (Rec1 -> Rec1). The master file record number is the reference.
578a62d723815dad650884714e801421b6d7cb34f91Jack Yu         */
579a62d723815dad650884714e801421b6d7cb34f91Jack Yu        private int mMasterFileRecordNum;
580a62d723815dad650884714e801421b6d7cb34f91Jack Yu
581a62d723815dad650884714e801421b6d7cb34f91Jack Yu        PbrRecord(byte[] record) {
582a62d723815dad650884714e801421b6d7cb34f91Jack Yu            mFileIds = new SparseArray<File>();
5830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            SimTlv recTlv;
584a62d723815dad650884714e801421b6d7cb34f91Jack Yu            log("PBR rec: " + IccUtils.bytesToHexString(record));
585a62d723815dad650884714e801421b6d7cb34f91Jack Yu            recTlv = new SimTlv(record, 0, record.length);
586a62d723815dad650884714e801421b6d7cb34f91Jack Yu            parseTag(recTlv);
5870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
5880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
589a62d723815dad650884714e801421b6d7cb34f91Jack Yu        void parseTag(SimTlv tlv) {
590a62d723815dad650884714e801421b6d7cb34f91Jack Yu            SimTlv tlvEfSfi;
5910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int tag;
5920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data;
593a62d723815dad650884714e801421b6d7cb34f91Jack Yu
5940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            do {
5950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tag = tlv.getTag();
5960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                switch(tag) {
5970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case USIM_TYPE1_TAG: // A8
5980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case USIM_TYPE3_TAG: // AA
5990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                case USIM_TYPE2_TAG: // A9
6000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    data = tlv.getData();
601a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    tlvEfSfi = new SimTlv(data, 0, data.length);
602a62d723815dad650884714e801421b6d7cb34f91Jack Yu                    parseEfAndSFI(tlvEfSfi, tag);
6030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    break;
6040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
6050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } while (tlv.nextObject());
6060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
608a62d723815dad650884714e801421b6d7cb34f91Jack Yu        void parseEfAndSFI(SimTlv tlv, int parentTag) {
6090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int tag;
6100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            byte[] data;
6110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int tagNumberWithinParentTag = 0;
6120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            do {
6130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tag = tlv.getTag();
6140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                switch(tag) {
6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFEMAIL_TAG:
6160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFADN_TAG:
6170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFEXT1_TAG:
6180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFANR_TAG:
6190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFPBC_TAG:
6200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFGRP_TAG:
6210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFAAS_TAG:
6220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFGSD_TAG:
6230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFUID_TAG:
6240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFCCP1_TAG:
6250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFIAP_TAG:
6260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    case USIM_EFSNE_TAG:
627a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        /** 3GPP TS 31.102, 4.4.2.1 EF_PBR (Phone Book Reference file)
628a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         *
629a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         * The SFI value assigned to an EF which is indicated in EF_PBR shall
630a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         * correspond to the SFI indicated in the TLV object in EF_PBR.
631a62d723815dad650884714e801421b6d7cb34f91Jack Yu
632a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         * The primitive tag identifies clearly the type of data, its value
633a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         * field indicates the file identifier and, if applicable, the SFI
634a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         * value of the specified EF. That is, the length value of a primitive
635a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         * tag indicates if an SFI value is available for the EF or not:
636a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         * - Length = '02' Value: 'EFID (2 bytes)'
637a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         * - Length = '03' Value: 'EFID (2 bytes)', 'SFI (1 byte)'
638a62d723815dad650884714e801421b6d7cb34f91Jack Yu                         */
639a62d723815dad650884714e801421b6d7cb34f91Jack Yu
640a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        int sfi = INVALID_SFI;
6410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        data = tlv.getData();
642a62d723815dad650884714e801421b6d7cb34f91Jack Yu
643a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        if (data.length < 2 || data.length > 3) {
644a62d723815dad650884714e801421b6d7cb34f91Jack Yu                            log("Invalid TLV length: " + data.length);
645a62d723815dad650884714e801421b6d7cb34f91Jack Yu                            break;
646a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        }
647a62d723815dad650884714e801421b6d7cb34f91Jack Yu
648a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        if (data.length == 3) {
649a62d723815dad650884714e801421b6d7cb34f91Jack Yu                            sfi = data[2] & 0xFF;
650a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        }
651a62d723815dad650884714e801421b6d7cb34f91Jack Yu
6520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
653a62d723815dad650884714e801421b6d7cb34f91Jack Yu
654a62d723815dad650884714e801421b6d7cb34f91Jack Yu                        mFileIds.put(tag, new File(parentTag, efid, sfi, tagNumberWithinParentTag));
6550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        break;
6560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
657a62d723815dad650884714e801421b6d7cb34f91Jack Yu                tagNumberWithinParentTag++;
6580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } while(tlv.nextObject());
6590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
6600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
6610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
6620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private void log(String msg) {
663ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        if(DBG) Rlog.d(LOG_TAG, msg);
6640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
665a62d723815dad650884714e801421b6d7cb34f91Jack Yu}