diff options
Diffstat (limited to 'com/android/internal/telephony/uicc/UiccProfile.java')
-rw-r--r-- | com/android/internal/telephony/uicc/UiccProfile.java | 781 |
1 files changed, 740 insertions, 41 deletions
diff --git a/com/android/internal/telephony/uicc/UiccProfile.java b/com/android/internal/telephony/uicc/UiccProfile.java index 3e7d2d7f..7e59e9ff 100644 --- a/com/android/internal/telephony/uicc/UiccProfile.java +++ b/com/android/internal/telephony/uicc/UiccProfile.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.uicc; +import android.app.ActivityManager; import android.app.AlertDialog; import android.app.usage.UsageStatsManager; import android.content.Context; @@ -31,11 +32,17 @@ import android.os.AsyncResult; import android.os.Binder; import android.os.Handler; import android.os.Message; +import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; +import android.os.UserHandle; import android.preference.PreferenceManager; import android.provider.Settings; +import android.telephony.CarrierConfigManager; import android.telephony.Rlog; +import android.telephony.ServiceState; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.LocalLog; @@ -43,8 +50,16 @@ import android.view.WindowManager; import com.android.internal.R; import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.MccTable; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.cat.CatService; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; +import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccCardStatus.PinState; import java.io.FileDescriptor; @@ -65,9 +80,11 @@ import java.util.List; * * {@hide} */ -public class UiccProfile { +public class UiccProfile extends Handler implements IccCard { protected static final String LOG_TAG = "UiccProfile"; protected static final boolean DBG = true; + private static final boolean VDBG = false; //STOPSHIP if true + private static final boolean ICC_CARD_PROXY_REMOVED = true; private static final String OPERATOR_BRAND_OVERRIDE_PREFIX = "operator_branding_"; @@ -83,6 +100,7 @@ public class UiccProfile { private UiccCard mUiccCard; //parent private CatService mCatService; private UiccCarrierPrivilegeRules mCarrierPrivilegeRules; + private boolean mDisposed = false; private RegistrantList mCarrierPrivilegeRegistrants = new RegistrantList(); @@ -97,12 +115,50 @@ public class UiccProfile { private final int mPhoneId; + /*----------------------------------------------------*/ + // logic moved over from IccCardProxy + private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1; + 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_NETWORK_LOCKED = 9; + + private static final int EVENT_ICC_RECORD_EVENTS = 500; + + private TelephonyManager mTelephonyManager; + + private RegistrantList mNetworkLockedRegistrants = new RegistrantList(); + + private int mCurrentAppType = UiccController.APP_FAM_3GPP; //default to 3gpp? + private UiccCardApplication mUiccApplication = null; + private IccRecords mIccRecords = null; + private IccCardConstants.State mExternalState = IccCardConstants.State.UNKNOWN; + + public static final String ACTION_INTERNAL_SIM_STATE_CHANGED = + "android.intent.action.internal_sim_state_changed"; + + /*----------------------------------------------------*/ + public UiccProfile(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, UiccCard uiccCard) { if (DBG) log("Creating profile"); mUiccCard = uiccCard; mPhoneId = phoneId; + if (ICC_CARD_PROXY_REMOVED) { + // set current app type based on phone type - do this before calling update() as that + // calls updateIccAvailability() which uses mCurrentAppType + Phone phone = PhoneFactory.getPhone(phoneId); + if (phone != null) { + setCurrentAppType(phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM); + } + } update(c, ci, ics); + + if (ICC_CARD_PROXY_REMOVED) { + ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); + + resetProperties(); + } } /** @@ -111,6 +167,14 @@ public class UiccProfile { public void dispose() { synchronized (mLock) { if (DBG) log("Disposing profile"); + + unregisterAllAppEvents(); + unregisterCurrAppEvents(); + + if (ICC_CARD_PROXY_REMOVED) { + mCi.unregisterForOffOrNotAvailable(this); + } + if (mCatService != null) mCatService.dispose(); for (UiccCardApplication app : mUiccApplications) { if (app != null) { @@ -120,6 +184,591 @@ public class UiccProfile { mCatService = null; mUiccApplications = null; mCarrierPrivilegeRules = null; + mDisposed = true; + } + } + + /** + * 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)); + } + setCurrentAppType(ServiceState.isGsm(radioTech)); + updateIccAvailability(false); + } + } + + private void setCurrentAppType(boolean isGsm) { + if (VDBG) log("setCurrentAppType"); + synchronized (mLock) { + boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic() + == PhoneConstants.LTE_ON_CDMA_TRUE; + if (isGsm || isLteOnCdmaMode) { + mCurrentAppType = UiccController.APP_FAM_3GPP; + } else { + mCurrentAppType = UiccController.APP_FAM_3GPP2; + } + } + } + + @Override + public void handleMessage(Message msg) { + if (mDisposed) { + loge("handleMessage: Received " + msg.what + " after dispose(); ignoring the message"); + return; + } + switch (msg.what) { + case EVENT_RADIO_OFF_OR_UNAVAILABLE: + updateExternalState(); + break; + + case EVENT_ICC_LOCKED: + processLockedState(); + break; + + case EVENT_APP_READY: + if (VDBG) log("EVENT_APP_READY"); + if (areAllApplicationsReady()) { + if (areAllRecordsLoaded() && areCarrierPriviligeRulesLoaded()) { + setExternalState(IccCardConstants.State.LOADED); + } else { + setExternalState(IccCardConstants.State.READY); + } + } + break; + + case EVENT_RECORDS_LOADED: + if (VDBG) log("EVENT_RECORDS_LOADED"); + if (!areAllRecordsLoaded()) { + break; + } + // 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 (areCarrierPriviligeRulesLoaded()) { + setExternalState(IccCardConstants.State.LOADED); + } + break; + + case EVENT_NETWORK_LOCKED: + mNetworkLockedRegistrants.notifyRegistrants(); + setExternalState(IccCardConstants.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: + if (VDBG) log("EVENT_CARRIER_PRIVILEGES_LOADED"); + onCarrierPriviligesLoadedMessage(); + if (areAllRecordsLoaded()) { + setExternalState(IccCardConstants.State.LOADED); + } + break; + + case EVENT_OPEN_LOGICAL_CHANNEL_DONE: + case EVENT_CLOSE_LOGICAL_CHANNEL_DONE: + case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE: + case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE: + case EVENT_SIM_IO_DONE: + AsyncResult ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + loglocal("Exception: " + ar.exception); + log("Error in SIM access with exception" + ar.exception); + } + AsyncResult.forMessage((Message) ar.userObj, ar.result, ar.exception); + ((Message) ar.userObj).sendToTarget(); + break; + + default: + loge("Unhandled message with number: " + msg.what); + break; + } + } + + private void updateIccAvailability(boolean allAppsChanged) { + synchronized (mLock) { + UiccCardApplication newApp; + IccRecords newRecords = null; + newApp = getApplication(mCurrentAppType); + if (newApp != null) { + newRecords = newApp.getIccRecords(); + } + + if (allAppsChanged) { + unregisterAllAppEvents(); + registerAllAppEvents(); + } + + if (mIccRecords != newRecords || mUiccApplication != newApp) { + if (DBG) log("Icc changed. Reregistering."); + unregisterCurrAppEvents(); + mUiccApplication = newApp; + mIccRecords = newRecords; + registerCurrAppEvents(); + } + 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 updateExternalState() { + + if (mUiccCard.getCardState() == IccCardStatus.CardState.CARDSTATE_ERROR) { + setExternalState(IccCardConstants.State.CARD_IO_ERROR); + return; + } + + if (mUiccCard.getCardState() == IccCardStatus.CardState.CARDSTATE_RESTRICTED) { + setExternalState(IccCardConstants.State.CARD_RESTRICTED); + return; + } + + if (mUiccApplication == null || !areAllApplicationsReady()) { + setExternalState(IccCardConstants.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(IccCardConstants.State.NOT_READY); + break; + case APPSTATE_SUBSCRIPTION_PERSO: + if (mUiccApplication.getPersoSubState() + == IccCardApplicationStatus.PersoSubState.PERSOSUBSTATE_SIM_NETWORK) { + setExternalState(IccCardConstants.State.NETWORK_LOCKED); + } + // Otherwise don't change external SIM state. + break; + case APPSTATE_READY: + if (areAllApplicationsReady()) { + if (areAllRecordsLoaded() && areCarrierPriviligeRulesLoaded()) { + setExternalState(IccCardConstants.State.LOADED); + } else { + setExternalState(IccCardConstants.State.READY); + } + } else { + setExternalState(IccCardConstants.State.NOT_READY); + } + break; + } + } + + private void registerAllAppEvents() { + // todo: all of these should be notified to UiccProfile directly without needing to register + for (UiccCardApplication app : mUiccApplications) { + if (app != null) { + if (VDBG) log("registerUiccCardEvents: registering for EVENT_APP_READY"); + app.registerForReady(this, EVENT_APP_READY, null); + IccRecords ir = app.getIccRecords(); + if (ir != null) { + if (VDBG) log("registerUiccCardEvents: registering for EVENT_RECORDS_LOADED"); + ir.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); + ir.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); + } + } + } + } + + private void unregisterAllAppEvents() { + for (UiccCardApplication app : mUiccApplications) { + if (app != null) { + app.unregisterForReady(this); + IccRecords ir = app.getIccRecords(); + if (ir != null) { + ir.unregisterForRecordsLoaded(this); + ir.unregisterForRecordsEvents(this); + } + } + } + } + + private void registerCurrAppEvents() { + // In case of locked, only listen to the current application. + if (mIccRecords != null) { + mIccRecords.registerForLockedRecordsLoaded(this, EVENT_ICC_LOCKED, null); + mIccRecords.registerForNetworkLockedRecordsLoaded(this, EVENT_NETWORK_LOCKED, null); + } + } + + private void unregisterCurrAppEvents() { + if (mIccRecords != null) { + mIccRecords.unregisterForLockedRecordsLoaded(this); + mIccRecords.unregisterForNetworkLockedRecordsLoaded(this); + } + } + + private void broadcastInternalIccStateChangedIntent(String value, String reason) { + synchronized (mLock) { + 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("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED value=" + value + + " for mPhoneId : " + mPhoneId); + ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL); + } + } + + private void setExternalState(IccCardConstants.State newState, boolean override) { + synchronized (mLock) { + if (!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(IccCardConstants.State.PERM_DISABLED); + return; + } + + IccCardApplicationStatus.AppState appState = mUiccApplication.getState(); + switch (appState) { + case APPSTATE_PIN: + setExternalState(IccCardConstants.State.PIN_REQUIRED); + break; + case APPSTATE_PUK: + setExternalState(IccCardConstants.State.PUK_REQUIRED); + break; + case APPSTATE_DETECTED: + case APPSTATE_READY: + case APPSTATE_SUBSCRIPTION_PERSO: + case APPSTATE_UNKNOWN: + // Neither required + break; + } + } + } + + private void setExternalState(IccCardConstants.State newState) { + setExternalState(newState, false); + } + + /** + * Function to check if all ICC records have been loaded + * @return true if all ICC records have been loaded, false otherwise. + */ + public boolean getIccRecordsLoaded() { + synchronized (mLock) { + if (mIccRecords != null) { + return mIccRecords.getRecordsLoaded(); + } + return false; + } + } + + private String getIccStateIntentString(IccCardConstants.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(IccCardConstants.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 IccCardConstants.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() == IccCardConstants.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 */ + return mUiccApplication != null && mUiccApplication.getIccLockEnabled(); + } + } + + @Override + public boolean getIccFdnEnabled() { + synchronized (mLock) { + return mUiccApplication != null && mUiccApplication.getIccFdnEnabled(); + } + } + + @Override + public boolean getIccPin2Blocked() { + /* defaults to disabled */ + return mUiccApplication != null && mUiccApplication.getIccPin2Blocked(); + } + + @Override + public boolean getIccPuk2Blocked() { + /* defaults to disabled */ + return mUiccApplication != null && mUiccApplication.getIccPuk2Blocked(); + } + + @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 hasIccCard() { + synchronized (mLock) { + if (mUiccCard != null && mUiccCard.getCardState() + != IccCardStatus.CardState.CARDSTATE_ABSENT) { + return true; + } + loge("hasIccCard: UiccProfile is not null but UiccCard is null or card state is " + + "ABSENT"); + return false; } } @@ -134,6 +783,8 @@ public class UiccProfile { mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex; mContext = c; mCi = ci; + mTelephonyManager = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); //update applications if (DBG) log(ics.mApplications.length + " applications"); @@ -141,7 +792,7 @@ public class UiccProfile { if (mUiccApplications[i] == null) { //Create newly added Applications if (i < ics.mApplications.length) { - mUiccApplications[i] = new UiccCardApplication(mUiccCard, + mUiccApplications[i] = new UiccCardApplication(this, ics.mApplications[i], mContext, mCi); } } else if (i >= ics.mApplications.length) { @@ -156,13 +807,18 @@ public class UiccProfile { createAndUpdateCatServiceLocked(); - log("Before privilege rules: " + mCarrierPrivilegeRules); - if (mCarrierPrivilegeRules == null) { - mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccCard, - mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED)); + // Reload the carrier privilege rules if necessary. + log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + ics.mCardState); + if (mCarrierPrivilegeRules == null && ics.mCardState == CardState.CARDSTATE_PRESENT) { + mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this, + obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED)); + } else if (mCarrierPrivilegeRules != null + && ics.mCardState != CardState.CARDSTATE_PRESENT) { + mCarrierPrivilegeRules = null; } sanitizeApplicationIndexesLocked(); + updateIccAvailability(true); } } @@ -170,9 +826,9 @@ public class UiccProfile { if (mUiccApplications.length > 0 && mUiccApplications[0] != null) { // Initialize or Reinitialize CatService if (mCatService == null) { - mCatService = CatService.getInstance(mCi, mContext, mUiccCard, mPhoneId); + mCatService = CatService.getInstance(mCi, mContext, this, mPhoneId); } else { - mCatService.update(mCi, mContext, mUiccCard); + mCatService.update(mCi, mContext, this); } } else { if (mCatService != null) { @@ -203,6 +859,46 @@ public class UiccProfile { checkIndexLocked(mImsSubscriptionAppIndex, AppType.APPTYPE_ISIM, null); } + private boolean isSupportedApplication(UiccCardApplication app) { + if (app.getType() != AppType.APPTYPE_USIM && app.getType() != AppType.APPTYPE_CSIM + && app.getType() != AppType.APPTYPE_ISIM && app.getType() != AppType.APPTYPE_SIM + && app.getType() != AppType.APPTYPE_RUIM) { + return false; + } + return true; + } + + private boolean areAllApplicationsReady() { + for (UiccCardApplication app : mUiccApplications) { + if (app != null && isSupportedApplication(app) && !app.isReady()) { + if (VDBG) log("areAllApplicationsReady: return false"); + return false; + } + } + if (VDBG) { + log("areAllApplicationsReady: outside loop, return " + (mUiccApplications[0] != null)); + } + // Returns false if there is no application in the UiccProfile. + return mUiccApplications[0] != null; + } + + private boolean areAllRecordsLoaded() { + for (UiccCardApplication app : mUiccApplications) { + if (app != null && isSupportedApplication(app)) { + IccRecords ir = app.getIccRecords(); + if (ir == null || !ir.isLoaded()) { + if (VDBG) log("areAllRecordsLoaded: return false"); + return false; + } + } + } + if (VDBG) { + log("areAllRecordsLoaded: outside loop, return " + (mUiccApplications[0] != null)); + } + // Returns false if there is no application in the UiccProfile. + return mUiccApplications[0] != null; + } + private int checkIndexLocked(int index, AppType expectedAppType, AppType altExpectedAppType) { if (mUiccApplications == null || index >= mUiccApplications.length) { loge("App index " + index + " is invalid since there are no applications"); @@ -255,32 +951,6 @@ public class UiccProfile { } } - protected Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_OPEN_LOGICAL_CHANNEL_DONE: - case EVENT_CLOSE_LOGICAL_CHANNEL_DONE: - case EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE: - case EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE: - case EVENT_SIM_IO_DONE: - AsyncResult ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - loglocal("Exception: " + ar.exception); - log("Error in SIM access with exception" + ar.exception); - } - AsyncResult.forMessage((Message) ar.userObj, ar.result, ar.exception); - ((Message) ar.userObj).sendToTarget(); - break; - case EVENT_CARRIER_PRIVILEGES_LOADED: - onCarrierPriviligesLoadedMessage(); - break; - default: - loge("Unknown Event " + msg.what); - } - } - }; - private boolean isPackageInstalled(String pkgName) { PackageManager pm = mContext.getPackageManager(); try { @@ -484,7 +1154,7 @@ public class UiccProfile { loglocal("Open Logical Channel: " + aid + " , " + p2 + " by pid:" + Binder.getCallingPid() + " uid:" + Binder.getCallingUid()); mCi.iccOpenLogicalChannel(aid, p2, - mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response)); + obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response)); } /** @@ -493,7 +1163,7 @@ public class UiccProfile { public void iccCloseLogicalChannel(int channel, Message response) { loglocal("Close Logical Channel: " + channel); mCi.iccCloseLogicalChannel(channel, - mHandler.obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response)); + obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response)); } /** @@ -502,7 +1172,7 @@ public class UiccProfile { public void iccTransmitApduLogicalChannel(int channel, int cla, int command, int p1, int p2, int p3, String data, Message response) { mCi.iccTransmitApduLogicalChannel(channel, cla, command, p1, p2, p3, - data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); + data, obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); } /** @@ -511,7 +1181,7 @@ public class UiccProfile { public void iccTransmitApduBasicChannel(int cla, int command, int p1, int p2, int p3, String data, Message response) { mCi.iccTransmitApduBasicChannel(cla, command, p1, p2, p3, - data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response)); + data, obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response)); } /** @@ -520,7 +1190,7 @@ public class UiccProfile { public void iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, String pathID, Message response) { mCi.iccIO(command, fileID, pathID, p1, p2, p3, null, null, - mHandler.obtainMessage(EVENT_SIM_IO_DONE, response)); + obtainMessage(EVENT_SIM_IO_DONE, response)); } /** @@ -631,7 +1301,7 @@ public class UiccProfile { */ public boolean setOperatorBrandOverride(String brand) { log("setOperatorBrandOverride: " + brand); - log("current iccId: " + getIccId()); + log("current iccId: " + SubscriptionInfo.givePrintableIccid(getIccId())); String iccId = getIccId(); if (TextUtils.isEmpty(iccId)) { @@ -658,7 +1328,21 @@ public class UiccProfile { return null; } SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - return sp.getString(OPERATOR_BRAND_OVERRIDE_PREFIX + iccId, null); + String brandName = sp.getString(OPERATOR_BRAND_OVERRIDE_PREFIX + iccId, null); + if (brandName == null) { + // Check if CarrierConfig sets carrier name + CarrierConfigManager manager = (CarrierConfigManager) + mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); + int subId = SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhoneId); + if (manager != null) { + PersistableBundle bundle = manager.getConfigForSubId(subId); + if (bundle != null && bundle.getBoolean( + CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL)) { + brandName = bundle.getString(CarrierConfigManager.KEY_CARRIER_NAME_STRING); + } + } + } + return brandName; } /** @@ -744,6 +1428,21 @@ public class UiccProfile { + ((Registrant) mCarrierPrivilegeRegistrants.get(i)).getHandler()); } pw.flush(); + + if (ICC_CARD_PROXY_REMOVED) { + 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(" mUiccCard=" + mUiccCard); + pw.println(" mUiccApplication=" + mUiccApplication); + pw.println(" mIccRecords=" + mIccRecords); + pw.println(" mExternalState=" + mExternalState); + pw.flush(); + } + pw.println("sLocalLog:"); sLocalLog.dump(fd, pw, args); pw.flush(); |