PageRenderTime 80ms CodeModel.GetById 25ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 0ms

/android/upstream/com/android/internal/telephony/gsm/UsimPhoneBookManager.java

https://bitbucket.org/festevezga/xobotos
Java | 452 lines | 355 code | 50 blank | 47 comment | 63 complexity | ae83840d407f3082d7a792ea2502675f MD5 | raw file
  1/*
  2 * Copyright (C) 2009 The Android Open Source Project
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License");
  5 * you may not use this file except in compliance with the License.
  6 * You may obtain a copy of the License at
  7 *
  8 *      http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS,
 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13 * See the License for the specific language governing permissions and
 14 * limitations under the License.
 15 */
 16
 17package com.android.internal.telephony.gsm;
 18
 19import android.os.AsyncResult;
 20import android.os.Handler;
 21import android.os.Message;
 22import android.util.Log;
 23
 24import com.android.internal.telephony.AdnRecord;
 25import com.android.internal.telephony.AdnRecordCache;
 26import com.android.internal.telephony.IccConstants;
 27import com.android.internal.telephony.IccUtils;
 28import com.android.internal.telephony.PhoneBase;
 29
 30import java.util.ArrayList;
 31import java.util.HashMap;
 32import java.util.Map;
 33
 34/**
 35 * This class implements reading and parsing USIM records.
 36 * Refer to Spec 3GPP TS 31.102 for more details.
 37 *
 38 * {@hide}
 39 */
 40public class UsimPhoneBookManager extends Handler implements IccConstants {
 41    private static final String LOG_TAG = "GSM";
 42    private static final boolean DBG = true;
 43    private PbrFile mPbrFile;
 44    private Boolean mIsPbrPresent;
 45    private PhoneBase mPhone;
 46    private AdnRecordCache mAdnCache;
 47    private Object mLock = new Object();
 48    private ArrayList<AdnRecord> mPhoneBookRecords;
 49    private boolean mEmailPresentInIap = false;
 50    private int mEmailTagNumberInIap = 0;
 51    private ArrayList<byte[]> mIapFileRecord;
 52    private ArrayList<byte[]> mEmailFileRecord;
 53    private Map<Integer, ArrayList<String>> mEmailsForAdnRec;
 54    private boolean mRefreshCache = false;
 55
 56    private static final int EVENT_PBR_LOAD_DONE = 1;
 57    private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
 58    private static final int EVENT_IAP_LOAD_DONE = 3;
 59    private static final int EVENT_EMAIL_LOAD_DONE = 4;
 60
 61    private static final int USIM_TYPE1_TAG   = 0xA8;
 62    private static final int USIM_TYPE2_TAG   = 0xA9;
 63    private static final int USIM_TYPE3_TAG   = 0xAA;
 64    private static final int USIM_EFADN_TAG   = 0xC0;
 65    private static final int USIM_EFIAP_TAG   = 0xC1;
 66    private static final int USIM_EFEXT1_TAG  = 0xC2;
 67    private static final int USIM_EFSNE_TAG   = 0xC3;
 68    private static final int USIM_EFANR_TAG   = 0xC4;
 69    private static final int USIM_EFPBC_TAG   = 0xC5;
 70    private static final int USIM_EFGRP_TAG   = 0xC6;
 71    private static final int USIM_EFAAS_TAG   = 0xC7;
 72    private static final int USIM_EFGSD_TAG   = 0xC8;
 73    private static final int USIM_EFUID_TAG   = 0xC9;
 74    private static final int USIM_EFEMAIL_TAG = 0xCA;
 75    private static final int USIM_EFCCP1_TAG  = 0xCB;
 76
 77    public UsimPhoneBookManager(PhoneBase phone, AdnRecordCache cache) {
 78        mPhone = phone;
 79        mPhoneBookRecords = new ArrayList<AdnRecord>();
 80        mPbrFile = null;
 81        // We assume its present, after the first read this is updated.
 82        // So we don't have to read from UICC if its not present on subsequent reads.
 83        mIsPbrPresent = true;
 84        mAdnCache = cache;
 85    }
 86
 87    public void reset() {
 88        mPhoneBookRecords.clear();
 89        mIapFileRecord = null;
 90        mEmailFileRecord = null;
 91        mPbrFile = null;
 92        mIsPbrPresent = true;
 93        mRefreshCache = false;
 94    }
 95
 96    public ArrayList<AdnRecord> loadEfFilesFromUsim() {
 97        synchronized (mLock) {
 98            if (!mPhoneBookRecords.isEmpty()) {
 99                if (mRefreshCache) {
100                    mRefreshCache = false;
101                    refreshCache();
102                }
103                return mPhoneBookRecords;
104            }
105
106            if (!mIsPbrPresent) return null;
107
108            // Check if the PBR file is present in the cache, if not read it
109            // from the USIM.
110            if (mPbrFile == null) {
111                readPbrFileAndWait();
112            }
113
114            if (mPbrFile == null) return null;
115
116            int numRecs = mPbrFile.mFileIds.size();
117            for (int i = 0; i < numRecs; i++) {
118                readAdnFileAndWait(i);
119                readEmailFileAndWait(i);
120            }
121            // All EF files are loaded, post the response.
122        }
123        return mPhoneBookRecords;
124    }
125
126    private void refreshCache() {
127        if (mPbrFile == null) return;
128        mPhoneBookRecords.clear();
129
130        int numRecs = mPbrFile.mFileIds.size();
131        for (int i = 0; i < numRecs; i++) {
132            readAdnFileAndWait(i);
133        }
134    }
135
136    public void invalidateCache() {
137        mRefreshCache = true;
138    }
139
140    private void readPbrFileAndWait() {
141        mPhone.getIccFileHandler().loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
142        try {
143            mLock.wait();
144        } catch (InterruptedException e) {
145            Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
146        }
147    }
148
149    private void readEmailFileAndWait(int recNum) {
150        Map <Integer,Integer> fileIds;
151        fileIds = mPbrFile.mFileIds.get(recNum);
152        if (fileIds == null) return;
153
154        if (fileIds.containsKey(USIM_EFEMAIL_TAG)) {
155            int efid = fileIds.get(USIM_EFEMAIL_TAG);
156            // Check if the EFEmail is a Type 1 file or a type 2 file.
157            // If mEmailPresentInIap is true, its a type 2 file.
158            // So we read the IAP file and then read the email records.
159            // instead of reading directly.
160            if (mEmailPresentInIap) {
161                readIapFileAndWait(fileIds.get(USIM_EFIAP_TAG));
162                if (mIapFileRecord == null) {
163                    Log.e(LOG_TAG, "Error: IAP file is empty");
164                    return;
165                }
166            }
167            // Read the EFEmail file.
168            mPhone.getIccFileHandler().loadEFLinearFixedAll(fileIds.get(USIM_EFEMAIL_TAG),
169                    obtainMessage(EVENT_EMAIL_LOAD_DONE));
170            try {
171                mLock.wait();
172            } catch (InterruptedException e) {
173                Log.e(LOG_TAG, "Interrupted Exception in readEmailFileAndWait");
174            }
175
176            if (mEmailFileRecord == null) {
177                Log.e(LOG_TAG, "Error: Email file is empty");
178                return;
179            }
180            updatePhoneAdnRecord();
181        }
182
183    }
184
185    private void readIapFileAndWait(int efid) {
186        mPhone.getIccFileHandler().loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
187        try {
188            mLock.wait();
189        } catch (InterruptedException e) {
190            Log.e(LOG_TAG, "Interrupted Exception in readIapFileAndWait");
191        }
192    }
193
194    private void updatePhoneAdnRecord() {
195        if (mEmailFileRecord == null) return;
196        int numAdnRecs = mPhoneBookRecords.size();
197        if (mIapFileRecord != null) {
198            // The number of records in the IAP file is same as the number of records in ADN file.
199            // The order of the pointers in an EFIAP shall be the same as the order of file IDs
200            // that appear in the TLV object indicated by Tag 'A9' in the reference file record.
201            // i.e value of mEmailTagNumberInIap
202
203            for (int i = 0; i < numAdnRecs; i++) {
204                byte[] record = null;
205                try {
206                    record = mIapFileRecord.get(i);
207                } catch (IndexOutOfBoundsException e) {
208                    Log.e(LOG_TAG, "Error: Improper ICC card: No IAP record for ADN, continuing");
209                    break;
210                }
211                int recNum = record[mEmailTagNumberInIap];
212
213                if (recNum != -1) {
214                    String[] emails = new String[1];
215                    // SIM record numbers are 1 based
216                    emails[0] = readEmailRecord(recNum - 1);
217                    AdnRecord rec = mPhoneBookRecords.get(i);
218                    if (rec != null) {
219                        rec.setEmails(emails);
220                    } else {
221                        // might be a record with only email
222                        rec = new AdnRecord("", "", emails);
223                    }
224                    mPhoneBookRecords.set(i, rec);
225                }
226            }
227        }
228
229        // ICC cards can be made such that they have an IAP file but all
230        // records are empty. So we read both type 1 and type 2 file
231        // email records, just to be sure.
232
233        int len = mPhoneBookRecords.size();
234        // Type 1 file, the number of records is the same as the number of
235        // records in the ADN file.
236        if (mEmailsForAdnRec == null) {
237            parseType1EmailFile(len);
238        }
239        for (int i = 0; i < numAdnRecs; i++) {
240            ArrayList<String> emailList = null;
241            try {
242                emailList = mEmailsForAdnRec.get(i);
243            } catch (IndexOutOfBoundsException e) {
244                break;
245            }
246            if (emailList == null) continue;
247
248            AdnRecord rec = mPhoneBookRecords.get(i);
249
250            String[] emails = new String[emailList.size()];
251            System.arraycopy(emailList.toArray(), 0, emails, 0, emailList.size());
252            rec.setEmails(emails);
253            mPhoneBookRecords.set(i, rec);
254        }
255    }
256
257    void parseType1EmailFile(int numRecs) {
258        mEmailsForAdnRec = new HashMap<Integer, ArrayList<String>>();
259        byte[] emailRec = null;
260        for (int i = 0; i < numRecs; i++) {
261            try {
262                emailRec = mEmailFileRecord.get(i);
263            } catch (IndexOutOfBoundsException e) {
264                Log.e(LOG_TAG, "Error: Improper ICC card: No email record for ADN, continuing");
265                break;
266            }
267            int adnRecNum = emailRec[emailRec.length - 1];
268
269            if (adnRecNum == -1) {
270                continue;
271            }
272
273            String email = readEmailRecord(i);
274
275            if (email == null || email.equals("")) {
276                continue;
277            }
278
279            // SIM record numbers are 1 based.
280            ArrayList<String> val = mEmailsForAdnRec.get(adnRecNum - 1);
281            if (val == null) {
282                val = new ArrayList<String>();
283            }
284            val.add(email);
285            // SIM record numbers are 1 based.
286            mEmailsForAdnRec.put(adnRecNum - 1, val);
287        }
288    }
289
290    private String readEmailRecord(int recNum) {
291        byte[] emailRec = null;
292        try {
293            emailRec = mEmailFileRecord.get(recNum);
294        } catch (IndexOutOfBoundsException e) {
295            return null;
296        }
297
298        // The length of the record is X+2 byte, where X bytes is the email address
299        String email = IccUtils.adnStringFieldToString(emailRec, 0, emailRec.length - 2);
300        return email;
301    }
302
303    private void readAdnFileAndWait(int recNum) {
304        Map <Integer,Integer> fileIds;
305        fileIds = mPbrFile.mFileIds.get(recNum);
306        if (fileIds == null || fileIds.isEmpty()) return;
307
308
309        int extEf = 0;
310        // Only call fileIds.get while EFEXT1_TAG is available
311        if (fileIds.containsKey(USIM_EFEXT1_TAG)) {
312            extEf = fileIds.get(USIM_EFEXT1_TAG);
313        }
314
315        mAdnCache.requestLoadAllAdnLike(fileIds.get(USIM_EFADN_TAG),
316            extEf, obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
317        try {
318            mLock.wait();
319        } catch (InterruptedException e) {
320            Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
321        }
322    }
323
324    private void createPbrFile(ArrayList<byte[]> records) {
325        if (records == null) {
326            mPbrFile = null;
327            mIsPbrPresent = false;
328            return;
329        }
330        mPbrFile = new PbrFile(records);
331    }
332
333    @Override
334    public void handleMessage(Message msg) {
335        AsyncResult ar;
336
337        switch(msg.what) {
338        case EVENT_PBR_LOAD_DONE:
339            ar = (AsyncResult) msg.obj;
340            if (ar.exception == null) {
341                createPbrFile((ArrayList<byte[]>)ar.result);
342            }
343            synchronized (mLock) {
344                mLock.notify();
345            }
346            break;
347        case EVENT_USIM_ADN_LOAD_DONE:
348            log("Loading USIM ADN records done");
349            ar = (AsyncResult) msg.obj;
350            if (ar.exception == null) {
351                mPhoneBookRecords.addAll((ArrayList<AdnRecord>)ar.result);
352            }
353            synchronized (mLock) {
354                mLock.notify();
355            }
356            break;
357        case EVENT_IAP_LOAD_DONE:
358            log("Loading USIM IAP records done");
359            ar = (AsyncResult) msg.obj;
360            if (ar.exception == null) {
361                mIapFileRecord = ((ArrayList<byte[]>)ar.result);
362            }
363            synchronized (mLock) {
364                mLock.notify();
365            }
366            break;
367        case EVENT_EMAIL_LOAD_DONE:
368            log("Loading USIM Email records done");
369            ar = (AsyncResult) msg.obj;
370            if (ar.exception == null) {
371                mEmailFileRecord = ((ArrayList<byte[]>)ar.result);
372            }
373
374            synchronized (mLock) {
375                mLock.notify();
376            }
377            break;
378        }
379    }
380
381    private class PbrFile {
382        // RecNum <EF Tag, efid>
383        HashMap<Integer,Map<Integer,Integer>> mFileIds;
384
385        PbrFile(ArrayList<byte[]> records) {
386            mFileIds = new HashMap<Integer, Map<Integer, Integer>>();
387            SimTlv recTlv;
388            int recNum = 0;
389            for (byte[] record: records) {
390                recTlv = new SimTlv(record, 0, record.length);
391                parseTag(recTlv, recNum);
392                recNum ++;
393            }
394        }
395
396        void parseTag(SimTlv tlv, int recNum) {
397            SimTlv tlvEf;
398            int tag;
399            byte[] data;
400            Map<Integer, Integer> val = new HashMap<Integer, Integer>();
401            do {
402                tag = tlv.getTag();
403                switch(tag) {
404                case USIM_TYPE1_TAG: // A8
405                case USIM_TYPE3_TAG: // AA
406                case USIM_TYPE2_TAG: // A9
407                    data = tlv.getData();
408                    tlvEf = new SimTlv(data, 0, data.length);
409                    parseEf(tlvEf, val, tag);
410                    break;
411                }
412            } while (tlv.nextObject());
413            mFileIds.put(recNum, val);
414        }
415
416        void parseEf(SimTlv tlv, Map<Integer, Integer> val, int parentTag) {
417            int tag;
418            byte[] data;
419            int tagNumberWithinParentTag = 0;
420            do {
421                tag = tlv.getTag();
422                if (parentTag == USIM_TYPE2_TAG && tag == USIM_EFEMAIL_TAG) {
423                    mEmailPresentInIap = true;
424                    mEmailTagNumberInIap = tagNumberWithinParentTag;
425                }
426                switch(tag) {
427                    case USIM_EFEMAIL_TAG:
428                    case USIM_EFADN_TAG:
429                    case USIM_EFEXT1_TAG:
430                    case USIM_EFANR_TAG:
431                    case USIM_EFPBC_TAG:
432                    case USIM_EFGRP_TAG:
433                    case USIM_EFAAS_TAG:
434                    case USIM_EFGSD_TAG:
435                    case USIM_EFUID_TAG:
436                    case USIM_EFCCP1_TAG:
437                    case USIM_EFIAP_TAG:
438                    case USIM_EFSNE_TAG:
439                        data = tlv.getData();
440                        int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
441                        val.put(tag, efid);
442                        break;
443                }
444                tagNumberWithinParentTag ++;
445            } while(tlv.nextObject());
446        }
447    }
448
449    private void log(String msg) {
450        if(DBG) Log.d(LOG_TAG, msg);
451    }
452}