/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.uicc; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.os.UserHandle; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.CommandsInterface.RadioState; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.IntentBroadcaster; import com.android.internal.telephony.MccTable; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccCardStatus.PinState; import java.io.FileDescriptor; import java.io.PrintWriter; /** * @Deprecated use {@link UiccController}.getUiccCard instead. * * The Phone App assumes that there is only one icc card, and one icc application * available at a time. Moreover, it assumes such object (represented with IccCard) * is available all the time (whether {@link RILConstants#RIL_REQUEST_GET_SIM_STATUS} returned * or not, whether card has desired application or not, whether there really is a card in the * slot or not). * * UiccController, however, can handle multiple instances of icc objects (multiple * {@link UiccCardApplication}, multiple {@link IccFileHandler}, multiple {@link IccRecords}) * created and destroyed dynamically during phone operation. * * This class implements the IccCard interface that is always available (right after default * phone object is constructed) to expose the current (based on voice radio technology) * application on the uicc card, so that external apps won't break. */ public class IccCardProxy extends Handler implements IccCard { private static final boolean DBG = true; private static final String LOG_TAG = "IccCardProxy"; private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1; private static final int EVENT_RADIO_ON = 2; private static final int EVENT_ICC_CHANGED = 3; private static final int EVENT_ICC_ABSENT = 4; private static final int EVENT_ICC_LOCKED = 5; private static final int EVENT_APP_READY = 6; private static final int EVENT_RECORDS_LOADED = 7; private static final int EVENT_IMSI_READY = 8; private static final int EVENT_NETWORK_LOCKED = 9; private static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 11; private static final int EVENT_ICC_RECORD_EVENTS = 500; private static final int EVENT_SUBSCRIPTION_ACTIVATED = 501; private static final int EVENT_SUBSCRIPTION_DEACTIVATED = 502; private static final int EVENT_CARRIER_PRIVILEGES_LOADED = 503; private Integer mPhoneId = null; private final Object mLock = new Object(); private Context mContext; private CommandsInterface mCi; private TelephonyManager mTelephonyManager; private RegistrantList mAbsentRegistrants = new RegistrantList(); private RegistrantList mPinLockedRegistrants = new RegistrantList(); private RegistrantList mNetworkLockedRegistrants = new RegistrantList(); private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp? private UiccController mUiccController = null; private UiccCard mUiccCard = null; private UiccCardApplication mUiccApplication = null; private IccRecords mIccRecords = null; private CdmaSubscriptionSourceManager mCdmaSSM = null; private RadioState mRadioState = RadioState.RADIO_UNAVAILABLE; private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast // ACTION_SIM_STATE_CHANGED intents private boolean mInitialized = false; private State mExternalState = State.UNKNOWN; public static final String ACTION_INTERNAL_SIM_STATE_CHANGED = "android.intent.action.internal_sim_state_changed"; public IccCardProxy(Context context, CommandsInterface ci, int phoneId) { if (DBG) log("ctor: ci=" + ci + " phoneId=" + phoneId); mContext = context; mCi = ci; mPhoneId = phoneId; mTelephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context, ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); mUiccController = UiccController.getInstance(); mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); ci.registerForOn(this,EVENT_RADIO_ON, null); ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); resetProperties(); } public void dispose() { synchronized (mLock) { log("Disposing"); //Cleanup icc references mUiccController.unregisterForIccChanged(this); mUiccController = null; mCi.unregisterForOn(this); mCi.unregisterForOffOrNotAvailable(this); mCdmaSSM.dispose(this); } } /* * The card application that the external world sees will be based on the * voice radio technology only! */ public void setVoiceRadioTech(int radioTech) { synchronized (mLock) { if (DBG) { log("Setting radio tech " + ServiceState.rilRadioTechnologyToString(radioTech)); } if (ServiceState.isGsm(radioTech)) { mCurrentAppType = UiccController.APP_FAM_3GPP; } else { mCurrentAppType = UiccController.APP_FAM_3GPP2; } updateQuietMode(); } } /** * In case of 3gpp2 we need to find out if subscription used is coming from * NV in which case we shouldn't broadcast any sim states changes. */ private void updateQuietMode() { synchronized (mLock) { boolean oldQuietMode = mQuietMode; boolean newQuietMode; int cdmaSource = Phone.CDMA_SUBSCRIPTION_UNKNOWN; boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE; if (mCurrentAppType == UiccController.APP_FAM_3GPP) { newQuietMode = false; if (DBG) log("updateQuietMode: 3GPP subscription -> newQuietMode=" + newQuietMode); } else { if (isLteOnCdmaMode) { log("updateQuietMode: is cdma/lte device, force IccCardProxy into 3gpp mode"); mCurrentAppType = UiccController.APP_FAM_3GPP; } cdmaSource = mCdmaSSM != null ? mCdmaSSM.getCdmaSubscriptionSource() : Phone.CDMA_SUBSCRIPTION_UNKNOWN; newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV) && (mCurrentAppType == UiccController.APP_FAM_3GPP2) && !isLteOnCdmaMode; if (DBG) { log("updateQuietMode: cdmaSource=" + cdmaSource + " mCurrentAppType=" + mCurrentAppType + " isLteOnCdmaMode=" + isLteOnCdmaMode + " newQuietMode=" + newQuietMode); } } if (mQuietMode == false && newQuietMode == true) { // Last thing to do before switching to quiet mode is // broadcast ICC_READY log("Switching to QuietMode."); setExternalState(State.READY); mQuietMode = newQuietMode; } else if (mQuietMode == true && newQuietMode == false) { if (DBG) { log("updateQuietMode: Switching out from QuietMode." + " Force broadcast of current state=" + mExternalState); } mQuietMode = newQuietMode; setExternalState(mExternalState, true); } else { if (DBG) log("updateQuietMode: no changes don't setExternalState"); } if (DBG) { log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type=" + mCurrentAppType + " isLteOnCdmaMode=" + isLteOnCdmaMode + " cdmaSource=" + cdmaSource + ")"); } mInitialized = true; sendMessage(obtainMessage(EVENT_ICC_CHANGED)); } } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_RADIO_OFF_OR_UNAVAILABLE: mRadioState = mCi.getRadioState(); updateExternalState(); break; case EVENT_RADIO_ON: mRadioState = RadioState.RADIO_ON; if (!mInitialized) { updateQuietMode(); } else { // updateQuietMode() triggers ICC_CHANGED, which eventually // calls updateExternalState; thus, we don't need this in the // above case updateExternalState(); } break; case EVENT_ICC_CHANGED: if (mInitialized) { updateIccAvailability(); } break; case EVENT_ICC_ABSENT: mAbsentRegistrants.notifyRegistrants(); setExternalState(State.ABSENT); break; case EVENT_ICC_LOCKED: processLockedState(); break; case EVENT_APP_READY: setExternalState(State.READY); break; case EVENT_RECORDS_LOADED: // Update the MCC/MNC. if (mIccRecords != null) { String operator = mIccRecords.getOperatorNumeric(); log("operator=" + operator + " mPhoneId=" + mPhoneId); if (!TextUtils.isEmpty(operator)) { mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, operator); String countryCode = operator.substring(0,3); if (countryCode != null) { mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, MccTable.countryCodeForMcc(Integer.parseInt(countryCode))); } else { loge("EVENT_RECORDS_LOADED Country code is null"); } } else { loge("EVENT_RECORDS_LOADED Operator name is null"); } } if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) { mUiccCard.registerForCarrierPrivilegeRulesLoaded( this, EVENT_CARRIER_PRIVILEGES_LOADED, null); } else { onRecordsLoaded(); } break; case EVENT_IMSI_READY: broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, null); break; case EVENT_NETWORK_LOCKED: mNetworkLockedRegistrants.notifyRegistrants(); setExternalState(State.NETWORK_LOCKED); break; case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED: updateQuietMode(); break; case EVENT_SUBSCRIPTION_ACTIVATED: log("EVENT_SUBSCRIPTION_ACTIVATED"); onSubscriptionActivated(); break; case EVENT_SUBSCRIPTION_DEACTIVATED: log("EVENT_SUBSCRIPTION_DEACTIVATED"); onSubscriptionDeactivated(); break; case EVENT_ICC_RECORD_EVENTS: if ((mCurrentAppType == UiccController.APP_FAM_3GPP) && (mIccRecords != null)) { AsyncResult ar = (AsyncResult)msg.obj; int eventCode = (Integer) ar.result; if (eventCode == SIMRecords.EVENT_SPN) { mTelephonyManager.setSimOperatorNameForPhone( mPhoneId, mIccRecords.getServiceProviderName()); } } break; case EVENT_CARRIER_PRIVILEGES_LOADED: log("EVENT_CARRIER_PRIVILEGES_LOADED"); if (mUiccCard != null) { mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this); } onRecordsLoaded(); break; default: loge("Unhandled message with number: " + msg.what); break; } } private void onSubscriptionActivated() { updateIccAvailability(); updateStateProperty(); } private void onSubscriptionDeactivated() { resetProperties(); updateIccAvailability(); updateStateProperty(); } private void onRecordsLoaded() { broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null); } private void updateIccAvailability() { synchronized (mLock) { UiccCard newCard = mUiccController.getUiccCard(mPhoneId); UiccCardApplication newApp = null; IccRecords newRecords = null; if (newCard != null) { newApp = newCard.getApplication(mCurrentAppType); if (newApp != null) { newRecords = newApp.getIccRecords(); } } if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) { if (DBG) log("Icc changed. Reregistering."); unregisterUiccCardEvents(); mUiccCard = newCard; mUiccApplication = newApp; mIccRecords = newRecords; registerUiccCardEvents(); } updateExternalState(); } } void resetProperties() { if (mCurrentAppType == UiccController.APP_FAM_3GPP) { log("update icc_operator_numeric=" + ""); mTelephonyManager.setSimOperatorNumericForPhone(mPhoneId, ""); mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, ""); mTelephonyManager.setSimOperatorNameForPhone(mPhoneId, ""); } } private void HandleDetectedState() { // CAF_MSIM SAND // setExternalState(State.DETECTED, false); } private void updateExternalState() { // mUiccCard could be null at bootup, before valid card states have // been received from UiccController. if (mUiccCard == null) { setExternalState(State.UNKNOWN); return; } if (mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) { /* * Both IccCardProxy and UiccController are registered for * RadioState changes. When the UiccController receives a radio * state changed to Unknown it will dispose of all of the IccCard * objects, which will then notify the IccCardProxy and the null * object will force the state to unknown. However, because the * IccCardProxy is also registered for RadioState changes, it will * recieve that signal first. By triggering on radio state changes * directly, we reduce the time window during which the modem is * UNAVAILABLE but the IccStatus is reported as something valid. * This is not ideal. */ if (mRadioState == RadioState.RADIO_UNAVAILABLE) { setExternalState(State.UNKNOWN); } else { setExternalState(State.ABSENT); } return; } if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) { setExternalState(State.CARD_IO_ERROR); return; } if (mUiccCard.getCardState() == CardState.CARDSTATE_RESTRICTED) { setExternalState(State.CARD_RESTRICTED); return; } if (mUiccApplication == null) { setExternalState(State.NOT_READY); return; } // By process of elimination, the UICC Card State = PRESENT switch (mUiccApplication.getState()) { case APPSTATE_UNKNOWN: /* * APPSTATE_UNKNOWN is a catch-all state reported whenever the app * is not explicitly in one of the other states. To differentiate the * case where we know that there is a card present, but the APP is not * ready, we choose NOT_READY here instead of unknown. This is possible * in at least two cases: * 1) A transient during the process of the SIM bringup * 2) There is no valid App on the SIM to load, which can be the case with an * eSIM/soft SIM. */ setExternalState(State.NOT_READY); break; case APPSTATE_DETECTED: HandleDetectedState(); break; case APPSTATE_PIN: setExternalState(State.PIN_REQUIRED); break; case APPSTATE_PUK: PinState pin1State = mUiccApplication.getPin1State(); if (pin1State.isPermBlocked()) { setExternalState(State.PERM_DISABLED); return; } setExternalState(State.PUK_REQUIRED); break; case APPSTATE_SUBSCRIPTION_PERSO: if (mUiccApplication.getPersoSubState() == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) { setExternalState(State.NETWORK_LOCKED); } // Otherwise don't change external SIM state. break; case APPSTATE_READY: setExternalState(State.READY); break; } } private void registerUiccCardEvents() { if (mUiccCard != null) { mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null); } if (mUiccApplication != null) { mUiccApplication.registerForReady(this, EVENT_APP_READY, null); mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null); mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null); } if (mIccRecords != null) { mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null); mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); } } private void unregisterUiccCardEvents() { if (mUiccCard != null) mUiccCard.unregisterForAbsent(this); if (mUiccCard != null) mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this); if (mUiccApplication != null) mUiccApplication.unregisterForReady(this); if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this); if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this); if (mIccRecords != null) mIccRecords.unregisterForImsiReady(this); if (mIccRecords != null) mIccRecords.unregisterForRecordsLoaded(this); if (mIccRecords != null) mIccRecords.unregisterForRecordsEvents(this); } private void updateStateProperty() { mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString()); } private void broadcastIccStateChangedIntent(String value, String reason) { synchronized (mLock) { if (mPhoneId == null || !SubscriptionManager.isValidSlotIndex(mPhoneId)) { loge("broadcastIccStateChangedIntent: mPhoneId=" + mPhoneId + " is invalid; Return!!"); return; } if (mQuietMode) { log("broadcastIccStateChangedIntent: QuietMode" + " NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " + " value=" + value + " reason=" + reason); return; } Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); // TODO - we'd like this intent to have a single snapshot of all sim state, // but until then this should not use REPLACE_PENDING or we may lose // information // intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value); intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId); log("broadcastIccStateChangedIntent intent ACTION_SIM_STATE_CHANGED value=" + value + " reason=" + reason + " for mPhoneId=" + mPhoneId); IntentBroadcaster.getInstance().broadcastStickyIntent(intent, mPhoneId); } } private void broadcastInternalIccStateChangedIntent(String value, String reason) { synchronized (mLock) { if (mPhoneId == null) { loge("broadcastInternalIccStateChangedIntent: Card Index is not set; Return!!"); return; } Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value); intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId); // SubId may not be valid. log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED value=" + value + " for mPhoneId : " + mPhoneId); ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL); } } private void setExternalState(State newState, boolean override) { synchronized (mLock) { if (mPhoneId == null || !SubscriptionManager.isValidSlotIndex(mPhoneId)) { loge("setExternalState: mPhoneId=" + mPhoneId + " is invalid; Return!!"); return; } if (!override && newState == mExternalState) { log("setExternalState: !override and newstate unchanged from " + newState); return; } mExternalState = newState; log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState); mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString()); // For locked states, we should be sending internal broadcast. if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals( getIccStateIntentString(mExternalState))) { broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState), getIccStateReason(mExternalState)); } else { broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState), getIccStateReason(mExternalState)); } // TODO: Need to notify registrants for other states as well. if ( State.ABSENT == mExternalState) { mAbsentRegistrants.notifyRegistrants(); } } } private void processLockedState() { synchronized (mLock) { if (mUiccApplication == null) { //Don't need to do anything if non-existent application is locked return; } PinState pin1State = mUiccApplication.getPin1State(); if (pin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) { setExternalState(State.PERM_DISABLED); return; } AppState appState = mUiccApplication.getState(); switch (appState) { case APPSTATE_PIN: mPinLockedRegistrants.notifyRegistrants(); setExternalState(State.PIN_REQUIRED); break; case APPSTATE_PUK: setExternalState(State.PUK_REQUIRED); break; case APPSTATE_DETECTED: case APPSTATE_READY: case APPSTATE_SUBSCRIPTION_PERSO: case APPSTATE_UNKNOWN: // Neither required break; } } } private void setExternalState(State newState) { setExternalState(newState, false); } public boolean getIccRecordsLoaded() { synchronized (mLock) { if (mIccRecords != null) { return mIccRecords.getRecordsLoaded(); } return false; } } private String getIccStateIntentString(State state) { switch (state) { case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT; case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; case READY: return IccCardConstants.INTENT_VALUE_ICC_READY; case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY; case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED; case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR; case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED; default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN; } } /** * Locked state have a reason (PIN, PUK, NETWORK, PERM_DISABLED, CARD_IO_ERROR) * @return reason */ private String getIccStateReason(State state) { switch (state) { case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN; case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK; case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_LOCKED_NETWORK; case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED; case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR; case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED; default: return null; } } /* IccCard interface implementation */ @Override public State getState() { synchronized (mLock) { return mExternalState; } } @Override public IccRecords getIccRecords() { synchronized (mLock) { return mIccRecords; } } @Override public IccFileHandler getIccFileHandler() { synchronized (mLock) { if (mUiccApplication != null) { return mUiccApplication.getIccFileHandler(); } return null; } } /** * Notifies handler of any transition into State.ABSENT */ @Override public void registerForAbsent(Handler h, int what, Object obj) { synchronized (mLock) { Registrant r = new Registrant (h, what, obj); mAbsentRegistrants.add(r); if (getState() == State.ABSENT) { r.notifyRegistrant(); } } } @Override public void unregisterForAbsent(Handler h) { synchronized (mLock) { mAbsentRegistrants.remove(h); } } /** * Notifies handler of any transition into State.NETWORK_LOCKED */ @Override public void registerForNetworkLocked(Handler h, int what, Object obj) { synchronized (mLock) { Registrant r = new Registrant (h, what, obj); mNetworkLockedRegistrants.add(r); if (getState() == State.NETWORK_LOCKED) { r.notifyRegistrant(); } } } @Override public void unregisterForNetworkLocked(Handler h) { synchronized (mLock) { mNetworkLockedRegistrants.remove(h); } } /** * Notifies handler of any transition into State.isPinLocked() */ @Override public void registerForLocked(Handler h, int what, Object obj) { synchronized (mLock) { Registrant r = new Registrant (h, what, obj); mPinLockedRegistrants.add(r); if (getState().isPinLocked()) { r.notifyRegistrant(); } } } @Override public void unregisterForLocked(Handler h) { synchronized (mLock) { mPinLockedRegistrants.remove(h); } } @Override public void supplyPin(String pin, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.supplyPin(pin, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("ICC card is absent."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public void supplyPuk(String puk, String newPin, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.supplyPuk(puk, newPin, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("ICC card is absent."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public void supplyPin2(String pin2, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.supplyPin2(pin2, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("ICC card is absent."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public void supplyPuk2(String puk2, String newPin2, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.supplyPuk2(puk2, newPin2, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("ICC card is absent."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public void supplyNetworkDepersonalization(String pin, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.supplyNetworkDepersonalization(pin, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("CommandsInterface is not set."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public boolean getIccLockEnabled() { synchronized (mLock) { /* defaults to false, if ICC is absent/deactivated */ Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccLockEnabled() : false; return retValue; } } @Override public boolean getIccFdnEnabled() { synchronized (mLock) { Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnEnabled() : false; return retValue; } } public boolean getIccFdnAvailable() { boolean retValue = mUiccApplication != null ? mUiccApplication.getIccFdnAvailable() : false; return retValue; } public boolean getIccPin2Blocked() { /* defaults to disabled */ Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPin2Blocked() : false; return retValue; } public boolean getIccPuk2Blocked() { /* defaults to disabled */ Boolean retValue = mUiccApplication != null ? mUiccApplication.getIccPuk2Blocked() : false; return retValue; } @Override public void setIccLockEnabled(boolean enabled, String password, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.setIccLockEnabled(enabled, password, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("ICC card is absent."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public void setIccFdnEnabled(boolean enabled, String password, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.setIccFdnEnabled(enabled, password, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("ICC card is absent."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.changeIccLockPassword(oldPassword, newPassword, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("ICC card is absent."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) { synchronized (mLock) { if (mUiccApplication != null) { mUiccApplication.changeIccFdnPassword(oldPassword, newPassword, onComplete); } else if (onComplete != null) { Exception e = new RuntimeException("ICC card is absent."); AsyncResult.forMessage(onComplete).exception = e; onComplete.sendToTarget(); return; } } } @Override public String getServiceProviderName() { synchronized (mLock) { if (mIccRecords != null) { return mIccRecords.getServiceProviderName(); } return null; } } @Override public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) { synchronized (mLock) { Boolean retValue = mUiccCard != null ? mUiccCard.isApplicationOnIcc(type) : false; return retValue; } } @Override public boolean hasIccCard() { synchronized (mLock) { if (mUiccCard != null && mUiccCard.getCardState() != CardState.CARDSTATE_ABSENT) { return true; } return false; } } private void setSystemProperty(String property, String value) { TelephonyManager.setTelephonyProperty(mPhoneId, property, value); } public IccRecords getIccRecord() { return mIccRecords; } private void log(String s) { Rlog.d(LOG_TAG, s); } private void loge(String msg) { Rlog.e(LOG_TAG, msg); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("IccCardProxy: " + this); pw.println(" mContext=" + mContext); pw.println(" mCi=" + mCi); pw.println(" mAbsentRegistrants: size=" + mAbsentRegistrants.size()); for (int i = 0; i < mAbsentRegistrants.size(); i++) { pw.println(" mAbsentRegistrants[" + i + "]=" + ((Registrant)mAbsentRegistrants.get(i)).getHandler()); } pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size()); for (int i = 0; i < mPinLockedRegistrants.size(); i++) { pw.println(" mPinLockedRegistrants[" + i + "]=" + ((Registrant)mPinLockedRegistrants.get(i)).getHandler()); } pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size()); for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) { pw.println(" mNetworkLockedRegistrants[" + i + "]=" + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler()); } pw.println(" mCurrentAppType=" + mCurrentAppType); pw.println(" mUiccController=" + mUiccController); pw.println(" mUiccCard=" + mUiccCard); pw.println(" mUiccApplication=" + mUiccApplication); pw.println(" mIccRecords=" + mIccRecords); pw.println(" mCdmaSSM=" + mCdmaSSM); pw.println(" mRadioState=" + mRadioState); pw.println(" mQuietMode=" + mQuietMode); pw.println(" mInitialized=" + mInitialized); pw.println(" mExternalState=" + mExternalState); pw.flush(); } }