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