| /* |
| * 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.MccTable; |
| import com.android.internal.telephony.PhoneConstants; |
| import com.android.internal.telephony.RILConstants; |
| 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_ICC_RECORD_EVENTS = 500; |
| 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 mNetworkLockedRegistrants = new RegistrantList(); |
| |
| private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp? |
| private UiccController mUiccController = null; |
| private UiccSlot mUiccSlot = null; |
| private UiccCard mUiccCard = null; |
| private UiccCardApplication mUiccApplication = null; |
| private IccRecords mIccRecords = null; |
| private RadioState mRadioState = RadioState.RADIO_UNAVAILABLE; |
| 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); |
| 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); |
| } |
| } |
| |
| /* |
| * 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; |
| } |
| updateCurrentAppType(); |
| } |
| } |
| |
| /** |
| * Update current app type and post EVENT_ICC_CHANGED. |
| */ |
| private void updateCurrentAppType() { |
| synchronized (mLock) { |
| boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic() |
| == PhoneConstants.LTE_ON_CDMA_TRUE; |
| if (mCurrentAppType == UiccController.APP_FAM_3GPP2) { |
| if (isLteOnCdmaMode) { |
| log("updateCurrentAppType: is cdma/lte device, force IccCardProxy into 3gpp" |
| + " mode"); |
| mCurrentAppType = UiccController.APP_FAM_3GPP; |
| } |
| |
| if (DBG) { |
| log("updateCurrentAppType: " |
| + " mCurrentAppType=" + mCurrentAppType |
| + " isLteOnCdmaMode=" + isLteOnCdmaMode); |
| } |
| } |
| |
| 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) { |
| updateCurrentAppType(); |
| } else { |
| // updateCurrentAppType() 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: |
| 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 { |
| setExternalState(State.LOADED); |
| } |
| break; |
| case EVENT_IMSI_READY: |
| broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_IMSI, |
| null); |
| break; |
| case EVENT_NETWORK_LOCKED: |
| mNetworkLockedRegistrants.notifyRegistrants(); |
| setExternalState(State.NETWORK_LOCKED); |
| 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); |
| } |
| setExternalState(State.LOADED); |
| break; |
| |
| default: |
| loge("Unhandled message with number: " + msg.what); |
| break; |
| } |
| } |
| |
| private void updateIccAvailability() { |
| synchronized (mLock) { |
| UiccSlot newSlot = mUiccController.getUiccSlotForPhone(mPhoneId); |
| 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 |
| || mUiccSlot != newSlot) { |
| if (DBG) log("Icc changed. Reregistering."); |
| unregisterUiccCardEvents(); |
| mUiccSlot = newSlot; |
| 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_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 (mUiccApplication != null) { |
| mUiccApplication.registerForReady(this, EVENT_APP_READY, null); |
| } |
| if (mIccRecords != null) { |
| mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null); |
| mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); |
| mIccRecords.registerForLockedRecordsLoaded(this, EVENT_ICC_LOCKED, null); |
| mIccRecords.registerForNetworkLockedRecordsLoaded(this, EVENT_NETWORK_LOCKED, null); |
| mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); |
| } |
| } |
| |
| private void unregisterUiccCardEvents() { |
| if (mUiccCard != null) mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this); |
| if (mUiccApplication != null) { |
| mUiccApplication.unregisterForReady(this); |
| } |
| if (mIccRecords != null) { |
| mIccRecords.unregisterForImsiReady(this); |
| mIccRecords.unregisterForRecordsLoaded(this); |
| mIccRecords.unregisterForLockedRecordsLoaded(this); |
| mIccRecords.unregisterForNetworkLockedRecordsLoaded(this); |
| mIccRecords.unregisterForRecordsEvents(this); |
| } |
| } |
| |
| 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_REGISTERED_ONLY_BEFORE_BOOT |
| | Intent.FLAG_RECEIVER_FOREGROUND); |
| 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("broadcastInternalIccStateChangedIntent: 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()); |
| |
| broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState), |
| getIccStateReason(mExternalState)); |
| } |
| } |
| |
| 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: |
| 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; |
| case LOADED: return IccCardConstants.INTENT_VALUE_ICC_LOADED; |
| 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; |
| } |
| } |
| |
| /** |
| * 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); |
| } |
| } |
| |
| @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 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 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(" 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(" mRadioState=" + mRadioState); |
| pw.println(" mInitialized=" + mInitialized); |
| pw.println(" mExternalState=" + mExternalState); |
| |
| pw.flush(); |
| } |
| } |