Home | History | Annotate | Download | only in uicc
      1 /*
      2  * Copyright (C) 2006, 2012 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 android.content.Context;
     20 import android.os.AsyncResult;
     21 import android.os.Handler;
     22 import android.os.Message;
     23 import android.os.Registrant;
     24 import android.os.RegistrantList;
     25 import android.telephony.Rlog;
     26 
     27 import com.android.internal.telephony.CommandsInterface;
     28 import com.android.internal.telephony.PhoneConstants;
     29 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
     30 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
     31 import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
     32 import com.android.internal.telephony.uicc.IccCardStatus.PinState;
     33 
     34 import java.io.FileDescriptor;
     35 import java.io.PrintWriter;
     36 
     37 /**
     38  * {@hide}
     39  */
     40 public class UiccCardApplication {
     41     private static final String LOG_TAG = "UiccCardApplication";
     42     private static final boolean DBG = true;
     43 
     44     private static final int EVENT_PIN1_PUK1_DONE = 1;
     45     private static final int EVENT_CHANGE_PIN1_DONE = 2;
     46     private static final int EVENT_CHANGE_PIN2_DONE = 3;
     47     private static final int EVENT_QUERY_FACILITY_FDN_DONE = 4;
     48     private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 5;
     49     private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 6;
     50     private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 7;
     51     private static final int EVENT_PIN2_PUK2_DONE = 8;
     52     private static final int EVENT_RADIO_UNAVAILABLE = 9;
     53 
     54     /**
     55      * These values are for authContext (parameter P2) per 3GPP TS 31.102 (Section 7.1.2)
     56      */
     57     public static final int AUTH_CONTEXT_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
     58     public static final int AUTH_CONTEXT_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
     59     public static final int AUTH_CONTEXT_UNDEFINED = PhoneConstants.AUTH_CONTEXT_UNDEFINED;
     60 
     61     private final Object  mLock = new Object();
     62     private UiccProfile   mUiccProfile; //parent
     63     private AppState      mAppState;
     64     private AppType       mAppType;
     65     private int           mAuthContext;
     66     private PersoSubState mPersoSubState;
     67     private String        mAid;
     68     private String        mAppLabel;
     69     private boolean       mPin1Replaced;
     70     private PinState      mPin1State;
     71     private PinState      mPin2State;
     72     private boolean       mIccFdnEnabled;
     73     private boolean       mDesiredFdnEnabled;
     74     private boolean       mIccLockEnabled;
     75     private boolean       mDesiredPinLocked;
     76 
     77     // App state will be ignored while deciding whether the card is ready or not.
     78     private boolean       mIgnoreApp;
     79     private boolean       mIccFdnAvailable = true; // Default is enabled.
     80 
     81     private CommandsInterface mCi;
     82     private Context mContext;
     83     private IccRecords mIccRecords;
     84     private IccFileHandler mIccFh;
     85 
     86     private boolean mDestroyed;//set to true once this App is commanded to be disposed of.
     87 
     88     private RegistrantList mReadyRegistrants = new RegistrantList();
     89     private RegistrantList mPinLockedRegistrants = new RegistrantList();
     90     private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
     91 
     92     public UiccCardApplication(UiccProfile uiccProfile,
     93                         IccCardApplicationStatus as,
     94                         Context c,
     95                         CommandsInterface ci) {
     96         if (DBG) log("Creating UiccApp: " + as);
     97         mUiccProfile = uiccProfile;
     98         mAppState = as.app_state;
     99         mAppType = as.app_type;
    100         mAuthContext = getAuthContext(mAppType);
    101         mPersoSubState = as.perso_substate;
    102         mAid = as.aid;
    103         mAppLabel = as.app_label;
    104         mPin1Replaced = (as.pin1_replaced != 0);
    105         mPin1State = as.pin1;
    106         mPin2State = as.pin2;
    107         mIgnoreApp = false;
    108 
    109         mContext = c;
    110         mCi = ci;
    111 
    112         mIccFh = createIccFileHandler(as.app_type);
    113         mIccRecords = createIccRecords(as.app_type, mContext, mCi);
    114         if (mAppState == AppState.APPSTATE_READY) {
    115             queryFdn();
    116             queryPin1State();
    117         }
    118         mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null);
    119     }
    120 
    121     public void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
    122         synchronized (mLock) {
    123             if (mDestroyed) {
    124                 loge("Application updated after destroyed! Fix me!");
    125                 return;
    126             }
    127 
    128             if (DBG) log(mAppType + " update. New " + as);
    129             mContext = c;
    130             mCi = ci;
    131             AppType oldAppType = mAppType;
    132             AppState oldAppState = mAppState;
    133             PersoSubState oldPersoSubState = mPersoSubState;
    134             mAppType = as.app_type;
    135             mAuthContext = getAuthContext(mAppType);
    136             mAppState = as.app_state;
    137             mPersoSubState = as.perso_substate;
    138             mAid = as.aid;
    139             mAppLabel = as.app_label;
    140             mPin1Replaced = (as.pin1_replaced != 0);
    141             mPin1State = as.pin1;
    142             mPin2State = as.pin2;
    143 
    144             if (mAppType != oldAppType) {
    145                 if (mIccFh != null) { mIccFh.dispose();}
    146                 if (mIccRecords != null) { mIccRecords.dispose();}
    147                 mIccFh = createIccFileHandler(as.app_type);
    148                 mIccRecords = createIccRecords(as.app_type, c, ci);
    149             }
    150 
    151             if (mPersoSubState != oldPersoSubState &&
    152                     mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
    153                 notifyNetworkLockedRegistrantsIfNeeded(null);
    154             }
    155 
    156             if (mAppState != oldAppState) {
    157                 if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);
    158                 // If the app state turns to APPSTATE_READY, then query FDN status,
    159                 //as it might have failed in earlier attempt.
    160                 if (mAppState == AppState.APPSTATE_READY) {
    161                     queryFdn();
    162                     queryPin1State();
    163                 }
    164                 notifyPinLockedRegistrantsIfNeeded(null);
    165                 notifyReadyRegistrantsIfNeeded(null);
    166             }
    167         }
    168     }
    169 
    170     void dispose() {
    171         synchronized (mLock) {
    172             if (DBG) log(mAppType + " being Disposed");
    173             mDestroyed = true;
    174             if (mIccRecords != null) { mIccRecords.dispose();}
    175             if (mIccFh != null) { mIccFh.dispose();}
    176             mIccRecords = null;
    177             mIccFh = null;
    178             mCi.unregisterForNotAvailable(mHandler);
    179         }
    180     }
    181 
    182     private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {
    183         if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {
    184             return new SIMRecords(this, c, ci);
    185         } else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){
    186             return new RuimRecords(this, c, ci);
    187         } else if (type == AppType.APPTYPE_ISIM) {
    188             return new IsimUiccRecords(this, c, ci);
    189         } else {
    190             // Unknown app type (maybe detection is still in progress)
    191             return null;
    192         }
    193     }
    194 
    195     private IccFileHandler createIccFileHandler(AppType type) {
    196         switch (type) {
    197             case APPTYPE_SIM:
    198                 return new SIMFileHandler(this, mAid, mCi);
    199             case APPTYPE_RUIM:
    200                 return new RuimFileHandler(this, mAid, mCi);
    201             case APPTYPE_USIM:
    202                 return new UsimFileHandler(this, mAid, mCi);
    203             case APPTYPE_CSIM:
    204                 return new CsimFileHandler(this, mAid, mCi);
    205             case APPTYPE_ISIM:
    206                 return new IsimFileHandler(this, mAid, mCi);
    207             default:
    208                 return null;
    209         }
    210     }
    211 
    212     /** Assumes mLock is held. */
    213     public void queryFdn() {
    214         //This shouldn't change run-time. So needs to be called only once.
    215         int serviceClassX;
    216 
    217         serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
    218                         CommandsInterface.SERVICE_CLASS_DATA +
    219                         CommandsInterface.SERVICE_CLASS_FAX;
    220         mCi.queryFacilityLockForApp (
    221                 CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
    222                 mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
    223     }
    224     /**
    225      * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
    226      * @param ar is asyncResult of Query_Facility_Locked
    227      */
    228     private void onQueryFdnEnabled(AsyncResult ar) {
    229         synchronized (mLock) {
    230             if (ar.exception != null) {
    231                 if (DBG) log("Error in querying facility lock:" + ar.exception);
    232                 return;
    233             }
    234 
    235             int[] result = (int[])ar.result;
    236             if(result.length != 0) {
    237                 //0 - Available & Disabled, 1-Available & Enabled, 2-Unavailable.
    238                 if (result[0] == 2) {
    239                     mIccFdnEnabled = false;
    240                     mIccFdnAvailable = false;
    241                 } else {
    242                     mIccFdnEnabled = (result[0] == 1) ? true : false;
    243                     mIccFdnAvailable = true;
    244                 }
    245                 log("Query facility FDN : FDN service available: "+ mIccFdnAvailable
    246                         +" enabled: "  + mIccFdnEnabled);
    247             } else {
    248                 loge("Bogus facility lock response");
    249             }
    250         }
    251     }
    252 
    253     private void onChangeFdnDone(AsyncResult ar) {
    254         synchronized (mLock) {
    255             int attemptsRemaining = -1;
    256 
    257             if (ar.exception == null) {
    258                 mIccFdnEnabled = mDesiredFdnEnabled;
    259                 if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
    260                         "mIccFdnEnabled=" + mIccFdnEnabled);
    261             } else {
    262                 attemptsRemaining = parsePinPukErrorResult(ar);
    263                 loge("Error change facility fdn with exception " + ar.exception);
    264             }
    265             Message response = (Message)ar.userObj;
    266             response.arg1 = attemptsRemaining;
    267             AsyncResult.forMessage(response).exception = ar.exception;
    268             response.sendToTarget();
    269         }
    270     }
    271 
    272     /** REMOVE when mIccLockEnabled is not needed, assumes mLock is held */
    273     private void queryPin1State() {
    274         int serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
    275                 CommandsInterface.SERVICE_CLASS_DATA +
    276                 CommandsInterface.SERVICE_CLASS_FAX;
    277         mCi.queryFacilityLockForApp (
    278             CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
    279             mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
    280     }
    281 
    282     /** REMOVE when mIccLockEnabled is not needed*/
    283     private void onQueryFacilityLock(AsyncResult ar) {
    284         synchronized (mLock) {
    285             if(ar.exception != null) {
    286                 if (DBG) log("Error in querying facility lock:" + ar.exception);
    287                 return;
    288             }
    289 
    290             int[] ints = (int[])ar.result;
    291             if(ints.length != 0) {
    292                 if (DBG) log("Query facility lock : "  + ints[0]);
    293 
    294                 mIccLockEnabled = (ints[0] != 0);
    295 
    296                 if (mIccLockEnabled) {
    297                     mPinLockedRegistrants.notifyRegistrants();
    298                 }
    299 
    300                 // Sanity check: we expect mPin1State to match mIccLockEnabled.
    301                 // When mPin1State is DISABLED mIccLockEanbled should be false.
    302                 // When mPin1State is ENABLED mIccLockEnabled should be true.
    303                 //
    304                 // Here we validate these assumptions to assist in identifying which ril/radio's
    305                 // have not correctly implemented GET_SIM_STATUS
    306                 switch (mPin1State) {
    307                     case PINSTATE_DISABLED:
    308                         if (mIccLockEnabled) {
    309                             loge("QUERY_FACILITY_LOCK:enabled GET_SIM_STATUS.Pin1:disabled."
    310                                     + " Fixme");
    311                         }
    312                         break;
    313                     case PINSTATE_ENABLED_NOT_VERIFIED:
    314                     case PINSTATE_ENABLED_VERIFIED:
    315                     case PINSTATE_ENABLED_BLOCKED:
    316                     case PINSTATE_ENABLED_PERM_BLOCKED:
    317                         if (!mIccLockEnabled) {
    318                             loge("QUERY_FACILITY_LOCK:disabled GET_SIM_STATUS.Pin1:enabled."
    319                                     + " Fixme");
    320                         }
    321                     case PINSTATE_UNKNOWN:
    322                     default:
    323                         if (DBG) log("Ignoring: pin1state=" + mPin1State);
    324                         break;
    325                 }
    326             } else {
    327                 loge("Bogus facility lock response");
    328             }
    329         }
    330     }
    331 
    332     /** REMOVE when mIccLockEnabled is not needed */
    333     private void onChangeFacilityLock(AsyncResult ar) {
    334         synchronized (mLock) {
    335             int attemptsRemaining = -1;
    336 
    337             if (ar.exception == null) {
    338                 mIccLockEnabled = mDesiredPinLocked;
    339                 if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: mIccLockEnabled= "
    340                         + mIccLockEnabled);
    341             } else {
    342                 attemptsRemaining = parsePinPukErrorResult(ar);
    343                 loge("Error change facility lock with exception " + ar.exception);
    344             }
    345             Message response = (Message)ar.userObj;
    346             AsyncResult.forMessage(response).exception = ar.exception;
    347             response.arg1 = attemptsRemaining;
    348             response.sendToTarget();
    349         }
    350     }
    351 
    352     /**
    353      * Parse the error response to obtain number of attempts remaining
    354      */
    355     private int parsePinPukErrorResult(AsyncResult ar) {
    356         int[] result = (int[]) ar.result;
    357         if (result == null) {
    358             return -1;
    359         } else {
    360             int length = result.length;
    361             int attemptsRemaining = -1;
    362             if (length > 0) {
    363                 attemptsRemaining = result[0];
    364             }
    365             log("parsePinPukErrorResult: attemptsRemaining=" + attemptsRemaining);
    366             return attemptsRemaining;
    367         }
    368     }
    369 
    370     private Handler mHandler = new Handler() {
    371         @Override
    372         public void handleMessage(Message msg){
    373             AsyncResult ar;
    374 
    375             if (mDestroyed) {
    376                 loge("Received message " + msg + "[" + msg.what
    377                         + "] while being destroyed. Ignoring.");
    378                 return;
    379             }
    380 
    381             switch (msg.what) {
    382                 case EVENT_PIN1_PUK1_DONE:
    383                 case EVENT_PIN2_PUK2_DONE:
    384                 case EVENT_CHANGE_PIN1_DONE:
    385                 case EVENT_CHANGE_PIN2_DONE:
    386                     // a PIN/PUK/PIN2/PUK2 complete
    387                     // request has completed. ar.userObj is the response Message
    388                     ar = (AsyncResult)msg.obj;
    389                     int attemptsRemaining = parsePinPukErrorResult(ar);
    390                     Message response = (Message)ar.userObj;
    391                     AsyncResult.forMessage(response).exception = ar.exception;
    392                     response.arg1 = attemptsRemaining;
    393                     response.sendToTarget();
    394                     break;
    395                 case EVENT_QUERY_FACILITY_FDN_DONE:
    396                     ar = (AsyncResult)msg.obj;
    397                     onQueryFdnEnabled(ar);
    398                     break;
    399                 case EVENT_CHANGE_FACILITY_FDN_DONE:
    400                     ar = (AsyncResult)msg.obj;
    401                     onChangeFdnDone(ar);
    402                     break;
    403                 case EVENT_QUERY_FACILITY_LOCK_DONE:
    404                     ar = (AsyncResult)msg.obj;
    405                     onQueryFacilityLock(ar);
    406                     break;
    407                 case EVENT_CHANGE_FACILITY_LOCK_DONE:
    408                     ar = (AsyncResult)msg.obj;
    409                     onChangeFacilityLock(ar);
    410                     break;
    411                 case EVENT_RADIO_UNAVAILABLE:
    412                     if (DBG) log("handleMessage (EVENT_RADIO_UNAVAILABLE)");
    413                     mAppState = AppState.APPSTATE_UNKNOWN;
    414                     break;
    415                 default:
    416                     loge("Unknown Event " + msg.what);
    417             }
    418         }
    419     };
    420 
    421     public void registerForReady(Handler h, int what, Object obj) {
    422         synchronized (mLock) {
    423             Registrant r = new Registrant (h, what, obj);
    424             mReadyRegistrants.add(r);
    425             notifyReadyRegistrantsIfNeeded(r);
    426         }
    427     }
    428 
    429     public void unregisterForReady(Handler h) {
    430         synchronized (mLock) {
    431             mReadyRegistrants.remove(h);
    432         }
    433     }
    434 
    435     /**
    436      * Notifies handler of any transition into State.isPinLocked()
    437      */
    438     protected void registerForLocked(Handler h, int what, Object obj) {
    439         synchronized (mLock) {
    440             Registrant r = new Registrant (h, what, obj);
    441             mPinLockedRegistrants.add(r);
    442             notifyPinLockedRegistrantsIfNeeded(r);
    443         }
    444     }
    445 
    446     protected void unregisterForLocked(Handler h) {
    447         synchronized (mLock) {
    448             mPinLockedRegistrants.remove(h);
    449         }
    450     }
    451 
    452     /**
    453      * Notifies handler of any transition into State.NETWORK_LOCKED
    454      */
    455     protected void registerForNetworkLocked(Handler h, int what, Object obj) {
    456         synchronized (mLock) {
    457             Registrant r = new Registrant (h, what, obj);
    458             mNetworkLockedRegistrants.add(r);
    459             notifyNetworkLockedRegistrantsIfNeeded(r);
    460         }
    461     }
    462 
    463     protected void unregisterForNetworkLocked(Handler h) {
    464         synchronized (mLock) {
    465             mNetworkLockedRegistrants.remove(h);
    466         }
    467     }
    468 
    469     /**
    470      * Notifies specified registrant, assume mLock is held.
    471      *
    472      * @param r Registrant to be notified. If null - all registrants will be notified
    473      */
    474     private void notifyReadyRegistrantsIfNeeded(Registrant r) {
    475         if (mDestroyed) {
    476             return;
    477         }
    478         if (mAppState == AppState.APPSTATE_READY) {
    479             if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
    480                     mPin1State == PinState.PINSTATE_ENABLED_BLOCKED ||
    481                     mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
    482                 loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!");
    483                 // Don't notify if application is in insane state
    484                 return;
    485             }
    486             if (r == null) {
    487                 if (DBG) log("Notifying registrants: READY");
    488                 mReadyRegistrants.notifyRegistrants();
    489             } else {
    490                 if (DBG) log("Notifying 1 registrant: READY");
    491                 r.notifyRegistrant(new AsyncResult(null, null, null));
    492             }
    493         }
    494     }
    495 
    496     /**
    497      * Notifies specified registrant, assume mLock is held.
    498      *
    499      * @param r Registrant to be notified. If null - all registrants will be notified
    500      */
    501     private void notifyPinLockedRegistrantsIfNeeded(Registrant r) {
    502         if (mDestroyed) {
    503             return;
    504         }
    505 
    506         if (mAppState == AppState.APPSTATE_PIN ||
    507                 mAppState == AppState.APPSTATE_PUK) {
    508             if (mPin1State == PinState.PINSTATE_ENABLED_VERIFIED ||
    509                     mPin1State == PinState.PINSTATE_DISABLED) {
    510                 loge("Sanity check failed! APPSTATE is locked while PIN1 is not!!!");
    511                 //Don't notify if application is in insane state
    512                 return;
    513             }
    514             if (r == null) {
    515                 if (DBG) log("Notifying registrants: LOCKED");
    516                 mPinLockedRegistrants.notifyRegistrants();
    517             } else {
    518                 if (DBG) log("Notifying 1 registrant: LOCKED");
    519                 r.notifyRegistrant(new AsyncResult(null, null, null));
    520             }
    521         }
    522     }
    523 
    524     /**
    525      * Notifies specified registrant, assume mLock is held.
    526      *
    527      * @param r Registrant to be notified. If null - all registrants will be notified
    528      */
    529     private void notifyNetworkLockedRegistrantsIfNeeded(Registrant r) {
    530         if (mDestroyed) {
    531             return;
    532         }
    533 
    534         if (mAppState == AppState.APPSTATE_SUBSCRIPTION_PERSO &&
    535                 mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
    536             if (r == null) {
    537                 if (DBG) log("Notifying registrants: NETWORK_LOCKED");
    538                 mNetworkLockedRegistrants.notifyRegistrants();
    539             } else {
    540                 if (DBG) log("Notifying 1 registrant: NETWORK_LOCED");
    541                 r.notifyRegistrant(new AsyncResult(null, null, null));
    542             }
    543         }
    544     }
    545 
    546     public AppState getState() {
    547         synchronized (mLock) {
    548             return mAppState;
    549         }
    550     }
    551 
    552     public AppType getType() {
    553         synchronized (mLock) {
    554             return mAppType;
    555         }
    556     }
    557 
    558     public int getAuthContext() {
    559         synchronized (mLock) {
    560             return mAuthContext;
    561         }
    562     }
    563 
    564     /**
    565      * Returns the authContext based on the type of UiccCard.
    566      *
    567      * @param appType the app type
    568      * @return authContext corresponding to the type or AUTH_CONTEXT_UNDEFINED if appType not
    569      * supported
    570      */
    571     private static int getAuthContext(AppType appType) {
    572         int authContext;
    573 
    574         switch (appType) {
    575             case APPTYPE_SIM:
    576                 authContext = AUTH_CONTEXT_EAP_SIM;
    577                 break;
    578 
    579             case APPTYPE_USIM:
    580                 authContext = AUTH_CONTEXT_EAP_AKA;
    581                 break;
    582 
    583             default:
    584                 authContext = AUTH_CONTEXT_UNDEFINED;
    585                 break;
    586         }
    587 
    588         return authContext;
    589     }
    590 
    591     public PersoSubState getPersoSubState() {
    592         synchronized (mLock) {
    593             return mPersoSubState;
    594         }
    595     }
    596 
    597     public String getAid() {
    598         synchronized (mLock) {
    599             return mAid;
    600         }
    601     }
    602 
    603     public String getAppLabel() {
    604         return mAppLabel;
    605     }
    606 
    607     public PinState getPin1State() {
    608         synchronized (mLock) {
    609             if (mPin1Replaced) {
    610                 return mUiccProfile.getUniversalPinState();
    611             }
    612             return mPin1State;
    613         }
    614     }
    615 
    616     public IccFileHandler getIccFileHandler() {
    617         synchronized (mLock) {
    618             return mIccFh;
    619         }
    620     }
    621 
    622     public IccRecords getIccRecords() {
    623         synchronized (mLock) {
    624             return mIccRecords;
    625         }
    626     }
    627 
    628     /**
    629      * Supply the ICC PIN to the ICC
    630      *
    631      * When the operation is complete, onComplete will be sent to its
    632      * Handler.
    633      *
    634      * onComplete.obj will be an AsyncResult
    635      * onComplete.arg1 = remaining attempts before puk locked or -1 if unknown
    636      *
    637      * ((AsyncResult)onComplete.obj).exception == null on success
    638      * ((AsyncResult)onComplete.obj).exception != null on fail
    639      *
    640      * If the supplied PIN is incorrect:
    641      * ((AsyncResult)onComplete.obj).exception != null
    642      * && ((AsyncResult)onComplete.obj).exception
    643      *       instanceof com.android.internal.telephony.gsm.CommandException)
    644      * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
    645      *          .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
    646      */
    647     public void supplyPin (String pin, Message onComplete) {
    648         synchronized (mLock) {
    649             mCi.supplyIccPinForApp(pin, mAid, mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE,
    650                     onComplete));
    651         }
    652     }
    653 
    654     /**
    655      * Supply the ICC PUK to the ICC
    656      *
    657      * When the operation is complete, onComplete will be sent to its
    658      * Handler.
    659      *
    660      * onComplete.obj will be an AsyncResult
    661      * onComplete.arg1 = remaining attempts before Icc will be permanently unusable
    662      * or -1 if unknown
    663      *
    664      * ((AsyncResult)onComplete.obj).exception == null on success
    665      * ((AsyncResult)onComplete.obj).exception != null on fail
    666      *
    667      * If the supplied PIN is incorrect:
    668      * ((AsyncResult)onComplete.obj).exception != null
    669      * && ((AsyncResult)onComplete.obj).exception
    670      *       instanceof com.android.internal.telephony.gsm.CommandException)
    671      * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
    672      *          .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
    673      *
    674      *
    675      */
    676     public void supplyPuk (String puk, String newPin, Message onComplete) {
    677         synchronized (mLock) {
    678         mCi.supplyIccPukForApp(puk, newPin, mAid,
    679                 mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE, onComplete));
    680         }
    681     }
    682 
    683     public void supplyPin2 (String pin2, Message onComplete) {
    684         synchronized (mLock) {
    685             mCi.supplyIccPin2ForApp(pin2, mAid,
    686                     mHandler.obtainMessage(EVENT_PIN2_PUK2_DONE, onComplete));
    687         }
    688     }
    689 
    690     public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
    691         synchronized (mLock) {
    692             mCi.supplyIccPuk2ForApp(puk2, newPin2, mAid,
    693                     mHandler.obtainMessage(EVENT_PIN2_PUK2_DONE, onComplete));
    694         }
    695     }
    696 
    697     public void supplyNetworkDepersonalization (String pin, Message onComplete) {
    698         synchronized (mLock) {
    699             if (DBG) log("supplyNetworkDepersonalization");
    700             mCi.supplyNetworkDepersonalization(pin, onComplete);
    701         }
    702     }
    703 
    704     /**
    705      * Check whether ICC pin lock is enabled
    706      * This is a sync call which returns the cached pin enabled state
    707      *
    708      * @return true for ICC locked enabled
    709      *         false for ICC locked disabled
    710      */
    711     public boolean getIccLockEnabled() {
    712         return mIccLockEnabled;
    713         /* STOPSHIP: Remove line above and all code associated with setting
    714            mIccLockEanbled once all RIL correctly sends the pin1 state.
    715         // Use getPin1State to take into account pin1Replaced flag
    716         PinState pinState = getPin1State();
    717         return pinState == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
    718                pinState == PinState.PINSTATE_ENABLED_VERIFIED ||
    719                pinState == PinState.PINSTATE_ENABLED_BLOCKED ||
    720                pinState == PinState.PINSTATE_ENABLED_PERM_BLOCKED;*/
    721      }
    722 
    723     /**
    724      * Check whether ICC fdn (fixed dialing number) is enabled
    725      * This is a sync call which returns the cached pin enabled state
    726      *
    727      * @return true for ICC fdn enabled
    728      *         false for ICC fdn disabled
    729      */
    730     public boolean getIccFdnEnabled() {
    731         synchronized (mLock) {
    732             return mIccFdnEnabled;
    733         }
    734     }
    735 
    736     /**
    737      * Check whether fdn (fixed dialing number) service is available.
    738      * @return true if ICC fdn service available
    739      *         false if ICC fdn service not available
    740      */
    741     public boolean getIccFdnAvailable() {
    742         return mIccFdnAvailable;
    743     }
    744 
    745     /**
    746      * Set the ICC pin lock enabled or disabled
    747      * When the operation is complete, onComplete will be sent to its handler
    748      *
    749      * @param enabled "true" for locked "false" for unlocked.
    750      * @param password needed to change the ICC pin state, aka. Pin1
    751      * @param onComplete
    752      *        onComplete.obj will be an AsyncResult
    753      *        ((AsyncResult)onComplete.obj).exception == null on success
    754      *        ((AsyncResult)onComplete.obj).exception != null on fail
    755      */
    756     public void setIccLockEnabled (boolean enabled,
    757             String password, Message onComplete) {
    758         synchronized (mLock) {
    759             int serviceClassX;
    760             serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
    761                     CommandsInterface.SERVICE_CLASS_DATA +
    762                     CommandsInterface.SERVICE_CLASS_FAX;
    763 
    764             mDesiredPinLocked = enabled;
    765 
    766             mCi.setFacilityLockForApp(CommandsInterface.CB_FACILITY_BA_SIM,
    767                     enabled, password, serviceClassX, mAid,
    768                     mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
    769         }
    770     }
    771 
    772     /**
    773      * Set the ICC fdn enabled or disabled
    774      * When the operation is complete, onComplete will be sent to its handler
    775      *
    776      * @param enabled "true" for locked "false" for unlocked.
    777      * @param password needed to change the ICC fdn enable, aka Pin2
    778      * @param onComplete
    779      *        onComplete.obj will be an AsyncResult
    780      *        ((AsyncResult)onComplete.obj).exception == null on success
    781      *        ((AsyncResult)onComplete.obj).exception != null on fail
    782      */
    783     public void setIccFdnEnabled (boolean enabled,
    784             String password, Message onComplete) {
    785         synchronized (mLock) {
    786             int serviceClassX;
    787             serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
    788                     CommandsInterface.SERVICE_CLASS_DATA +
    789                     CommandsInterface.SERVICE_CLASS_FAX +
    790                     CommandsInterface.SERVICE_CLASS_SMS;
    791 
    792             mDesiredFdnEnabled = enabled;
    793 
    794             mCi.setFacilityLockForApp(CommandsInterface.CB_FACILITY_BA_FD,
    795                     enabled, password, serviceClassX, mAid,
    796                     mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
    797         }
    798     }
    799 
    800     /**
    801      * Change the ICC password used in ICC pin lock
    802      * When the operation is complete, onComplete will be sent to its handler
    803      *
    804      * @param oldPassword is the old password
    805      * @param newPassword is the new password
    806      * @param onComplete
    807      *        onComplete.obj will be an AsyncResult
    808      *        onComplete.arg1 = attempts remaining or -1 if unknown
    809      *        ((AsyncResult)onComplete.obj).exception == null on success
    810      *        ((AsyncResult)onComplete.obj).exception != null on fail
    811      */
    812     public void changeIccLockPassword(String oldPassword, String newPassword,
    813             Message onComplete) {
    814         synchronized (mLock) {
    815             if (DBG) log("changeIccLockPassword");
    816             mCi.changeIccPinForApp(oldPassword, newPassword, mAid,
    817                     mHandler.obtainMessage(EVENT_CHANGE_PIN1_DONE, onComplete));
    818         }
    819     }
    820 
    821     /**
    822      * Change the ICC password used in ICC fdn enable
    823      * When the operation is complete, onComplete will be sent to its handler
    824      *
    825      * @param oldPassword is the old password
    826      * @param newPassword is the new password
    827      * @param onComplete
    828      *        onComplete.obj will be an AsyncResult
    829      *        ((AsyncResult)onComplete.obj).exception == null on success
    830      *        ((AsyncResult)onComplete.obj).exception != null on fail
    831      */
    832     public void changeIccFdnPassword(String oldPassword, String newPassword,
    833             Message onComplete) {
    834         synchronized (mLock) {
    835             if (DBG) log("changeIccFdnPassword");
    836             mCi.changeIccPin2ForApp(oldPassword, newPassword, mAid,
    837                     mHandler.obtainMessage(EVENT_CHANGE_PIN2_DONE, onComplete));
    838         }
    839     }
    840 
    841     /**
    842      * @return true if the UiccCardApplication is ready.
    843      */
    844     public boolean isReady() {
    845         synchronized (mLock) {
    846             if (mAppState != AppState.APPSTATE_READY) {
    847                 return false;
    848             } else if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED
    849                     || mPin1State == PinState.PINSTATE_ENABLED_BLOCKED
    850                     || mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
    851                 loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!");
    852                 return false;
    853             } else {
    854                 return true;
    855             }
    856         }
    857     }
    858 
    859     /**
    860      * @return true if ICC card is PIN2 blocked
    861      */
    862     public boolean getIccPin2Blocked() {
    863         synchronized (mLock) {
    864             return mPin2State == PinState.PINSTATE_ENABLED_BLOCKED;
    865         }
    866     }
    867 
    868     /**
    869      * @return true if ICC card is PUK2 blocked
    870      */
    871     public boolean getIccPuk2Blocked() {
    872         synchronized (mLock) {
    873             return mPin2State == PinState.PINSTATE_ENABLED_PERM_BLOCKED;
    874         }
    875     }
    876 
    877     public int getPhoneId() {
    878         return mUiccProfile.getPhoneId();
    879     }
    880 
    881     public boolean isAppIgnored() {
    882         return mIgnoreApp;
    883     }
    884 
    885     public void setAppIgnoreState(boolean ignore) {
    886         mIgnoreApp = ignore;
    887     }
    888 
    889     protected UiccProfile getUiccProfile() {
    890         return mUiccProfile;
    891     }
    892 
    893     private void log(String msg) {
    894         Rlog.d(LOG_TAG, msg);
    895     }
    896 
    897     private void loge(String msg) {
    898         Rlog.e(LOG_TAG, msg);
    899     }
    900 
    901     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    902         pw.println("UiccCardApplication: " + this);
    903         pw.println(" mUiccProfile=" + mUiccProfile);
    904         pw.println(" mAppState=" + mAppState);
    905         pw.println(" mAppType=" + mAppType);
    906         pw.println(" mPersoSubState=" + mPersoSubState);
    907         pw.println(" mAid=" + mAid);
    908         pw.println(" mAppLabel=" + mAppLabel);
    909         pw.println(" mPin1Replaced=" + mPin1Replaced);
    910         pw.println(" mPin1State=" + mPin1State);
    911         pw.println(" mPin2State=" + mPin2State);
    912         pw.println(" mIccFdnEnabled=" + mIccFdnEnabled);
    913         pw.println(" mDesiredFdnEnabled=" + mDesiredFdnEnabled);
    914         pw.println(" mIccLockEnabled=" + mIccLockEnabled);
    915         pw.println(" mDesiredPinLocked=" + mDesiredPinLocked);
    916         pw.println(" mCi=" + mCi);
    917         pw.println(" mIccRecords=" + mIccRecords);
    918         pw.println(" mIccFh=" + mIccFh);
    919         pw.println(" mDestroyed=" + mDestroyed);
    920         pw.println(" mReadyRegistrants: size=" + mReadyRegistrants.size());
    921         for (int i = 0; i < mReadyRegistrants.size(); i++) {
    922             pw.println("  mReadyRegistrants[" + i + "]="
    923                     + ((Registrant)mReadyRegistrants.get(i)).getHandler());
    924         }
    925         pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size());
    926         for (int i = 0; i < mPinLockedRegistrants.size(); i++) {
    927             pw.println("  mPinLockedRegistrants[" + i + "]="
    928                     + ((Registrant)mPinLockedRegistrants.get(i)).getHandler());
    929         }
    930         pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
    931         for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
    932             pw.println("  mNetworkLockedRegistrants[" + i + "]="
    933                     + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
    934         }
    935         pw.flush();
    936     }
    937 }
    938