Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony;
     18 
     19 import android.os.AsyncResult;
     20 import android.os.Handler;
     21 import android.os.Message;
     22 import android.util.Log;
     23 import android.util.SparseArray;
     24 
     25 import com.android.internal.telephony.gsm.UsimPhoneBookManager;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Iterator;
     29 
     30 /**
     31  * {@hide}
     32  */
     33 public final class AdnRecordCache extends Handler implements IccConstants {
     34     //***** Instance Variables
     35 
     36     PhoneBase phone;
     37     private UsimPhoneBookManager mUsimPhoneBookManager;
     38 
     39     // Indexed by EF ID
     40     SparseArray<ArrayList<AdnRecord>> adnLikeFiles
     41         = new SparseArray<ArrayList<AdnRecord>>();
     42 
     43     // People waiting for ADN-like files to be loaded
     44     SparseArray<ArrayList<Message>> adnLikeWaiters
     45         = new SparseArray<ArrayList<Message>>();
     46 
     47     // People waiting for adn record to be updated
     48     SparseArray<Message> userWriteResponse = new SparseArray<Message>();
     49 
     50     //***** Event Constants
     51 
     52     static final int EVENT_LOAD_ALL_ADN_LIKE_DONE = 1;
     53     static final int EVENT_UPDATE_ADN_DONE = 2;
     54 
     55     //***** Constructor
     56 
     57 
     58 
     59     public AdnRecordCache(PhoneBase phone) {
     60         this.phone = phone;
     61         mUsimPhoneBookManager = new UsimPhoneBookManager(phone, this);
     62     }
     63 
     64     //***** Called from SIMRecords
     65 
     66     /**
     67      * Called from SIMRecords.onRadioNotAvailable and SIMRecords.handleSimRefresh.
     68      */
     69     public void reset() {
     70         adnLikeFiles.clear();
     71         mUsimPhoneBookManager.reset();
     72 
     73         clearWaiters();
     74         clearUserWriters();
     75 
     76     }
     77 
     78     private void clearWaiters() {
     79         int size = adnLikeWaiters.size();
     80         for (int i = 0; i < size; i++) {
     81             ArrayList<Message> waiters = adnLikeWaiters.valueAt(i);
     82             AsyncResult ar = new AsyncResult(null, null, new RuntimeException("AdnCache reset"));
     83             notifyWaiters(waiters, ar);
     84         }
     85         adnLikeWaiters.clear();
     86     }
     87 
     88     private void clearUserWriters() {
     89         int size = userWriteResponse.size();
     90         for (int i = 0; i < size; i++) {
     91             sendErrorResponse(userWriteResponse.valueAt(i), "AdnCace reset");
     92         }
     93         userWriteResponse.clear();
     94     }
     95 
     96     /**
     97      * @return List of AdnRecords for efid if we've already loaded them this
     98      * radio session, or null if we haven't
     99      */
    100     public ArrayList<AdnRecord>
    101     getRecordsIfLoaded(int efid) {
    102         return adnLikeFiles.get(efid);
    103     }
    104 
    105     /**
    106      * Returns extension ef associated with ADN-like EF or -1 if
    107      * we don't know.
    108      *
    109      * See 3GPP TS 51.011 for this mapping
    110      */
    111     int extensionEfForEf(int efid) {
    112         switch (efid) {
    113             case EF_MBDN: return EF_EXT6;
    114             case EF_ADN: return EF_EXT1;
    115             case EF_SDN: return EF_EXT3;
    116             case EF_FDN: return EF_EXT2;
    117             case EF_MSISDN: return EF_EXT1;
    118             case EF_PBR: return 0; // The EF PBR doesn't have an extension record
    119             default: return -1;
    120         }
    121     }
    122 
    123     private void sendErrorResponse(Message response, String errString) {
    124         if (response != null) {
    125             Exception e = new RuntimeException(errString);
    126             AsyncResult.forMessage(response).exception = e;
    127             response.sendToTarget();
    128         }
    129     }
    130 
    131     /**
    132      * Update an ADN-like record in EF by record index
    133      *
    134      * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
    135      * @param adn is the new adn to be stored
    136      * @param recordIndex is the 1-based adn record index
    137      * @param pin2 is required to update EF_FDN, otherwise must be null
    138      * @param response message to be posted when done
    139      *        response.exception hold the exception in error
    140      */
    141     public void updateAdnByIndex(int efid, AdnRecord adn, int recordIndex, String pin2,
    142             Message response) {
    143 
    144         int extensionEF = extensionEfForEf(efid);
    145         if (extensionEF < 0) {
    146             sendErrorResponse(response, "EF is not known ADN-like EF:" + efid);
    147             return;
    148         }
    149 
    150         Message pendingResponse = userWriteResponse.get(efid);
    151         if (pendingResponse != null) {
    152             sendErrorResponse(response, "Have pending update for EF:" + efid);
    153             return;
    154         }
    155 
    156         userWriteResponse.put(efid, response);
    157 
    158         new AdnRecordLoader(phone).updateEF(adn, efid, extensionEF,
    159                 recordIndex, pin2,
    160                 obtainMessage(EVENT_UPDATE_ADN_DONE, efid, recordIndex, adn));
    161     }
    162 
    163     /**
    164      * Replace oldAdn with newAdn in ADN-like record in EF
    165      *
    166      * The ADN-like records must be read through requestLoadAllAdnLike() before
    167      *
    168      * @param efid must be one of EF_ADN, EF_FDN, and EF_SDN
    169      * @param oldAdn is the adn to be replaced
    170      *        If oldAdn.isEmpty() is ture, it insert the newAdn
    171      * @param newAdn is the adn to be stored
    172      *        If newAdn.isEmpty() is true, it delete the oldAdn
    173      * @param pin2 is required to update EF_FDN, otherwise must be null
    174      * @param response message to be posted when done
    175      *        response.exception hold the exception in error
    176      */
    177     public void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn,
    178             String pin2, Message response) {
    179 
    180         int extensionEF;
    181         extensionEF = extensionEfForEf(efid);
    182 
    183         if (extensionEF < 0) {
    184             sendErrorResponse(response, "EF is not known ADN-like EF:" + efid);
    185             return;
    186         }
    187 
    188         ArrayList<AdnRecord>  oldAdnList;
    189 
    190         if (efid == EF_PBR) {
    191             oldAdnList = mUsimPhoneBookManager.loadEfFilesFromUsim();
    192         } else {
    193             oldAdnList = getRecordsIfLoaded(efid);
    194         }
    195 
    196         if (oldAdnList == null) {
    197             sendErrorResponse(response, "Adn list not exist for EF:" + efid);
    198             return;
    199         }
    200 
    201         int index = -1;
    202         int count = 1;
    203         for (Iterator<AdnRecord> it = oldAdnList.iterator(); it.hasNext(); ) {
    204             if (oldAdn.isEqual(it.next())) {
    205                 index = count;
    206                 break;
    207             }
    208             count++;
    209         }
    210 
    211         if (index == -1) {
    212             sendErrorResponse(response, "Adn record don't exist for " + oldAdn);
    213             return;
    214         }
    215 
    216         if (efid == EF_PBR) {
    217             AdnRecord foundAdn = oldAdnList.get(index-1);
    218             efid = foundAdn.efid;
    219             extensionEF = foundAdn.extRecord;
    220             index = foundAdn.recordNumber;
    221 
    222             newAdn.efid = efid;
    223             newAdn.extRecord = extensionEF;
    224             newAdn.recordNumber = index;
    225         }
    226 
    227         Message pendingResponse = userWriteResponse.get(efid);
    228 
    229         if (pendingResponse != null) {
    230             sendErrorResponse(response, "Have pending update for EF:" + efid);
    231             return;
    232         }
    233 
    234         userWriteResponse.put(efid, response);
    235 
    236         new AdnRecordLoader(phone).updateEF(newAdn, efid, extensionEF,
    237                 index, pin2,
    238                 obtainMessage(EVENT_UPDATE_ADN_DONE, efid, index, newAdn));
    239     }
    240 
    241 
    242     /**
    243      * Responds with exception (in response) if efid is not a known ADN-like
    244      * record
    245      */
    246     public void
    247     requestLoadAllAdnLike (int efid, int extensionEf, Message response) {
    248         ArrayList<Message> waiters;
    249         ArrayList<AdnRecord> result;
    250 
    251         if (efid == EF_PBR) {
    252             result = mUsimPhoneBookManager.loadEfFilesFromUsim();
    253         } else {
    254             result = getRecordsIfLoaded(efid);
    255         }
    256 
    257         // Have we already loaded this efid?
    258         if (result != null) {
    259             if (response != null) {
    260                 AsyncResult.forMessage(response).result = result;
    261                 response.sendToTarget();
    262             }
    263 
    264             return;
    265         }
    266 
    267         // Have we already *started* loading this efid?
    268 
    269         waiters = adnLikeWaiters.get(efid);
    270 
    271         if (waiters != null) {
    272             // There's a pending request for this EF already
    273             // just add ourselves to it
    274 
    275             waiters.add(response);
    276             return;
    277         }
    278 
    279         // Start loading efid
    280 
    281         waiters = new ArrayList<Message>();
    282         waiters.add(response);
    283 
    284         adnLikeWaiters.put(efid, waiters);
    285 
    286 
    287         if (extensionEf < 0) {
    288             // respond with error if not known ADN-like record
    289 
    290             if (response != null) {
    291                 AsyncResult.forMessage(response).exception
    292                     = new RuntimeException("EF is not known ADN-like EF:" + efid);
    293                 response.sendToTarget();
    294             }
    295 
    296             return;
    297         }
    298 
    299         new AdnRecordLoader(phone).loadAllFromEF(efid, extensionEf,
    300             obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, 0));
    301     }
    302 
    303     //***** Private methods
    304 
    305     private void
    306     notifyWaiters(ArrayList<Message> waiters, AsyncResult ar) {
    307 
    308         if (waiters == null) {
    309             return;
    310         }
    311 
    312         for (int i = 0, s = waiters.size() ; i < s ; i++) {
    313             Message waiter = waiters.get(i);
    314 
    315             AsyncResult.forMessage(waiter, ar.result, ar.exception);
    316             waiter.sendToTarget();
    317         }
    318     }
    319 
    320     //***** Overridden from Handler
    321 
    322     public void
    323     handleMessage(Message msg) {
    324         AsyncResult ar;
    325         int efid;
    326 
    327         switch(msg.what) {
    328             case EVENT_LOAD_ALL_ADN_LIKE_DONE:
    329                 /* arg1 is efid, obj.result is ArrayList<AdnRecord>*/
    330                 ar = (AsyncResult) msg.obj;
    331                 efid = msg.arg1;
    332                 ArrayList<Message> waiters;
    333 
    334                 waiters = adnLikeWaiters.get(efid);
    335                 adnLikeWaiters.delete(efid);
    336 
    337                 if (ar.exception == null) {
    338                     adnLikeFiles.put(efid, (ArrayList<AdnRecord>) ar.result);
    339                 }
    340                 notifyWaiters(waiters, ar);
    341                 break;
    342             case EVENT_UPDATE_ADN_DONE:
    343                 ar = (AsyncResult)msg.obj;
    344                 efid = msg.arg1;
    345                 int index = msg.arg2;
    346                 AdnRecord adn = (AdnRecord) (ar.userObj);
    347 
    348                 if (ar.exception == null) {
    349                     adnLikeFiles.get(efid).set(index - 1, adn);
    350                     mUsimPhoneBookManager.invalidateCache();
    351                 }
    352 
    353                 Message response = userWriteResponse.get(efid);
    354                 userWriteResponse.delete(efid);
    355 
    356                 AsyncResult.forMessage(response, null, ar.exception);
    357                 response.sendToTarget();
    358                 break;
    359         }
    360 
    361     }
    362 
    363 
    364 }
    365