| /* |
| * 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 static android.Manifest.permission.READ_PHONE_STATE; |
| |
| import android.app.ActivityManagerNative; |
| 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.SystemProperties; |
| import android.os.UserHandle; |
| import android.telephony.Rlog; |
| import android.telephony.ServiceState; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| |
| import com.android.internal.telephony.CommandsInterface; |
| import com.android.internal.telephony.IccCard; |
| import com.android.internal.telephony.IccCardConstants; |
| import com.android.internal.telephony.PhoneConstants; |
| import com.android.internal.telephony.MccTable; |
| import com.android.internal.telephony.RILConstants; |
| import com.android.internal.telephony.TelephonyIntents; |
| import com.android.internal.telephony.IccCardConstants.State; |
| import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; |
| import com.android.internal.telephony.Phone; |
| import com.android.internal.telephony.SubscriptionController; |
| 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 com.android.internal.telephony.uicc.UiccController; |
| |
| 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_PRIVILIGES_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 boolean mRadioOn = false; |
| 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(); |
| setExternalState(State.NOT_READY, false); |
| } |
| |
| 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: |
| mRadioOn = false; |
| if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) { |
| setExternalState(State.NOT_READY); |
| } |
| break; |
| case EVENT_RADIO_ON: |
| mRadioOn = true; |
| if (!mInitialized) { |
| updateQuietMode(); |
| } |
| 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 (operator != null) { |
| log("update icc_operator_numeric=" + 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_PRIVILIGES_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_PRIVILIGES_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); |
| CardState state = CardState.CARDSTATE_ABSENT; |
| UiccCardApplication newApp = null; |
| IccRecords newRecords = null; |
| if (newCard != null) { |
| state = newCard.getCardState(); |
| newApp = newCard.getApplication(mCurrentAppType); |
| if (newApp != null) { |
| newRecords = newApp.getIccRecords(); |
| } |
| } |
| |
| if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) { |
| if (DBG) log("Icc changed. Reregestering."); |
| 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() { |
| if (mUiccCard == null || mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) { |
| if (mRadioOn) { |
| setExternalState(State.ABSENT); |
| } else { |
| setExternalState(State.NOT_READY); |
| } |
| return; |
| } |
| |
| if (mUiccCard.getCardState() == CardState.CARDSTATE_ERROR) { |
| setExternalState(State.CARD_IO_ERROR); |
| return; |
| } |
| |
| if (mUiccApplication == null) { |
| setExternalState(State.NOT_READY); |
| return; |
| } |
| |
| switch (mUiccApplication.getState()) { |
| case APPSTATE_UNKNOWN: |
| setExternalState(State.UNKNOWN); |
| break; |
| case APPSTATE_DETECTED: |
| HandleDetectedState(); |
| break; |
| case APPSTATE_PIN: |
| setExternalState(State.PIN_REQUIRED); |
| break; |
| case APPSTATE_PUK: |
| setExternalState(State.PUK_REQUIRED); |
| break; |
| case APPSTATE_SUBSCRIPTION_PERSO: |
| if (mUiccApplication.getPersoSubState() == |
| PersoSubState.PERSOSUBSTATE_SIM_NETWORK) { |
| setExternalState(State.NETWORK_LOCKED); |
| } else { |
| setExternalState(State.UNKNOWN); |
| } |
| 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 (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.isValidSlotId(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); |
| ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE, |
| UserHandle.USER_ALL); |
| } |
| } |
| |
| 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" + " for mPhoneId : " + mPhoneId); |
| ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL); |
| } |
| } |
| |
| private void setExternalState(State newState, boolean override) { |
| synchronized (mLock) { |
| if (mPhoneId == null || !SubscriptionManager.isValidSlotId(mPhoneId)) { |
| loge("setExternalState: mPhoneId=" + mPhoneId + " is invalid; Return!!"); |
| return; |
| } |
| |
| if (!override && newState == mExternalState) { |
| loge("setExternalState: !override and newstate unchanged from " + newState); |
| return; |
| } |
| mExternalState = newState; |
| loge("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; |
| 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; |
| 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(" mRadioOn=" + mRadioOn); |
| pw.println(" mQuietMode=" + mQuietMode); |
| pw.println(" mInitialized=" + mInitialized); |
| pw.println(" mExternalState=" + mExternalState); |
| |
| pw.flush(); |
| } |
| } |