Home | History | Annotate | Download | only in uicc
      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.uicc;
     18 
     19 import java.util.ArrayList;
     20 
     21 import android.os.AsyncResult;
     22 import android.os.Handler;
     23 import android.os.Looper;
     24 import android.os.Message;
     25 import android.telephony.Rlog;
     26 
     27 import com.android.internal.telephony.uicc.IccConstants;
     28 
     29 public class AdnRecordLoader extends Handler {
     30     final static String LOG_TAG = "AdnRecordLoader";
     31     final static boolean VDBG = false;
     32 
     33     //***** Instance Variables
     34 
     35     private IccFileHandler mFh;
     36     int mEf;
     37     int mExtensionEF;
     38     int mPendingExtLoads;
     39     Message mUserResponse;
     40     String mPin2;
     41 
     42     // For "load one"
     43     int mRecordNumber;
     44 
     45     // for "load all"
     46     ArrayList<AdnRecord> mAdns; // only valid after EVENT_ADN_LOAD_ALL_DONE
     47 
     48     // Either an AdnRecord or a reference to adns depending
     49     // if this is a load one or load all operation
     50     Object mResult;
     51 
     52     //***** Event Constants
     53 
     54     static final int EVENT_ADN_LOAD_DONE = 1;
     55     static final int EVENT_EXT_RECORD_LOAD_DONE = 2;
     56     static final int EVENT_ADN_LOAD_ALL_DONE = 3;
     57     static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4;
     58     static final int EVENT_UPDATE_RECORD_DONE = 5;
     59 
     60     //***** Constructor
     61 
     62     AdnRecordLoader(IccFileHandler fh) {
     63         // The telephony unit-test cases may create AdnRecords
     64         // in secondary threads
     65         super(Looper.getMainLooper());
     66         mFh = fh;
     67     }
     68 
     69     private String getEFPath(int efid) {
     70         if (efid == IccConstants.EF_ADN) {
     71             return IccConstants.MF_SIM + IccConstants.DF_TELECOM;
     72         }
     73 
     74         return null;
     75     }
     76 
     77     /**
     78      * Resulting AdnRecord is placed in response.obj.result
     79      * or response.obj.exception is set
     80      */
     81     public void
     82     loadFromEF(int ef, int extensionEF, int recordNumber,
     83                 Message response) {
     84         mEf = ef;
     85         mExtensionEF = extensionEF;
     86         mRecordNumber = recordNumber;
     87         mUserResponse = response;
     88 
     89        mFh.loadEFLinearFixed(
     90                ef, getEFPath(ef), recordNumber,
     91                obtainMessage(EVENT_ADN_LOAD_DONE));
     92     }
     93 
     94 
     95     /**
     96      * Resulting ArrayList&lt;adnRecord> is placed in response.obj.result
     97      * or response.obj.exception is set
     98      */
     99     public void
    100     loadAllFromEF(int ef, int extensionEF,
    101                 Message response) {
    102         mEf = ef;
    103         mExtensionEF = extensionEF;
    104         mUserResponse = response;
    105 
    106         /* If we are loading from EF_ADN, specifically
    107          * specify the path as well, since, on some cards,
    108          * the fileid is not unique.
    109          */
    110         mFh.loadEFLinearFixedAll(
    111                 ef, getEFPath(ef),
    112                 obtainMessage(EVENT_ADN_LOAD_ALL_DONE));
    113     }
    114 
    115     /**
    116      * Write adn to a EF SIM record
    117      * It will get the record size of EF record and compose hex adn array
    118      * then write the hex array to EF record
    119      *
    120      * @param adn is set with alphaTag and phone number
    121      * @param ef EF fileid
    122      * @param extensionEF extension EF fileid
    123      * @param recordNumber 1-based record index
    124      * @param pin2 for CHV2 operations, must be null if pin2 is not needed
    125      * @param response will be sent to its handler when completed
    126      */
    127     public void
    128     updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber,
    129             String pin2, Message response) {
    130         mEf = ef;
    131         mExtensionEF = extensionEF;
    132         mRecordNumber = recordNumber;
    133         mUserResponse = response;
    134         mPin2 = pin2;
    135 
    136         mFh.getEFLinearRecordSize( ef, getEFPath(ef),
    137                 obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn));
    138      }
    139 
    140     //***** Overridden from Handler
    141 
    142     @Override
    143     public void
    144     handleMessage(Message msg) {
    145         AsyncResult ar;
    146         byte data[];
    147         AdnRecord adn;
    148 
    149         try {
    150             switch (msg.what) {
    151                 case EVENT_EF_LINEAR_RECORD_SIZE_DONE:
    152                     ar = (AsyncResult)(msg.obj);
    153                     adn = (AdnRecord)(ar.userObj);
    154 
    155                     if (ar.exception != null) {
    156                         throw new RuntimeException("get EF record size failed",
    157                                 ar.exception);
    158                     }
    159 
    160                     int[] recordSize = (int[])ar.result;
    161                     // recordSize is int[3] array
    162                     // int[0]  is the record length
    163                     // int[1]  is the total length of the EF file
    164                     // int[2]  is the number of records in the EF file
    165                     // So int[0] * int[2] = int[1]
    166                    if (recordSize.length != 3 || mRecordNumber > recordSize[2]) {
    167                         throw new RuntimeException("get wrong EF record size format",
    168                                 ar.exception);
    169                     }
    170 
    171                     data = adn.buildAdnString(recordSize[0]);
    172 
    173                     if(data == null) {
    174                         throw new RuntimeException("wrong ADN format",
    175                                 ar.exception);
    176                     }
    177 
    178 
    179                     mFh.updateEFLinearFixed(mEf, getEFPath(mEf), mRecordNumber,
    180                             data, mPin2, obtainMessage(EVENT_UPDATE_RECORD_DONE));
    181 
    182                     mPendingExtLoads = 1;
    183 
    184                     break;
    185                 case EVENT_UPDATE_RECORD_DONE:
    186                     ar = (AsyncResult)(msg.obj);
    187                     if (ar.exception != null) {
    188                         throw new RuntimeException("update EF adn record failed",
    189                                 ar.exception);
    190                     }
    191                     mPendingExtLoads = 0;
    192                     mResult = null;
    193                     break;
    194                 case EVENT_ADN_LOAD_DONE:
    195                     ar = (AsyncResult)(msg.obj);
    196                     data = (byte[])(ar.result);
    197 
    198                     if (ar.exception != null) {
    199                         throw new RuntimeException("load failed", ar.exception);
    200                     }
    201 
    202                     if (VDBG) {
    203                         Rlog.d(LOG_TAG,"ADN EF: 0x"
    204                             + Integer.toHexString(mEf)
    205                             + ":" + mRecordNumber
    206                             + "\n" + IccUtils.bytesToHexString(data));
    207                     }
    208 
    209                     adn = new AdnRecord(mEf, mRecordNumber, data);
    210                     mResult = adn;
    211 
    212                     if (adn.hasExtendedRecord()) {
    213                         // If we have a valid value in the ext record field,
    214                         // we're not done yet: we need to read the corresponding
    215                         // ext record and append it
    216 
    217                         mPendingExtLoads = 1;
    218 
    219                         mFh.loadEFLinearFixed(
    220                             mExtensionEF, adn.mExtRecord,
    221                             obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
    222                     }
    223                 break;
    224 
    225                 case EVENT_EXT_RECORD_LOAD_DONE:
    226                     ar = (AsyncResult)(msg.obj);
    227                     data = (byte[])(ar.result);
    228                     adn = (AdnRecord)(ar.userObj);
    229 
    230                     if (ar.exception != null) {
    231                         throw new RuntimeException("load failed", ar.exception);
    232                     }
    233 
    234                     Rlog.d(LOG_TAG,"ADN extension EF: 0x"
    235                         + Integer.toHexString(mExtensionEF)
    236                         + ":" + adn.mExtRecord
    237                         + "\n" + IccUtils.bytesToHexString(data));
    238 
    239                     adn.appendExtRecord(data);
    240 
    241                     mPendingExtLoads--;
    242                     // result should have been set in
    243                     // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE
    244                 break;
    245 
    246                 case EVENT_ADN_LOAD_ALL_DONE:
    247                     ar = (AsyncResult)(msg.obj);
    248                     ArrayList<byte[]> datas = (ArrayList<byte[]>)(ar.result);
    249 
    250                     if (ar.exception != null) {
    251                         throw new RuntimeException("load failed", ar.exception);
    252                     }
    253 
    254                     mAdns = new ArrayList<AdnRecord>(datas.size());
    255                     mResult = mAdns;
    256                     mPendingExtLoads = 0;
    257 
    258                     for(int i = 0, s = datas.size() ; i < s ; i++) {
    259                         adn = new AdnRecord(mEf, 1 + i, datas.get(i));
    260                         mAdns.add(adn);
    261 
    262                         if (adn.hasExtendedRecord()) {
    263                             // If we have a valid value in the ext record field,
    264                             // we're not done yet: we need to read the corresponding
    265                             // ext record and append it
    266 
    267                             mPendingExtLoads++;
    268 
    269                             mFh.loadEFLinearFixed(
    270                                 mExtensionEF, adn.mExtRecord,
    271                                 obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
    272                         }
    273                     }
    274                 break;
    275             }
    276         } catch (RuntimeException exc) {
    277             if (mUserResponse != null) {
    278                 AsyncResult.forMessage(mUserResponse)
    279                                 .exception = exc;
    280                 mUserResponse.sendToTarget();
    281                 // Loading is all or nothing--either every load succeeds
    282                 // or we fail the whole thing.
    283                 mUserResponse = null;
    284             }
    285             return;
    286         }
    287 
    288         if (mUserResponse != null && mPendingExtLoads == 0) {
    289             AsyncResult.forMessage(mUserResponse).result
    290                 = mResult;
    291 
    292             mUserResponse.sendToTarget();
    293             mUserResponse = null;
    294         }
    295     }
    296 
    297 
    298 }
    299