Home | History | Annotate | Download | only in uicc
      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.uicc;
     18 
     19 import static android.Manifest.permission.READ_PHONE_STATE;
     20 
     21 import android.app.ActivityManagerNative;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.os.AsyncResult;
     25 import android.os.Handler;
     26 import android.os.Message;
     27 import android.os.Registrant;
     28 import android.os.RegistrantList;
     29 import android.os.SystemProperties;
     30 import android.os.UserHandle;
     31 import android.telephony.Rlog;
     32 import android.telephony.ServiceState;
     33 import android.telephony.SubscriptionManager;
     34 import android.telephony.TelephonyManager;
     35 
     36 import com.android.internal.telephony.CommandsInterface;
     37 import com.android.internal.telephony.IccCard;
     38 import com.android.internal.telephony.IccCardConstants;
     39 import com.android.internal.telephony.PhoneConstants;
     40 import com.android.internal.telephony.MccTable;
     41 import com.android.internal.telephony.RILConstants;
     42 import com.android.internal.telephony.TelephonyIntents;
     43 import com.android.internal.telephony.IccCardConstants.State;
     44 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
     45 import com.android.internal.telephony.Phone;
     46 import com.android.internal.telephony.Subscription;
     47 import com.android.internal.telephony.SubscriptionController;
     48 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
     49 import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
     50 import com.android.internal.telephony.uicc.IccCardStatus.CardState;
     51 import com.android.internal.telephony.uicc.IccCardStatus.PinState;
     52 import com.android.internal.telephony.uicc.UiccController;
     53 
     54 import java.io.FileDescriptor;
     55 import java.io.PrintWriter;
     56 
     57 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
     58 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
     59 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
     60 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_STATE;
     61 
     62 
     63 /**
     64  * @Deprecated use {@link UiccController}.getUiccCard instead.
     65  *
     66  * The Phone App assumes that there is only one icc card, and one icc application
     67  * available at a time. Moreover, it assumes such object (represented with IccCard)
     68  * is available all the time (whether {@link RILConstants#RIL_REQUEST_GET_SIM_STATUS} returned
     69  * or not, whether card has desired application or not, whether there really is a card in the
     70  * slot or not).
     71  *
     72  * UiccController, however, can handle multiple instances of icc objects (multiple
     73  * {@link UiccCardApplication}, multiple {@link IccFileHandler}, multiple {@link IccRecords})
     74  * created and destroyed dynamically during phone operation.
     75  *
     76  * This class implements the IccCard interface that is always available (right after default
     77  * phone object is constructed) to expose the current (based on voice radio technology)
     78  * application on the uicc card, so that external apps won't break.
     79  */
     80 
     81 public class IccCardProxy extends Handler implements IccCard {
     82     private static final boolean DBG = true;
     83     private static final String LOG_TAG = "IccCardProxy";
     84 
     85     private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1;
     86     private static final int EVENT_RADIO_ON = 2;
     87     private static final int EVENT_ICC_CHANGED = 3;
     88     private static final int EVENT_ICC_ABSENT = 4;
     89     private static final int EVENT_ICC_LOCKED = 5;
     90     private static final int EVENT_APP_READY = 6;
     91     private static final int EVENT_RECORDS_LOADED = 7;
     92     private static final int EVENT_IMSI_READY = 8;
     93     private static final int EVENT_NETWORK_LOCKED = 9;
     94     private static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 11;
     95 
     96     private static final int EVENT_ICC_RECORD_EVENTS = 500;
     97     private static final int EVENT_SUBSCRIPTION_ACTIVATED = 501;
     98     private static final int EVENT_SUBSCRIPTION_DEACTIVATED = 502;
     99     private static final int EVENT_CARRIER_PRIVILIGES_LOADED = 503;
    100 
    101     // FIXME Rename mCardIndex to mSlotId.
    102     private Integer mCardIndex = null;
    103     private Subscription mSubscriptionData = null;
    104 
    105     private final Object mLock = new Object();
    106     private Context mContext;
    107     private CommandsInterface mCi;
    108 
    109     private RegistrantList mAbsentRegistrants = new RegistrantList();
    110     private RegistrantList mPinLockedRegistrants = new RegistrantList();
    111     private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
    112 
    113     private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp?
    114     private UiccController mUiccController = null;
    115     private UiccCard mUiccCard = null;
    116     private UiccCardApplication mUiccApplication = null;
    117     private IccRecords mIccRecords = null;
    118     private CdmaSubscriptionSourceManager mCdmaSSM = null;
    119     private boolean mRadioOn = false;
    120     private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast
    121                                         // ACTION_SIM_STATE_CHANGED intents
    122     private boolean mInitialized = false;
    123     private State mExternalState = State.UNKNOWN;
    124 
    125     public IccCardProxy(Context context, CommandsInterface ci) {
    126         log("Creating");
    127         mContext = context;
    128         mCi = ci;
    129         mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context,
    130                 ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
    131         mUiccController = UiccController.getInstance();
    132         mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
    133         ci.registerForOn(this,EVENT_RADIO_ON, null);
    134         ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
    135         setExternalState(State.NOT_READY);
    136     }
    137 
    138     public IccCardProxy(Context context, CommandsInterface ci, int cardIndex) {
    139         this(context, ci);
    140 
    141         mCardIndex = cardIndex;
    142 
    143         resetProperties();
    144         setExternalState(State.NOT_READY, false);
    145     }
    146 
    147     public void dispose() {
    148         synchronized (mLock) {
    149             log("Disposing");
    150             //Cleanup icc references
    151             mUiccController.unregisterForIccChanged(this);
    152             mUiccController = null;
    153             mCi.unregisterForOn(this);
    154             mCi.unregisterForOffOrNotAvailable(this);
    155             mCdmaSSM.dispose(this);
    156         }
    157     }
    158 
    159     /*
    160      * The card application that the external world sees will be based on the
    161      * voice radio technology only!
    162      */
    163     public void setVoiceRadioTech(int radioTech) {
    164         synchronized (mLock) {
    165             if (DBG) {
    166                 log("Setting radio tech " + ServiceState.rilRadioTechnologyToString(radioTech));
    167             }
    168             if (ServiceState.isGsm(radioTech)) {
    169                 mCurrentAppType = UiccController.APP_FAM_3GPP;
    170             } else {
    171                 mCurrentAppType = UiccController.APP_FAM_3GPP2;
    172             }
    173             updateQuietMode();
    174         }
    175     }
    176 
    177     /**
    178      * In case of 3gpp2 we need to find out if subscription used is coming from
    179      * NV in which case we shouldn't broadcast any sim states changes.
    180      */
    181     private void updateQuietMode() {
    182         synchronized (mLock) {
    183             boolean oldQuietMode = mQuietMode;
    184             boolean newQuietMode;
    185             int cdmaSource = Phone.CDMA_SUBSCRIPTION_UNKNOWN;
    186             boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic()
    187                     == PhoneConstants.LTE_ON_CDMA_TRUE;
    188             if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
    189                 newQuietMode = false;
    190                 if (DBG) log("updateQuietMode: 3GPP subscription -> newQuietMode=" + newQuietMode);
    191             } else {
    192                 if (isLteOnCdmaMode) {
    193                     log("updateQuietMode: is cdma/lte device, force IccCardProxy into 3gpp mode");
    194                     mCurrentAppType = UiccController.APP_FAM_3GPP;
    195                 }
    196                 cdmaSource = mCdmaSSM != null ?
    197                         mCdmaSSM.getCdmaSubscriptionSource() : Phone.CDMA_SUBSCRIPTION_UNKNOWN;
    198 
    199                 newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV)
    200                         && (mCurrentAppType == UiccController.APP_FAM_3GPP2)
    201                         && !isLteOnCdmaMode;
    202             }
    203 
    204             if (mQuietMode == false && newQuietMode == true) {
    205                 // Last thing to do before switching to quiet mode is
    206                 // broadcast ICC_READY
    207                 log("Switching to QuietMode.");
    208                 setExternalState(State.READY);
    209                 mQuietMode = newQuietMode;
    210             } else if (mQuietMode == true && newQuietMode == false) {
    211                 if (DBG) {
    212                     log("updateQuietMode: Switching out from QuietMode."
    213                             + " Force broadcast of current state=" + mExternalState);
    214                 }
    215                 mQuietMode = newQuietMode;
    216                 setExternalState(mExternalState, true);
    217             }
    218             if (DBG) {
    219                 log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type="
    220                     + mCurrentAppType + " isLteOnCdmaMode=" + isLteOnCdmaMode
    221                     + " cdmaSource=" + cdmaSource + ")");
    222             }
    223             mInitialized = true;
    224             sendMessage(obtainMessage(EVENT_ICC_CHANGED));
    225         }
    226     }
    227 
    228     @Override
    229     public void handleMessage(Message msg) {
    230         switch (msg.what) {
    231             case EVENT_RADIO_OFF_OR_UNAVAILABLE:
    232                 mRadioOn = false;
    233                 if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) {
    234                     setExternalState(State.NOT_READY);
    235                 }
    236                 break;
    237             case EVENT_RADIO_ON:
    238                 mRadioOn = true;
    239                 if (!mInitialized) {
    240                     updateQuietMode();
    241                 }
    242                 break;
    243             case EVENT_ICC_CHANGED:
    244                 if (mInitialized) {
    245                     updateIccAvailability();
    246                 }
    247                 break;
    248             case EVENT_ICC_ABSENT:
    249                 mAbsentRegistrants.notifyRegistrants();
    250                 setExternalState(State.ABSENT);
    251                 break;
    252             case EVENT_ICC_LOCKED:
    253                 processLockedState();
    254                 break;
    255             case EVENT_APP_READY:
    256                 setExternalState(State.READY);
    257                 break;
    258             case EVENT_RECORDS_LOADED:
    259                 if (mIccRecords != null) {
    260                     String operator = mIccRecords.getOperatorNumeric();
    261                     int slotId = mCardIndex;
    262 
    263                     log("operator = " + operator + " slotId = " + slotId);
    264 
    265                     if (operator != null) {
    266                         log("update icc_operator_numeric=" + operator);
    267                         setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, slotId, operator);
    268                         String countryCode = operator.substring(0,3);
    269                         if (countryCode != null) {
    270                             setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, slotId,
    271                                     MccTable.countryCodeForMcc(Integer.parseInt(countryCode)));
    272                         } else {
    273                             loge("EVENT_RECORDS_LOADED Country code is null");
    274                         }
    275 
    276                         long[] subId = SubscriptionController.getInstance().getSubId(slotId);
    277                         // Update MCC MNC device configuration information only for default sub.
    278                         if (subId[0] == SubscriptionController.getInstance().getDefaultSubId()) {
    279                             log("update mccmnc=" + operator + " config for default subscription.");
    280                             MccTable.updateMccMncConfiguration(mContext, operator, false);
    281                         }
    282                         SubscriptionController.getInstance().setMccMnc(operator, subId[0]);
    283                     } else {
    284                         loge("EVENT_RECORDS_LOADED Operator name is null");
    285                     }
    286                 }
    287                 if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) {
    288                     mUiccCard.registerForCarrierPrivilegeRulesLoaded(
    289                         this, EVENT_CARRIER_PRIVILIGES_LOADED, null);
    290                 } else {
    291                     onRecordsLoaded();
    292                 }
    293                 break;
    294             case EVENT_IMSI_READY:
    295                 broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, null);
    296                 break;
    297             case EVENT_NETWORK_LOCKED:
    298                 mNetworkLockedRegistrants.notifyRegistrants();
    299                 setExternalState(State.NETWORK_LOCKED);
    300                 break;
    301             case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
    302                 updateQuietMode();
    303                 break;
    304             case EVENT_SUBSCRIPTION_ACTIVATED:
    305                 log("EVENT_SUBSCRIPTION_ACTIVATED");
    306                 onSubscriptionActivated();
    307                 break;
    308 
    309             case EVENT_SUBSCRIPTION_DEACTIVATED:
    310                 log("EVENT_SUBSCRIPTION_DEACTIVATED");
    311                 onSubscriptionDeactivated();
    312                 break;
    313 
    314             case EVENT_ICC_RECORD_EVENTS:
    315                 if ((mCurrentAppType == UiccController.APP_FAM_3GPP) && (mIccRecords != null)) {
    316                     int slotId = mCardIndex;
    317                     AsyncResult ar = (AsyncResult)msg.obj;
    318                     int eventCode = (Integer) ar.result;
    319                     if (eventCode == SIMRecords.EVENT_SPN) {
    320                         setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, slotId,
    321                                 mIccRecords.getServiceProviderName());
    322                     }
    323                 }
    324                 break;
    325 
    326             case EVENT_CARRIER_PRIVILIGES_LOADED:
    327                 log("EVENT_CARRIER_PRIVILEGES_LOADED");
    328                 if (mUiccCard != null) {
    329                     mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
    330                 }
    331                 onRecordsLoaded();
    332                 break;
    333 
    334             default:
    335                 loge("Unhandled message with number: " + msg.what);
    336                 break;
    337         }
    338     }
    339 
    340     private void onSubscriptionActivated() {
    341         //mSubscriptionData = SubscriptionManager.getCurrentSubscription(mCardIndex);
    342 
    343         updateIccAvailability();
    344         updateStateProperty();
    345     }
    346 
    347     private void onSubscriptionDeactivated() {
    348         resetProperties();
    349         mSubscriptionData = null;
    350         updateIccAvailability();
    351         updateStateProperty();
    352     }
    353 
    354     private void onRecordsLoaded() {
    355         broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
    356     }
    357 
    358     private void updateIccAvailability() {
    359         synchronized (mLock) {
    360             UiccCard newCard = mUiccController.getUiccCard(mCardIndex);
    361             CardState state = CardState.CARDSTATE_ABSENT;
    362             UiccCardApplication newApp = null;
    363             IccRecords newRecords = null;
    364             if (newCard != null) {
    365                 state = newCard.getCardState();
    366                 newApp = newCard.getApplication(mCurrentAppType);
    367                 if (newApp != null) {
    368                     newRecords = newApp.getIccRecords();
    369                 }
    370             }
    371 
    372             if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
    373                 if (DBG) log("Icc changed. Reregestering.");
    374                 unregisterUiccCardEvents();
    375                 mUiccCard = newCard;
    376                 mUiccApplication = newApp;
    377                 mIccRecords = newRecords;
    378                 registerUiccCardEvents();
    379             }
    380 
    381             updateExternalState();
    382         }
    383     }
    384 
    385     void resetProperties() {
    386         if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
    387             log("update icc_operator_numeric=" + "");
    388             setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, mCardIndex, "");
    389             setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, mCardIndex, "");
    390             setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, mCardIndex, "");
    391          }
    392     }
    393 
    394     private void HandleDetectedState() {
    395     // CAF_MSIM SAND
    396 //        setExternalState(State.DETECTED, false);
    397     }
    398 
    399     private void updateExternalState() {
    400         if (mUiccCard == null || mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
    401             if (mRadioOn) {
    402                 setExternalState(State.ABSENT);
    403             } else {
    404                 setExternalState(State.NOT_READY);
    405             }
    406             return;
    407         }
    408 
    409         if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) {
    410             setExternalState(State.CARD_IO_ERROR);
    411             return;
    412         }
    413 
    414         if (mUiccApplication == null) {
    415             setExternalState(State.NOT_READY);
    416             return;
    417         }
    418 
    419         switch (mUiccApplication.getState()) {
    420             case APPSTATE_UNKNOWN:
    421                 setExternalState(State.UNKNOWN);
    422                 break;
    423             case APPSTATE_DETECTED:
    424                 HandleDetectedState();
    425                 break;
    426             case APPSTATE_PIN:
    427                 setExternalState(State.PIN_REQUIRED);
    428                 break;
    429             case APPSTATE_PUK:
    430                 setExternalState(State.PUK_REQUIRED);
    431                 break;
    432             case APPSTATE_SUBSCRIPTION_PERSO:
    433                 if (mUiccApplication.getPersoSubState() ==
    434                         PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
    435                     setExternalState(State.NETWORK_LOCKED);
    436                 } else {
    437                     setExternalState(State.UNKNOWN);
    438                 }
    439                 break;
    440             case APPSTATE_READY:
    441                 setExternalState(State.READY);
    442                 break;
    443         }
    444     }
    445 
    446     private void registerUiccCardEvents() {
    447         if (mUiccCard != null) {
    448             mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null);
    449         }
    450         if (mUiccApplication != null) {
    451             mUiccApplication.registerForReady(this, EVENT_APP_READY, null);
    452             mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null);
    453             mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null);
    454         }
    455         if (mIccRecords != null) {
    456             mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null);
    457             mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
    458             mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
    459         }
    460     }
    461 
    462     private void unregisterUiccCardEvents() {
    463         if (mUiccCard != null) mUiccCard.unregisterForAbsent(this);
    464         if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
    465         if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
    466         if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
    467         if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this);
    468         if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this);
    469         if (mIccRecords != null) mIccRecords.unregisterForRecordsEvents(this);
    470     }
    471 
    472     private void updateStateProperty() {
    473         setSystemProperty(PROPERTY_SIM_STATE, mCardIndex,getState().toString());
    474     }
    475 
    476     private void broadcastIccStateChangedIntent(String value, String reason) {
    477         synchronized (mLock) {
    478             if (mCardIndex == null) {
    479                 loge("broadcastIccStateChangedIntent: Card Index is not set; Return!!");
    480                 return;
    481             }
    482 
    483             if (mQuietMode) {
    484                 log("QuietMode: NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
    485                         + " reason " + reason);
    486                 return;
    487             }
    488 
    489             Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
    490             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    491             intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
    492             intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
    493             intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
    494             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mCardIndex);
    495             log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
    496                 + " reason " + reason + " for mCardIndex : " + mCardIndex);
    497             ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
    498                     UserHandle.USER_ALL);
    499         }
    500     }
    501 
    502     private void setExternalState(State newState, boolean override) {
    503         synchronized (mLock) {
    504             if (mCardIndex == null) {
    505                 loge("setExternalState: Card Index is not set; Return!!");
    506                 return;
    507             }
    508 
    509             if (!override && newState == mExternalState) {
    510                 return;
    511             }
    512             mExternalState = newState;
    513             setSystemProperty(PROPERTY_SIM_STATE, mCardIndex, getState().toString());
    514             broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
    515                     getIccStateReason(mExternalState));
    516             // TODO: Need to notify registrants for other states as well.
    517             if ( State.ABSENT == mExternalState) {
    518                 mAbsentRegistrants.notifyRegistrants();
    519             }
    520         }
    521     }
    522 
    523     private void processLockedState() {
    524         synchronized (mLock) {
    525             if (mUiccApplication == null) {
    526                 //Don't need to do anything if non-existent application is locked
    527                 return;
    528             }
    529             PinState pin1State = mUiccApplication.getPin1State();
    530             if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
    531                 setExternalState(State.PERM_DISABLED);
    532                 return;
    533             }
    534 
    535             AppState appState = mUiccApplication.getState();
    536             switch (appState) {
    537                 case APPSTATE_PIN:
    538                     mPinLockedRegistrants.notifyRegistrants();
    539                     setExternalState(State.PIN_REQUIRED);
    540                     break;
    541                 case APPSTATE_PUK:
    542                     setExternalState(State.PUK_REQUIRED);
    543                     break;
    544                 case APPSTATE_DETECTED:
    545                 case APPSTATE_READY:
    546                 case APPSTATE_SUBSCRIPTION_PERSO:
    547                 case APPSTATE_UNKNOWN:
    548                     // Neither required
    549                     break;
    550             }
    551         }
    552     }
    553 
    554     private void setExternalState(State newState) {
    555         setExternalState(newState, false);
    556     }
    557 
    558     public boolean getIccRecordsLoaded() {
    559         synchronized (mLock) {
    560             if (mIccRecords != null) {
    561                 return mIccRecords.getRecordsLoaded();
    562             }
    563             return false;
    564         }
    565     }
    566 
    567     private String getIccStateIntentString(State state) {
    568         switch (state) {
    569             case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
    570             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
    571             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
    572             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
    573             case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
    574             case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
    575             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
    576             case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
    577             default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
    578         }
    579     }
    580 
    581     /**
    582      * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED, CARD_IO_ERROR)
    583      * @return reason
    584      */
    585     private String getIccStateReason(State state) {
    586         switch (state) {
    587             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN;
    588             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK;
    589             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK;
    590             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED;
    591             case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
    592             default: return null;
    593        }
    594     }
    595 
    596     /* IccCard interface implementation */
    597     @Override
    598     public State getState() {
    599         synchronized (mLock) {
    600             return mExternalState;
    601         }
    602     }
    603 
    604     @Override
    605     public IccRecords getIccRecords() {
    606         synchronized (mLock) {
    607             return mIccRecords;
    608         }
    609     }
    610 
    611     @Override
    612     public IccFileHandler getIccFileHandler() {
    613         synchronized (mLock) {
    614             if (mUiccApplication != null) {
    615                 return mUiccApplication.getIccFileHandler();
    616             }
    617             return null;
    618         }
    619     }
    620 
    621     /**
    622      * Notifies handler of any transition into State.ABSENT
    623      */
    624     @Override
    625     public void registerForAbsent(Handler h, int what, Object obj) {
    626         synchronized (mLock) {
    627             Registrant r = new Registrant (h, what, obj);
    628 
    629             mAbsentRegistrants.add(r);
    630 
    631             if (getState() == State.ABSENT) {
    632                 r.notifyRegistrant();
    633             }
    634         }
    635     }
    636 
    637     @Override
    638     public void unregisterForAbsent(Handler h) {
    639         synchronized (mLock) {
    640             mAbsentRegistrants.remove(h);
    641         }
    642     }
    643 
    644     /**
    645      * Notifies handler of any transition into State.NETWORK_LOCKED
    646      */
    647     @Override
    648     public void registerForNetworkLocked(Handler h, int what, Object obj) {
    649         synchronized (mLock) {
    650             Registrant r = new Registrant (h, what, obj);
    651 
    652             mNetworkLockedRegistrants.add(r);
    653 
    654             if (getState() == State.NETWORK_LOCKED) {
    655                 r.notifyRegistrant();
    656             }
    657         }
    658     }
    659 
    660     @Override
    661     public void unregisterForNetworkLocked(Handler h) {
    662         synchronized (mLock) {
    663             mNetworkLockedRegistrants.remove(h);
    664         }
    665     }
    666 
    667     /**
    668      * Notifies handler of any transition into State.isPinLocked()
    669      */
    670     @Override
    671     public void registerForLocked(Handler h, int what, Object obj) {
    672         synchronized (mLock) {
    673             Registrant r = new Registrant (h, what, obj);
    674 
    675             mPinLockedRegistrants.add(r);
    676 
    677             if (getState().isPinLocked()) {
    678                 r.notifyRegistrant();
    679             }
    680         }
    681     }
    682 
    683     @Override
    684     public void unregisterForLocked(Handler h) {
    685         synchronized (mLock) {
    686             mPinLockedRegistrants.remove(h);
    687         }
    688     }
    689 
    690     @Override
    691     public void supplyPin(String pin, Message onComplete) {
    692         synchronized (mLock) {
    693             if (mUiccApplication != null) {
    694                 mUiccApplication.supplyPin(pin, onComplete);
    695             } else if (onComplete != null) {
    696                 Exception e = new RuntimeException("ICC card is absent.");
    697                 AsyncResult.forMessage(onComplete).exception = e;
    698                 onComplete.sendToTarget();
    699                 return;
    700             }
    701         }
    702     }
    703 
    704     @Override
    705     public void supplyPuk(String puk, String newPin, Message onComplete) {
    706         synchronized (mLock) {
    707             if (mUiccApplication != null) {
    708                 mUiccApplication.supplyPuk(puk, newPin, onComplete);
    709             } else if (onComplete != null) {
    710                 Exception e = new RuntimeException("ICC card is absent.");
    711                 AsyncResult.forMessage(onComplete).exception = e;
    712                 onComplete.sendToTarget();
    713                 return;
    714             }
    715         }
    716     }
    717 
    718     @Override
    719     public void supplyPin2(String pin2, Message onComplete) {
    720         synchronized (mLock) {
    721             if (mUiccApplication != null) {
    722                 mUiccApplication.supplyPin2(pin2, onComplete);
    723             } else if (onComplete != null) {
    724                 Exception e = new RuntimeException("ICC card is absent.");
    725                 AsyncResult.forMessage(onComplete).exception = e;
    726                 onComplete.sendToTarget();
    727                 return;
    728             }
    729         }
    730     }
    731 
    732     @Override
    733     public void supplyPuk2(String puk2, String newPin2, Message onComplete) {
    734         synchronized (mLock) {
    735             if (mUiccApplication != null) {
    736                 mUiccApplication.supplyPuk2(puk2, newPin2, onComplete);
    737             } else if (onComplete != null) {
    738                 Exception e = new RuntimeException("ICC card is absent.");
    739                 AsyncResult.forMessage(onComplete).exception = e;
    740                 onComplete.sendToTarget();
    741                 return;
    742             }
    743         }
    744     }
    745 
    746     @Override
    747     public void supplyNetworkDepersonalization(String pin, Message onComplete) {
    748         synchronized (mLock) {
    749             if (mUiccApplication != null) {
    750                 mUiccApplication.supplyNetworkDepersonalization(pin, onComplete);
    751             } else if (onComplete != null) {
    752                 Exception e = new RuntimeException("CommandsInterface is not set.");
    753                 AsyncResult.forMessage(onComplete).exception = e;
    754                 onComplete.sendToTarget();
    755                 return;
    756             }
    757         }
    758     }
    759 
    760     @Override
    761     public boolean getIccLockEnabled() {
    762         synchronized (mLock) {
    763             /* defaults to false, if ICC is absent/deactivated */
    764             Boolean retValue = mUiccApplication != null ?
    765                     mUiccApplication.getIccLockEnabled() : false;
    766             return retValue;
    767         }
    768     }
    769 
    770     @Override
    771     public boolean getIccFdnEnabled() {
    772         synchronized (mLock) {
    773             Boolean retValue = mUiccApplication != null ?
    774                     mUiccApplication.getIccFdnEnabled() : false;
    775             return retValue;
    776         }
    777     }
    778 
    779     public boolean getIccFdnAvailable() {
    780         boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnAvailable() : false;
    781         return retValue;
    782     }
    783 
    784     public boolean getIccPin2Blocked() {
    785         /* defaults to disabled */
    786         Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPin2Blocked() : false;
    787         return retValue;
    788     }
    789 
    790     public boolean getIccPuk2Blocked() {
    791         /* defaults to disabled */
    792         Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPuk2Blocked() : false;
    793         return retValue;
    794     }
    795 
    796     @Override
    797     public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
    798         synchronized (mLock) {
    799             if (mUiccApplication != null) {
    800                 mUiccApplication.setIccLockEnabled(enabled, password, onComplete);
    801             } else if (onComplete != null) {
    802                 Exception e = new RuntimeException("ICC card is absent.");
    803                 AsyncResult.forMessage(onComplete).exception = e;
    804                 onComplete.sendToTarget();
    805                 return;
    806             }
    807         }
    808     }
    809 
    810     @Override
    811     public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) {
    812         synchronized (mLock) {
    813             if (mUiccApplication != null) {
    814                 mUiccApplication.setIccFdnEnabled(enabled, password, onComplete);
    815             } else if (onComplete != null) {
    816                 Exception e = new RuntimeException("ICC card is absent.");
    817                 AsyncResult.forMessage(onComplete).exception = e;
    818                 onComplete.sendToTarget();
    819                 return;
    820             }
    821         }
    822     }
    823 
    824     @Override
    825     public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {
    826         synchronized (mLock) {
    827             if (mUiccApplication != null) {
    828                 mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete);
    829             } else if (onComplete != null) {
    830                 Exception e = new RuntimeException("ICC card is absent.");
    831                 AsyncResult.forMessage(onComplete).exception = e;
    832                 onComplete.sendToTarget();
    833                 return;
    834             }
    835         }
    836     }
    837 
    838     @Override
    839     public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {
    840         synchronized (mLock) {
    841             if (mUiccApplication != null) {
    842                 mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete);
    843             } else if (onComplete != null) {
    844                 Exception e = new RuntimeException("ICC card is absent.");
    845                 AsyncResult.forMessage(onComplete).exception = e;
    846                 onComplete.sendToTarget();
    847                 return;
    848             }
    849         }
    850     }
    851 
    852     @Override
    853     public String getServiceProviderName() {
    854         synchronized (mLock) {
    855             if (mIccRecords != null) {
    856                 return mIccRecords.getServiceProviderName();
    857             }
    858             return null;
    859         }
    860     }
    861 
    862     @Override
    863     public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) {
    864         synchronized (mLock) {
    865             Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false;
    866             return retValue;
    867         }
    868     }
    869 
    870     @Override
    871     public boolean hasIccCard() {
    872         synchronized (mLock) {
    873             if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) {
    874                 return true;
    875             }
    876             return false;
    877         }
    878     }
    879 
    880     private void setSystemProperty(String property, int slotId, String value) {
    881         long[] subId = SubscriptionController.getInstance().getSubId(slotId);
    882         TelephonyManager.setTelephonyProperty(property, subId[0], value);
    883     }
    884 
    885     private void log(String s) {
    886         Rlog.d(LOG_TAG, s);
    887     }
    888 
    889     private void loge(String msg) {
    890         Rlog.e(LOG_TAG, msg);
    891     }
    892 
    893     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    894         pw.println("IccCardProxy: " + this);
    895         pw.println(" mContext=" + mContext);
    896         pw.println(" mCi=" + mCi);
    897         pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size());
    898         for (int i = 0; i < mAbsentRegistrants.size(); i++) {
    899             pw.println("  mAbsentRegistrants[" + i + "]="
    900                     + ((Registrant)mAbsentRegistrants.get(i)).getHandler());
    901         }
    902         pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size());
    903         for (int i = 0; i < mPinLockedRegistrants.size(); i++) {
    904             pw.println("  mPinLockedRegistrants[" + i + "]="
    905                     + ((Registrant)mPinLockedRegistrants.get(i)).getHandler());
    906         }
    907         pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
    908         for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
    909             pw.println("  mNetworkLockedRegistrants[" + i + "]="
    910                     + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
    911         }
    912         pw.println(" mCurrentAppType=" + mCurrentAppType);
    913         pw.println(" mUiccController=" + mUiccController);
    914         pw.println(" mUiccCard=" + mUiccCard);
    915         pw.println(" mUiccApplication=" + mUiccApplication);
    916         pw.println(" mIccRecords=" + mIccRecords);
    917         pw.println(" mCdmaSSM=" + mCdmaSSM);
    918         pw.println(" mRadioOn=" + mRadioOn);
    919         pw.println(" mQuietMode=" + mQuietMode);
    920         pw.println(" mInitialized=" + mInitialized);
    921         pw.println(" mExternalState=" + mExternalState);
    922 
    923         pw.flush();
    924     }
    925 }
    926