Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 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;
     18 
     19 import static android.Manifest.permission.READ_PHONE_STATE;
     20 import android.app.ActivityManagerNative;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.os.AsyncResult;
     24 import android.os.Handler;
     25 import android.os.Message;
     26 import android.os.Registrant;
     27 import android.os.RegistrantList;
     28 import android.os.SystemProperties;
     29 import android.os.UserHandle;
     30 import android.util.Log;
     31 import android.telephony.ServiceState;
     32 import android.telephony.TelephonyManager;
     33 
     34 import com.android.internal.telephony.IccCardConstants.State;
     35 import com.android.internal.telephony.IccCardApplicationStatus.AppState;
     36 import com.android.internal.telephony.IccCardApplicationStatus.PersoSubState;
     37 import com.android.internal.telephony.IccCardStatus.CardState;
     38 import com.android.internal.telephony.IccCardStatus.PinState;
     39 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
     40 import com.android.internal.telephony.uicc.UiccController;
     41 import com.android.internal.telephony.Phone;
     42 
     43 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_STATE;
     44 
     45 /**
     46  * @Deprecated use {@link UiccController}.getUiccCard instead.
     47  *
     48  * The Phone App assumes that there is only one icc card, and one icc application
     49  * available at a time. Moreover, it assumes such object (represented with IccCard)
     50  * is available all the time (whether {@link RILConstants.RIL_REQUEST_GET_SIM_STATUS} returned
     51  * or not, whether card has desired application or not, whether there really is a card in the
     52  * slot or not).
     53  *
     54  * UiccController, however, can handle multiple instances of icc objects (multiple
     55  * {@link UiccCardApplication}, multiple {@link IccFileHandler}, multiple {@link IccRecords})
     56  * created and destroyed dynamically during phone operation.
     57  *
     58  * This class implements the IccCard interface that is always available (right after default
     59  * phone object is constructed) to expose the current (based on voice radio technology)
     60  * application on the uicc card, so that external apps won't break.
     61  */
     62 
     63 public class IccCardProxy extends Handler implements IccCard {
     64     private static final boolean DBG = true;
     65     private static final String LOG_TAG = "RIL_IccCardProxy";
     66 
     67     private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1;
     68     private static final int EVENT_RADIO_ON = 2;
     69     private static final int EVENT_ICC_CHANGED = 3;
     70     private static final int EVENT_ICC_ABSENT = 4;
     71     private static final int EVENT_ICC_LOCKED = 5;
     72     private static final int EVENT_APP_READY = 6;
     73     private static final int EVENT_RECORDS_LOADED = 7;
     74     private static final int EVENT_IMSI_READY = 8;
     75     private static final int EVENT_NETWORK_LOCKED = 9;
     76     private static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 11;
     77 
     78     private final Object mLock = new Object();
     79     private Context mContext;
     80     private CommandsInterface mCi;
     81 
     82     private RegistrantList mAbsentRegistrants = new RegistrantList();
     83     private RegistrantList mPinLockedRegistrants = new RegistrantList();
     84     private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
     85 
     86     private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp?
     87     private UiccController mUiccController = null;
     88     private UiccCard mUiccCard = null;
     89     private UiccCardApplication mUiccApplication = null;
     90     private IccRecords mIccRecords = null;
     91     private CdmaSubscriptionSourceManager mCdmaSSM = null;
     92     private boolean mRadioOn = false;
     93     private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast
     94                                         // ACTION_SIM_STATE_CHANGED intents
     95     private boolean mInitialized = false;
     96     private State mExternalState = State.UNKNOWN;
     97 
     98     public IccCardProxy(Context context, CommandsInterface ci) {
     99         log("Creating");
    100         this.mContext = context;
    101         this.mCi = ci;
    102         mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context,
    103                 ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
    104         mUiccController = UiccController.getInstance();
    105         mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
    106         ci.registerForOn(this,EVENT_RADIO_ON, null);
    107         ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
    108         setExternalState(State.NOT_READY);
    109     }
    110 
    111     public void dispose() {
    112         synchronized (mLock) {
    113             log("Disposing");
    114             //Cleanup icc references
    115             mUiccController.unregisterForIccChanged(this);
    116             mUiccController = null;
    117             mCi.unregisterForOn(this);
    118             mCi.unregisterForOffOrNotAvailable(this);
    119             mCdmaSSM.dispose(this);
    120         }
    121     }
    122 
    123     /*
    124      * The card application that the external world sees will be based on the
    125      * voice radio technology only!
    126      */
    127     public void setVoiceRadioTech(int radioTech) {
    128         synchronized (mLock) {
    129             if (DBG) {
    130                 log("Setting radio tech " + ServiceState.rilRadioTechnologyToString(radioTech));
    131             }
    132             if (ServiceState.isGsm(radioTech)) {
    133                 mCurrentAppType = UiccController.APP_FAM_3GPP;
    134             } else {
    135                 mCurrentAppType = UiccController.APP_FAM_3GPP2;
    136             }
    137             updateQuietMode();
    138         }
    139     }
    140 
    141     /**
    142      * In case of 3gpp2 we need to find out if subscription used is coming from
    143      * NV in which case we shouldn't broadcast any sim states changes.
    144      */
    145     private void updateQuietMode() {
    146         synchronized (mLock) {
    147             boolean oldQuietMode = mQuietMode;
    148             boolean newQuietMode;
    149             int cdmaSource = Phone.CDMA_SUBSCRIPTION_UNKNOWN;
    150             boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic()
    151                     == PhoneConstants.LTE_ON_CDMA_TRUE;
    152             if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
    153                 newQuietMode = false;
    154                 if (DBG) log("updateQuietMode: 3GPP subscription -> newQuietMode=" + newQuietMode);
    155             } else {
    156                 if (isLteOnCdmaMode) {
    157                     log("updateQuietMode: is cdma/lte device, force IccCardProxy into 3gpp mode");
    158                     mCurrentAppType = UiccController.APP_FAM_3GPP;
    159                 }
    160                 cdmaSource = mCdmaSSM != null ?
    161                         mCdmaSSM.getCdmaSubscriptionSource() : Phone.CDMA_SUBSCRIPTION_UNKNOWN;
    162 
    163                 newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV)
    164                         && (mCurrentAppType == UiccController.APP_FAM_3GPP2)
    165                         && !isLteOnCdmaMode;
    166             }
    167 
    168             if (mQuietMode == false && newQuietMode == true) {
    169                 // Last thing to do before switching to quiet mode is
    170                 // broadcast ICC_READY
    171                 log("Switching to QuietMode.");
    172                 setExternalState(State.READY);
    173                 mQuietMode = newQuietMode;
    174             } else if (mQuietMode == true && newQuietMode == false) {
    175                 if (DBG) {
    176                     log("updateQuietMode: Switching out from QuietMode."
    177                             + " Force broadcast of current state=" + mExternalState);
    178                 }
    179                 mQuietMode = newQuietMode;
    180                 setExternalState(mExternalState, true);
    181             }
    182             if (DBG) {
    183                 log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type="
    184                     + mCurrentAppType + " isLteOnCdmaMode=" + isLteOnCdmaMode
    185                     + " cdmaSource=" + cdmaSource + ")");
    186             }
    187             mInitialized = true;
    188             sendMessage(obtainMessage(EVENT_ICC_CHANGED));
    189         }
    190     }
    191 
    192     public void handleMessage(Message msg) {
    193         switch (msg.what) {
    194             case EVENT_RADIO_OFF_OR_UNAVAILABLE:
    195                 mRadioOn = false;
    196                 break;
    197             case EVENT_RADIO_ON:
    198                 mRadioOn = true;
    199                 if (!mInitialized) {
    200                     updateQuietMode();
    201                 }
    202                 break;
    203             case EVENT_ICC_CHANGED:
    204                 if (mInitialized) {
    205                     updateIccAvailability();
    206                 }
    207                 break;
    208             case EVENT_ICC_ABSENT:
    209                 mAbsentRegistrants.notifyRegistrants();
    210                 setExternalState(State.ABSENT);
    211                 break;
    212             case EVENT_ICC_LOCKED:
    213                 processLockedState();
    214                 break;
    215             case EVENT_APP_READY:
    216                 setExternalState(State.READY);
    217                 break;
    218             case EVENT_RECORDS_LOADED:
    219                 broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
    220                 break;
    221             case EVENT_IMSI_READY:
    222                 broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, null);
    223                 break;
    224             case EVENT_NETWORK_LOCKED:
    225                 mNetworkLockedRegistrants.notifyRegistrants();
    226                 setExternalState(State.NETWORK_LOCKED);
    227                 break;
    228             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
    229                 updateQuietMode();
    230                 break;
    231             default:
    232                 loge("Unhandled message with number: " + msg.what);
    233                 break;
    234         }
    235     }
    236 
    237     private void updateIccAvailability() {
    238         synchronized (mLock) {
    239             UiccCard newCard = mUiccController.getUiccCard();
    240             CardState state = CardState.CARDSTATE_ABSENT;
    241             UiccCardApplication newApp = null;
    242             IccRecords newRecords = null;
    243             if (newCard != null) {
    244                 state = newCard.getCardState();
    245                 newApp = newCard.getApplication(mCurrentAppType);
    246                 if (newApp != null) {
    247                     newRecords = newApp.getIccRecords();
    248                 }
    249             }
    250 
    251             if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
    252                 if (DBG) log("Icc changed. Reregestering.");
    253                 unregisterUiccCardEvents();
    254                 mUiccCard = newCard;
    255                 mUiccApplication = newApp;
    256                 mIccRecords = newRecords;
    257                 registerUiccCardEvents();
    258             }
    259 
    260             updateExternalState();
    261         }
    262     }
    263 
    264     private void updateExternalState() {
    265         if (mUiccCard == null || mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
    266             if (mRadioOn) {
    267                 setExternalState(State.ABSENT);
    268             } else {
    269                 setExternalState(State.NOT_READY);
    270             }
    271             return;
    272         }
    273 
    274         if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR ||
    275                 mUiccApplication == null) {
    276             setExternalState(State.UNKNOWN);
    277             return;
    278         }
    279 
    280         switch (mUiccApplication.getState()) {
    281             case APPSTATE_UNKNOWN:
    282             case APPSTATE_DETECTED:
    283                 setExternalState(State.UNKNOWN);
    284                 break;
    285             case APPSTATE_PIN:
    286                 setExternalState(State.PIN_REQUIRED);
    287                 break;
    288             case APPSTATE_PUK:
    289                 setExternalState(State.PUK_REQUIRED);
    290                 break;
    291             case APPSTATE_SUBSCRIPTION_PERSO:
    292                 if (mUiccApplication.getPersoSubState() == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
    293                     setExternalState(State.NETWORK_LOCKED);
    294                 } else {
    295                     setExternalState(State.UNKNOWN);
    296                 }
    297                 break;
    298             case APPSTATE_READY:
    299                 setExternalState(State.READY);
    300                 break;
    301         }
    302     }
    303 
    304     private void registerUiccCardEvents() {
    305         if (mUiccCard != null) mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
    306         if (mUiccApplication != null) {
    307             mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
    308             mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
    309             mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
    310         }
    311         if (mIccRecords != null) {
    312             mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
    313             mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
    314         }
    315     }
    316 
    317     private void unregisterUiccCardEvents() {
    318         if (mUiccCard != null) mUiccCard.unregisterForAbsent(this);
    319         if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
    320         if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
    321         if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
    322         if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this);
    323         if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this);
    324     }
    325 
    326     private void broadcastIccStateChangedIntent(String value, String reason) {
    327         synchronized (mLock) {
    328             if (mQuietMode) {
    329                 log("QuietMode: NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
    330                         + " reason " + reason);
    331                 return;
    332             }
    333 
    334             Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
    335             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    336             intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
    337             intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
    338             intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
    339 
    340             if (DBG) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
    341                     + " reason " + reason);
    342             ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
    343                     UserHandle.USER_ALL);
    344         }
    345     }
    346 
    347     private void processLockedState() {
    348         synchronized (mLock) {
    349             if (mUiccApplication == null) {
    350                 //Don't need to do anything if non-existent application is locked
    351                 return;
    352             }
    353             PinState pin1State = mUiccApplication.getPin1State();
    354             if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
    355                 setExternalState(State.PERM_DISABLED);
    356                 return;
    357             }
    358 
    359             AppState appState = mUiccApplication.getState();
    360             switch (appState) {
    361                 case APPSTATE_PIN:
    362                     mPinLockedRegistrants.notifyRegistrants();
    363                     setExternalState(State.PIN_REQUIRED);
    364                     break;
    365                 case APPSTATE_PUK:
    366                     setExternalState(State.PUK_REQUIRED);
    367                     break;
    368             }
    369         }
    370     }
    371 
    372     private void setExternalState(State newState, boolean override) {
    373         synchronized (mLock) {
    374             if (!override && newState == mExternalState) {
    375                 return;
    376             }
    377             mExternalState = newState;
    378             SystemProperties.set(PROPERTY_SIM_STATE, mExternalState.toString());
    379             broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
    380                     getIccStateReason(mExternalState));
    381         }
    382     }
    383 
    384     private void setExternalState(State newState) {
    385         setExternalState(newState, false);
    386     }
    387 
    388     public boolean getIccRecordsLoaded() {
    389         synchronized (mLock) {
    390             if (mIccRecords != null) {
    391                 return mIccRecords.getRecordsLoaded();
    392             }
    393             return false;
    394         }
    395     }
    396 
    397     private String getIccStateIntentString(State state) {
    398         switch (state) {
    399             case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
    400             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
    401             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
    402             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
    403             case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
    404             case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
    405             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
    406             default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
    407         }
    408     }
    409 
    410     /**
    411      * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED)
    412      * @return reason
    413      */
    414     private String getIccStateReason(State state) {
    415         switch (state) {
    416             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN;
    417             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK;
    418             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK;
    419             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED;
    420             default: return null;
    421        }
    422     }
    423 
    424     /* IccCard interface implementation */
    425     @Override
    426     public State getState() {
    427         synchronized (mLock) {
    428             return mExternalState;
    429         }
    430     }
    431 
    432     @Override
    433     public IccRecords getIccRecords() {
    434         synchronized (mLock) {
    435             return mIccRecords;
    436         }
    437     }
    438 
    439     @Override
    440     public IccFileHandler getIccFileHandler() {
    441         synchronized (mLock) {
    442             if (mUiccApplication != null) {
    443                 return mUiccApplication.getIccFileHandler();
    444             }
    445             return null;
    446         }
    447     }
    448 
    449     /**
    450      * Notifies handler of any transition into State.ABSENT
    451      */
    452     @Override
    453     public void registerForAbsent(Handler h, int what, Object obj) {
    454         synchronized (mLock) {
    455             Registrant r = new Registrant (h, what, obj);
    456 
    457             mAbsentRegistrants.add(r);
    458 
    459             if (getState() == State.ABSENT) {
    460                 r.notifyRegistrant();
    461             }
    462         }
    463     }
    464 
    465     @Override
    466     public void unregisterForAbsent(Handler h) {
    467         synchronized (mLock) {
    468             mAbsentRegistrants.remove(h);
    469         }
    470     }
    471 
    472     /**
    473      * Notifies handler of any transition into State.NETWORK_LOCKED
    474      */
    475     @Override
    476     public void registerForNetworkLocked(Handler h, int what, Object obj) {
    477         synchronized (mLock) {
    478             Registrant r = new Registrant (h, what, obj);
    479 
    480             mNetworkLockedRegistrants.add(r);
    481 
    482             if (getState() == State.NETWORK_LOCKED) {
    483                 r.notifyRegistrant();
    484             }
    485         }
    486     }
    487 
    488     @Override
    489     public void unregisterForNetworkLocked(Handler h) {
    490         synchronized (mLock) {
    491             mNetworkLockedRegistrants.remove(h);
    492         }
    493     }
    494 
    495     /**
    496      * Notifies handler of any transition into State.isPinLocked()
    497      */
    498     @Override
    499     public void registerForLocked(Handler h, int what, Object obj) {
    500         synchronized (mLock) {
    501             Registrant r = new Registrant (h, what, obj);
    502 
    503             mPinLockedRegistrants.add(r);
    504 
    505             if (getState().isPinLocked()) {
    506                 r.notifyRegistrant();
    507             }
    508         }
    509     }
    510 
    511     @Override
    512     public void unregisterForLocked(Handler h) {
    513         synchronized (mLock) {
    514             mPinLockedRegistrants.remove(h);
    515         }
    516     }
    517 
    518     @Override
    519     public void supplyPin(String pin, Message onComplete) {
    520         synchronized (mLock) {
    521             if (mUiccApplication != null) {
    522                 mUiccApplication.supplyPin(pin, onComplete);
    523             } else if (onComplete != null) {
    524                 Exception e = new RuntimeException("ICC card is absent.");
    525                 AsyncResult.forMessage(onComplete).exception = e;
    526                 onComplete.sendToTarget();
    527                 return;
    528             }
    529         }
    530     }
    531 
    532     @Override
    533     public void supplyPuk(String puk, String newPin, Message onComplete) {
    534         synchronized (mLock) {
    535             if (mUiccApplication != null) {
    536                 mUiccApplication.supplyPuk(puk, newPin, onComplete);
    537             } else if (onComplete != null) {
    538                 Exception e = new RuntimeException("ICC card is absent.");
    539                 AsyncResult.forMessage(onComplete).exception = e;
    540                 onComplete.sendToTarget();
    541                 return;
    542             }
    543         }
    544     }
    545 
    546     @Override
    547     public void supplyPin2(String pin2, Message onComplete) {
    548         synchronized (mLock) {
    549             if (mUiccApplication != null) {
    550                 mUiccApplication.supplyPin2(pin2, onComplete);
    551             } else if (onComplete != null) {
    552                 Exception e = new RuntimeException("ICC card is absent.");
    553                 AsyncResult.forMessage(onComplete).exception = e;
    554                 onComplete.sendToTarget();
    555                 return;
    556             }
    557         }
    558     }
    559 
    560     @Override
    561     public void supplyPuk2(String puk2, String newPin2, Message onComplete) {
    562         synchronized (mLock) {
    563             if (mUiccApplication != null) {
    564                 mUiccApplication.supplyPuk2(puk2, newPin2, onComplete);
    565             } else if (onComplete != null) {
    566                 Exception e = new RuntimeException("ICC card is absent.");
    567                 AsyncResult.forMessage(onComplete).exception = e;
    568                 onComplete.sendToTarget();
    569                 return;
    570             }
    571         }
    572     }
    573 
    574     @Override
    575     public void supplyNetworkDepersonalization(String pin, Message onComplete) {
    576         synchronized (mLock) {
    577             if (mUiccApplication != null) {
    578                 mUiccApplication.supplyNetworkDepersonalization(pin, onComplete);
    579             } else if (onComplete != null) {
    580                 Exception e = new RuntimeException("CommandsInterface is not set.");
    581                 AsyncResult.forMessage(onComplete).exception = e;
    582                 onComplete.sendToTarget();
    583                 return;
    584             }
    585         }
    586     }
    587 
    588     @Override
    589     public boolean getIccLockEnabled() {
    590         synchronized (mLock) {
    591             /* defaults to true, if ICC is absent */
    592             Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccLockEnabled() : true;
    593             return retValue;
    594         }
    595     }
    596 
    597     @Override
    598     public boolean getIccFdnEnabled() {
    599         synchronized (mLock) {
    600             Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnEnabled() : false;
    601             return retValue;
    602         }
    603     }
    604 
    605     @Override
    606     public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
    607         synchronized (mLock) {
    608             if (mUiccApplication != null) {
    609                 mUiccApplication.setIccLockEnabled(enabled, password, onComplete);
    610             } else if (onComplete != null) {
    611                 Exception e = new RuntimeException("ICC card is absent.");
    612                 AsyncResult.forMessage(onComplete).exception = e;
    613                 onComplete.sendToTarget();
    614                 return;
    615             }
    616         }
    617     }
    618 
    619     @Override
    620     public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) {
    621         synchronized (mLock) {
    622             if (mUiccApplication != null) {
    623                 mUiccApplication.setIccFdnEnabled(enabled, password, onComplete);
    624             } else if (onComplete != null) {
    625                 Exception e = new RuntimeException("ICC card is absent.");
    626                 AsyncResult.forMessage(onComplete).exception = e;
    627                 onComplete.sendToTarget();
    628                 return;
    629             }
    630         }
    631     }
    632 
    633     @Override
    634     public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {
    635         synchronized (mLock) {
    636             if (mUiccApplication != null) {
    637                 mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete);
    638             } else if (onComplete != null) {
    639                 Exception e = new RuntimeException("ICC card is absent.");
    640                 AsyncResult.forMessage(onComplete).exception = e;
    641                 onComplete.sendToTarget();
    642                 return;
    643             }
    644         }
    645     }
    646 
    647     @Override
    648     public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {
    649         synchronized (mLock) {
    650             if (mUiccApplication != null) {
    651                 mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete);
    652             } else if (onComplete != null) {
    653                 Exception e = new RuntimeException("ICC card is absent.");
    654                 AsyncResult.forMessage(onComplete).exception = e;
    655                 onComplete.sendToTarget();
    656                 return;
    657             }
    658         }
    659     }
    660 
    661     @Override
    662     public String getServiceProviderName() {
    663         synchronized (mLock) {
    664             if (mIccRecords != null) {
    665                 return mIccRecords.getServiceProviderName();
    666             }
    667             return null;
    668         }
    669     }
    670 
    671     @Override
    672     public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
    673         synchronized (mLock) {
    674             Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false;
    675             return retValue;
    676         }
    677     }
    678 
    679     @Override
    680     public boolean hasIccCard() {
    681         synchronized (mLock) {
    682             if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) {
    683                 return true;
    684             }
    685             return false;
    686         }
    687     }
    688 
    689     private void log(String s) {
    690         Log.d(LOG_TAG, s);
    691     }
    692 
    693     private void loge(String msg) {
    694         Log.e(LOG_TAG, msg);
    695     }
    696 }
    697