Loading src/java/com/android/internal/telephony/GsmCdmaPhone.java +4 −1 Original line number Diff line number Diff line Loading @@ -3371,7 +3371,10 @@ public class GsmCdmaPhone extends Phone { @Override public IccCard getIccCard() { return UiccController.getInstance().getUiccProfileForPhone(mPhoneId); // This used to always return a non-null object. But getUiccProfile() can return null. // For backward compatibility consideration, we return a dummy object instead of null. IccCard iccCard = getUiccProfile(); return (iccCard != null) ? iccCard : new IccCard(); } private UiccProfile getUiccProfile() { Loading src/java/com/android/internal/telephony/IccCard.java +73 −23 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.telephony; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; Loading @@ -37,23 +38,34 @@ import com.android.internal.telephony.uicc.IccRecords; * This interface is implemented by UiccProfile and the object PhoneApp * gets when it calls getIccCard is UiccProfile. */ public interface IccCard { public class IccCard { /** * @return combined Card and current App state */ public State getState(); public State getState() { return State.UNKNOWN; } // todo: delete /** * @return IccRecords object belonging to current UiccCardApplication */ public IccRecords getIccRecords(); public IccRecords getIccRecords() { return null; } /** * Notifies handler of any transition into IccCardConstants.State.NETWORK_LOCKED */ public void registerForNetworkLocked(Handler h, int what, Object obj); public void unregisterForNetworkLocked(Handler h); public void registerForNetworkLocked(Handler h, int what, Object obj) { return; } /** * Unregister for networkLocked state change. */ public void unregisterForNetworkLocked(Handler h) { return; } /** * Supply the ICC PIN to the ICC Loading @@ -73,27 +85,37 @@ public interface IccCard { * && ((CommandException)(((AsyncResult)onComplete.obj).exception)) * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT */ public void supplyPin (String pin, Message onComplete); public void supplyPin(String pin, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Supply the ICC PUK to the ICC */ public void supplyPuk (String puk, String newPin, Message onComplete); public void supplyPuk(String puk, String newPin, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Supply the ICC PIN2 to the ICC */ public void supplyPin2 (String pin2, Message onComplete); public void supplyPin2(String pin2, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Supply the ICC PUK2 to the ICC */ public void supplyPuk2 (String puk2, String newPin2, Message onComplete); public void supplyPuk2(String puk2, String newPin2, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Supply Network depersonalization code to the RIL */ public void supplyNetworkDepersonalization (String pin, Message onComplete); public void supplyNetworkDepersonalization(String pin, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Check whether ICC pin lock is enabled Loading @@ -102,7 +124,9 @@ public interface IccCard { * @return true for ICC locked enabled * false for ICC locked disabled */ public boolean getIccLockEnabled(); public boolean getIccLockEnabled() { return false; } /** * Check whether ICC fdn (fixed dialing number) is enabled Loading @@ -111,7 +135,9 @@ public interface IccCard { * @return true for ICC fdn enabled * false for ICC fdn disabled */ public boolean getIccFdnEnabled(); public boolean getIccFdnEnabled() { return false; } /** * Set the ICC pin lock enabled or disabled Loading @@ -125,7 +151,9 @@ public interface IccCard { * ((AsyncResult)onComplete.obj).exception != null on fail */ public void setIccLockEnabled(boolean enabled, String password, Message onComplete); String password, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Set the ICC fdn enabled or disabled Loading @@ -139,7 +167,9 @@ public interface IccCard { * ((AsyncResult)onComplete.obj).exception != null on fail */ public void setIccFdnEnabled(boolean enabled, String password, Message onComplete); String password, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Change the ICC password used in ICC pin lock Loading @@ -153,7 +183,9 @@ public interface IccCard { * ((AsyncResult)onComplete.obj).exception != null on fail */ public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete); Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Change the ICC password used in ICC fdn enable Loading @@ -167,7 +199,9 @@ public interface IccCard { * ((AsyncResult)onComplete.obj).exception != null on fail */ public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete); Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Returns service provider name stored in ICC card. Loading @@ -185,26 +219,42 @@ public interface IccCard { * yet available * */ public String getServiceProviderName (); public String getServiceProviderName() { return null; } /** * Checks if an Application of specified type present on the card * @param type is AppType to look for */ public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type); public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) { return false; } /** * @return true if a ICC card is present */ public boolean hasIccCard(); public boolean hasIccCard() { return false; } /** * @return true if ICC card is PIN2 blocked */ public boolean getIccPin2Blocked(); public boolean getIccPin2Blocked() { return false; } /** * @return true if ICC card is PUK2 blocked */ public boolean getIccPuk2Blocked(); public boolean getIccPuk2Blocked() { return false; } private void sendMessageWithCardAbsentException(Message onComplete) { AsyncResult ret = AsyncResult.forMessage(onComplete); ret.exception = new RuntimeException("No valid IccCard"); onComplete.sendToTarget(); } } src/java/com/android/internal/telephony/uicc/UiccProfile.java +93 −89 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ import java.util.List; * * {@hide} */ public class UiccProfile extends Handler implements IccCard { public class UiccProfile extends IccCard { protected static final String LOG_TAG = "UiccProfile"; protected static final boolean DBG = true; private static final boolean VDBG = false; //STOPSHIP if true Loading Loading @@ -136,7 +136,78 @@ public class UiccProfile extends Handler implements IccCard { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED)); mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARRIER_CONFIG_CHANGED)); } } }; @VisibleForTesting public final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // We still need to handle the following response messages even the UiccProfile has been // disposed because whoever sent the request may be still waiting for the response. if (mDisposed && msg.what != EVENT_OPEN_LOGICAL_CHANNEL_DONE && msg.what != EVENT_CLOSE_LOGICAL_CHANNEL_DONE && msg.what != EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE && msg.what != EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE && msg.what != EVENT_SIM_IO_DONE) { loge("handleMessage: Received " + msg.what + " after dispose(); ignoring the message"); return; } loglocal("handleMessage: Received " + msg.what + " for phoneId " + mPhoneId); switch (msg.what) { case EVENT_NETWORK_LOCKED: mNetworkLockedRegistrants.notifyRegistrants(); // intentional fall through case EVENT_RADIO_OFF_OR_UNAVAILABLE: case EVENT_ICC_LOCKED: case EVENT_APP_READY: case EVENT_RECORDS_LOADED: case EVENT_EID_READY: if (VDBG) log("handleMessage: Received " + msg.what); updateExternalState(); 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("handleMessage: EVENT_CARRIER_PRIVILEGES_LOADED"); onCarrierPriviligesLoadedMessage(); updateExternalState(); break; case EVENT_CARRIER_CONFIG_CHANGED: handleCarrierNameOverride(); 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("handleMessage: Exception " + ar.exception); log("handleMessage: Error in SIM access with exception" + ar.exception); } AsyncResult.forMessage((Message) ar.userObj, ar.result, ar.exception); ((Message) ar.userObj).sendToTarget(); break; default: loge("handleMessage: Unhandled message with number: " + msg.what); break; } } }; Loading @@ -154,11 +225,11 @@ public class UiccProfile extends Handler implements IccCard { } if (mUiccCard instanceof EuiccCard) { ((EuiccCard) mUiccCard).registerForEidReady(this, EVENT_EID_READY, null); ((EuiccCard) mUiccCard).registerForEidReady(mHandler, EVENT_EID_READY, null); } update(c, ci, ics); ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); ci.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); resetProperties(); IntentFilter intentfilter = new IntentFilter(); Loading @@ -177,10 +248,10 @@ public class UiccProfile extends Handler implements IccCard { unregisterCurrAppEvents(); if (mUiccCard instanceof EuiccCard) { ((EuiccCard) mUiccCard).unregisterForEidReady(this); ((EuiccCard) mUiccCard).unregisterForEidReady(mHandler); } mCi.unregisterForOffOrNotAvailable(this); mCi.unregisterForOffOrNotAvailable(mHandler); mContext.unregisterReceiver(mReceiver); if (mCatService != null) mCatService.dispose(); Loading Loading @@ -221,73 +292,6 @@ public class UiccProfile extends Handler implements IccCard { } } @Override public void handleMessage(Message msg) { // We still need to handle the following response messages even the UiccProfile has been // disposed because whoever sent the request may be still waiting for the response. if (mDisposed && msg.what != EVENT_OPEN_LOGICAL_CHANNEL_DONE && msg.what != EVENT_CLOSE_LOGICAL_CHANNEL_DONE && msg.what != EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE && msg.what != EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE && msg.what != EVENT_SIM_IO_DONE) { loge("handleMessage: Received " + msg.what + " after dispose(); ignoring the message"); return; } loglocal("handleMessage: Received " + msg.what + " for phoneId " + mPhoneId); switch (msg.what) { case EVENT_NETWORK_LOCKED: mNetworkLockedRegistrants.notifyRegistrants(); // intentional fall through case EVENT_RADIO_OFF_OR_UNAVAILABLE: case EVENT_ICC_LOCKED: case EVENT_APP_READY: case EVENT_RECORDS_LOADED: case EVENT_EID_READY: if (VDBG) log("handleMessage: Received " + msg.what); updateExternalState(); 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("handleMessage: EVENT_CARRIER_PRIVILEGES_LOADED"); onCarrierPriviligesLoadedMessage(); updateExternalState(); break; case EVENT_CARRIER_CONFIG_CHANGED: handleCarrierNameOverride(); 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("handleMessage: Exception " + ar.exception); log("handleMessage: Error in SIM access with exception" + ar.exception); } AsyncResult.forMessage((Message) ar.userObj, ar.result, ar.exception); ((Message) ar.userObj).sendToTarget(); break; default: loge("handleMessage: Unhandled message with number: " + msg.what); break; } } /** * Override the carrier name with either carrier config or SPN * if an override is provided. Loading Loading @@ -505,12 +509,12 @@ public class UiccProfile extends Handler implements IccCard { for (UiccCardApplication app : mUiccApplications) { if (app != null) { if (VDBG) log("registerUiccCardEvents: registering for EVENT_APP_READY"); app.registerForReady(this, EVENT_APP_READY, null); app.registerForReady(mHandler, 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); ir.registerForRecordsLoaded(mHandler, EVENT_RECORDS_LOADED, null); ir.registerForRecordsEvents(mHandler, EVENT_ICC_RECORD_EVENTS, null); } } } Loading @@ -519,11 +523,11 @@ public class UiccProfile extends Handler implements IccCard { private void unregisterAllAppEvents() { for (UiccCardApplication app : mUiccApplications) { if (app != null) { app.unregisterForReady(this); app.unregisterForReady(mHandler); IccRecords ir = app.getIccRecords(); if (ir != null) { ir.unregisterForRecordsLoaded(this); ir.unregisterForRecordsEvents(this); ir.unregisterForRecordsLoaded(mHandler); ir.unregisterForRecordsEvents(mHandler); } } } Loading @@ -532,15 +536,15 @@ public class UiccProfile extends Handler implements IccCard { 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); mIccRecords.registerForLockedRecordsLoaded(mHandler, EVENT_ICC_LOCKED, null); mIccRecords.registerForNetworkLockedRecordsLoaded(mHandler, EVENT_NETWORK_LOCKED, null); } } private void unregisterCurrAppEvents() { if (mIccRecords != null) { mIccRecords.unregisterForLockedRecordsLoaded(this); mIccRecords.unregisterForNetworkLockedRecordsLoaded(this); mIccRecords.unregisterForLockedRecordsLoaded(mHandler); mIccRecords.unregisterForNetworkLockedRecordsLoaded(mHandler); } } Loading Loading @@ -886,7 +890,7 @@ public class UiccProfile extends Handler implements IccCard { log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + ics.mCardState); if (mCarrierPrivilegeRules == null && ics.mCardState == CardState.CARDSTATE_PRESENT) { mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this, obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED)); mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED)); } else if (mCarrierPrivilegeRules != null && ics.mCardState != CardState.CARDSTATE_PRESENT) { mCarrierPrivilegeRules = null; Loading Loading @@ -1234,7 +1238,7 @@ public class UiccProfile extends Handler implements IccCard { loglocal("iccOpenLogicalChannel: " + aid + " , " + p2 + " by pid:" + Binder.getCallingPid() + " uid:" + Binder.getCallingUid()); mCi.iccOpenLogicalChannel(aid, p2, obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response)); mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response)); } /** Loading @@ -1243,7 +1247,7 @@ public class UiccProfile extends Handler implements IccCard { public void iccCloseLogicalChannel(int channel, Message response) { loglocal("iccCloseLogicalChannel: " + channel); mCi.iccCloseLogicalChannel(channel, obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response)); mHandler.obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response)); } /** Loading @@ -1252,7 +1256,7 @@ public class UiccProfile extends Handler implements IccCard { 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, obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); } /** Loading @@ -1261,7 +1265,7 @@ public class UiccProfile extends Handler implements IccCard { 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, obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response)); data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response)); } /** Loading @@ -1270,7 +1274,7 @@ public class UiccProfile extends Handler implements IccCard { 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, obtainMessage(EVENT_SIM_IO_DONE, response)); mHandler.obtainMessage(EVENT_SIM_IO_DONE, response)); } /** Loading tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +39 −0 Original line number Diff line number Diff line Loading @@ -57,8 +57,10 @@ import android.telephony.gsm.GsmCellLocation; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccException; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.UiccProfile; import org.junit.After; import org.junit.Before; Loading @@ -79,6 +81,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { private static final int EVENT_EMERGENCY_CALLBACK_MODE_EXIT = 1; private static final int EVENT_EMERGENCY_CALL_TOGGLE = 2; private static final int EVENT_SET_ICC_LOCK_ENABLED = 3; private class GsmCdmaPhoneTestHandler extends HandlerThread { Loading Loading @@ -812,4 +815,40 @@ public class GsmCdmaPhoneTest extends TelephonyTest { waitForMs(100); verify(mEriManager, times(1)).loadEriFile(); } @Test @SmallTest public void testGetEmptyIccCard() { doReturn(null).when(mUiccController).getUiccProfileForPhone(anyInt()); IccCard iccCard = mPhoneUT.getIccCard(); // The iccCard should be a dummy object, not null. assertTrue(!(iccCard instanceof UiccProfile)); assertTrue(iccCard != null); assertEquals(IccCardConstants.State.UNKNOWN, iccCard.getState()); assertEquals(null, iccCard.getIccRecords()); assertEquals(false, iccCard.getIccLockEnabled()); assertEquals(false, iccCard.getIccFdnEnabled()); assertEquals(false, iccCard.isApplicationOnIcc( IccCardApplicationStatus.AppType.APPTYPE_SIM)); assertEquals(false, iccCard.hasIccCard()); assertEquals(false, iccCard.getIccPin2Blocked()); assertEquals(false, iccCard.getIccPuk2Blocked()); Message onComplete = mTestHandler.obtainMessage(EVENT_SET_ICC_LOCK_ENABLED); iccCard.setIccLockEnabled(true, "password", onComplete); waitForMs(100); ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); // Verify that message is sent back with exception. verify(mTestHandler, times(1)).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong()); Message message = messageArgumentCaptor.getAllValues().get(0); AsyncResult ret = (AsyncResult) message.obj; assertEquals(EVENT_SET_ICC_LOCK_ENABLED, message.what); assertTrue(ret.exception != null); } } tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java +10 −5 Original line number Diff line number Diff line Loading @@ -286,7 +286,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(3, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); assertEquals(mUiccProfile.getState(), State.NOT_READY); } Loading Loading @@ -318,7 +319,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(3, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); // state is loaded as all records are loaded right away as SimulatedCommands returns // response for them right away. Ideally applications and records should be mocked. Loading Loading @@ -352,7 +354,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(3, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); // state is loaded as all records are loaded right away as SimulatedCommands returns // response for them right away. Ideally applications and records should be mocked. Loading @@ -376,7 +379,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(0, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); // state is loaded since there is no applications. assertEquals(State.NOT_READY, mUiccProfile.getState()); Loading @@ -402,7 +406,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(1, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); // state is loaded since there is no applications. assertEquals(State.NOT_READY, mUiccProfile.getState()); Loading Loading
src/java/com/android/internal/telephony/GsmCdmaPhone.java +4 −1 Original line number Diff line number Diff line Loading @@ -3371,7 +3371,10 @@ public class GsmCdmaPhone extends Phone { @Override public IccCard getIccCard() { return UiccController.getInstance().getUiccProfileForPhone(mPhoneId); // This used to always return a non-null object. But getUiccProfile() can return null. // For backward compatibility consideration, we return a dummy object instead of null. IccCard iccCard = getUiccProfile(); return (iccCard != null) ? iccCard : new IccCard(); } private UiccProfile getUiccProfile() { Loading
src/java/com/android/internal/telephony/IccCard.java +73 −23 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.internal.telephony; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; Loading @@ -37,23 +38,34 @@ import com.android.internal.telephony.uicc.IccRecords; * This interface is implemented by UiccProfile and the object PhoneApp * gets when it calls getIccCard is UiccProfile. */ public interface IccCard { public class IccCard { /** * @return combined Card and current App state */ public State getState(); public State getState() { return State.UNKNOWN; } // todo: delete /** * @return IccRecords object belonging to current UiccCardApplication */ public IccRecords getIccRecords(); public IccRecords getIccRecords() { return null; } /** * Notifies handler of any transition into IccCardConstants.State.NETWORK_LOCKED */ public void registerForNetworkLocked(Handler h, int what, Object obj); public void unregisterForNetworkLocked(Handler h); public void registerForNetworkLocked(Handler h, int what, Object obj) { return; } /** * Unregister for networkLocked state change. */ public void unregisterForNetworkLocked(Handler h) { return; } /** * Supply the ICC PIN to the ICC Loading @@ -73,27 +85,37 @@ public interface IccCard { * && ((CommandException)(((AsyncResult)onComplete.obj).exception)) * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT */ public void supplyPin (String pin, Message onComplete); public void supplyPin(String pin, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Supply the ICC PUK to the ICC */ public void supplyPuk (String puk, String newPin, Message onComplete); public void supplyPuk(String puk, String newPin, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Supply the ICC PIN2 to the ICC */ public void supplyPin2 (String pin2, Message onComplete); public void supplyPin2(String pin2, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Supply the ICC PUK2 to the ICC */ public void supplyPuk2 (String puk2, String newPin2, Message onComplete); public void supplyPuk2(String puk2, String newPin2, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Supply Network depersonalization code to the RIL */ public void supplyNetworkDepersonalization (String pin, Message onComplete); public void supplyNetworkDepersonalization(String pin, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Check whether ICC pin lock is enabled Loading @@ -102,7 +124,9 @@ public interface IccCard { * @return true for ICC locked enabled * false for ICC locked disabled */ public boolean getIccLockEnabled(); public boolean getIccLockEnabled() { return false; } /** * Check whether ICC fdn (fixed dialing number) is enabled Loading @@ -111,7 +135,9 @@ public interface IccCard { * @return true for ICC fdn enabled * false for ICC fdn disabled */ public boolean getIccFdnEnabled(); public boolean getIccFdnEnabled() { return false; } /** * Set the ICC pin lock enabled or disabled Loading @@ -125,7 +151,9 @@ public interface IccCard { * ((AsyncResult)onComplete.obj).exception != null on fail */ public void setIccLockEnabled(boolean enabled, String password, Message onComplete); String password, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Set the ICC fdn enabled or disabled Loading @@ -139,7 +167,9 @@ public interface IccCard { * ((AsyncResult)onComplete.obj).exception != null on fail */ public void setIccFdnEnabled(boolean enabled, String password, Message onComplete); String password, Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Change the ICC password used in ICC pin lock Loading @@ -153,7 +183,9 @@ public interface IccCard { * ((AsyncResult)onComplete.obj).exception != null on fail */ public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete); Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Change the ICC password used in ICC fdn enable Loading @@ -167,7 +199,9 @@ public interface IccCard { * ((AsyncResult)onComplete.obj).exception != null on fail */ public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete); Message onComplete) { sendMessageWithCardAbsentException(onComplete); } /** * Returns service provider name stored in ICC card. Loading @@ -185,26 +219,42 @@ public interface IccCard { * yet available * */ public String getServiceProviderName (); public String getServiceProviderName() { return null; } /** * Checks if an Application of specified type present on the card * @param type is AppType to look for */ public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type); public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) { return false; } /** * @return true if a ICC card is present */ public boolean hasIccCard(); public boolean hasIccCard() { return false; } /** * @return true if ICC card is PIN2 blocked */ public boolean getIccPin2Blocked(); public boolean getIccPin2Blocked() { return false; } /** * @return true if ICC card is PUK2 blocked */ public boolean getIccPuk2Blocked(); public boolean getIccPuk2Blocked() { return false; } private void sendMessageWithCardAbsentException(Message onComplete) { AsyncResult ret = AsyncResult.forMessage(onComplete); ret.exception = new RuntimeException("No valid IccCard"); onComplete.sendToTarget(); } }
src/java/com/android/internal/telephony/uicc/UiccProfile.java +93 −89 Original line number Diff line number Diff line Loading @@ -81,7 +81,7 @@ import java.util.List; * * {@hide} */ public class UiccProfile extends Handler implements IccCard { public class UiccProfile extends IccCard { protected static final String LOG_TAG = "UiccProfile"; protected static final boolean DBG = true; private static final boolean VDBG = false; //STOPSHIP if true Loading Loading @@ -136,7 +136,78 @@ public class UiccProfile extends Handler implements IccCard { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { sendMessage(obtainMessage(EVENT_CARRIER_CONFIG_CHANGED)); mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARRIER_CONFIG_CHANGED)); } } }; @VisibleForTesting public final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // We still need to handle the following response messages even the UiccProfile has been // disposed because whoever sent the request may be still waiting for the response. if (mDisposed && msg.what != EVENT_OPEN_LOGICAL_CHANNEL_DONE && msg.what != EVENT_CLOSE_LOGICAL_CHANNEL_DONE && msg.what != EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE && msg.what != EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE && msg.what != EVENT_SIM_IO_DONE) { loge("handleMessage: Received " + msg.what + " after dispose(); ignoring the message"); return; } loglocal("handleMessage: Received " + msg.what + " for phoneId " + mPhoneId); switch (msg.what) { case EVENT_NETWORK_LOCKED: mNetworkLockedRegistrants.notifyRegistrants(); // intentional fall through case EVENT_RADIO_OFF_OR_UNAVAILABLE: case EVENT_ICC_LOCKED: case EVENT_APP_READY: case EVENT_RECORDS_LOADED: case EVENT_EID_READY: if (VDBG) log("handleMessage: Received " + msg.what); updateExternalState(); 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("handleMessage: EVENT_CARRIER_PRIVILEGES_LOADED"); onCarrierPriviligesLoadedMessage(); updateExternalState(); break; case EVENT_CARRIER_CONFIG_CHANGED: handleCarrierNameOverride(); 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("handleMessage: Exception " + ar.exception); log("handleMessage: Error in SIM access with exception" + ar.exception); } AsyncResult.forMessage((Message) ar.userObj, ar.result, ar.exception); ((Message) ar.userObj).sendToTarget(); break; default: loge("handleMessage: Unhandled message with number: " + msg.what); break; } } }; Loading @@ -154,11 +225,11 @@ public class UiccProfile extends Handler implements IccCard { } if (mUiccCard instanceof EuiccCard) { ((EuiccCard) mUiccCard).registerForEidReady(this, EVENT_EID_READY, null); ((EuiccCard) mUiccCard).registerForEidReady(mHandler, EVENT_EID_READY, null); } update(c, ci, ics); ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); ci.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); resetProperties(); IntentFilter intentfilter = new IntentFilter(); Loading @@ -177,10 +248,10 @@ public class UiccProfile extends Handler implements IccCard { unregisterCurrAppEvents(); if (mUiccCard instanceof EuiccCard) { ((EuiccCard) mUiccCard).unregisterForEidReady(this); ((EuiccCard) mUiccCard).unregisterForEidReady(mHandler); } mCi.unregisterForOffOrNotAvailable(this); mCi.unregisterForOffOrNotAvailable(mHandler); mContext.unregisterReceiver(mReceiver); if (mCatService != null) mCatService.dispose(); Loading Loading @@ -221,73 +292,6 @@ public class UiccProfile extends Handler implements IccCard { } } @Override public void handleMessage(Message msg) { // We still need to handle the following response messages even the UiccProfile has been // disposed because whoever sent the request may be still waiting for the response. if (mDisposed && msg.what != EVENT_OPEN_LOGICAL_CHANNEL_DONE && msg.what != EVENT_CLOSE_LOGICAL_CHANNEL_DONE && msg.what != EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE && msg.what != EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE && msg.what != EVENT_SIM_IO_DONE) { loge("handleMessage: Received " + msg.what + " after dispose(); ignoring the message"); return; } loglocal("handleMessage: Received " + msg.what + " for phoneId " + mPhoneId); switch (msg.what) { case EVENT_NETWORK_LOCKED: mNetworkLockedRegistrants.notifyRegistrants(); // intentional fall through case EVENT_RADIO_OFF_OR_UNAVAILABLE: case EVENT_ICC_LOCKED: case EVENT_APP_READY: case EVENT_RECORDS_LOADED: case EVENT_EID_READY: if (VDBG) log("handleMessage: Received " + msg.what); updateExternalState(); 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("handleMessage: EVENT_CARRIER_PRIVILEGES_LOADED"); onCarrierPriviligesLoadedMessage(); updateExternalState(); break; case EVENT_CARRIER_CONFIG_CHANGED: handleCarrierNameOverride(); 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("handleMessage: Exception " + ar.exception); log("handleMessage: Error in SIM access with exception" + ar.exception); } AsyncResult.forMessage((Message) ar.userObj, ar.result, ar.exception); ((Message) ar.userObj).sendToTarget(); break; default: loge("handleMessage: Unhandled message with number: " + msg.what); break; } } /** * Override the carrier name with either carrier config or SPN * if an override is provided. Loading Loading @@ -505,12 +509,12 @@ public class UiccProfile extends Handler implements IccCard { for (UiccCardApplication app : mUiccApplications) { if (app != null) { if (VDBG) log("registerUiccCardEvents: registering for EVENT_APP_READY"); app.registerForReady(this, EVENT_APP_READY, null); app.registerForReady(mHandler, 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); ir.registerForRecordsLoaded(mHandler, EVENT_RECORDS_LOADED, null); ir.registerForRecordsEvents(mHandler, EVENT_ICC_RECORD_EVENTS, null); } } } Loading @@ -519,11 +523,11 @@ public class UiccProfile extends Handler implements IccCard { private void unregisterAllAppEvents() { for (UiccCardApplication app : mUiccApplications) { if (app != null) { app.unregisterForReady(this); app.unregisterForReady(mHandler); IccRecords ir = app.getIccRecords(); if (ir != null) { ir.unregisterForRecordsLoaded(this); ir.unregisterForRecordsEvents(this); ir.unregisterForRecordsLoaded(mHandler); ir.unregisterForRecordsEvents(mHandler); } } } Loading @@ -532,15 +536,15 @@ public class UiccProfile extends Handler implements IccCard { 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); mIccRecords.registerForLockedRecordsLoaded(mHandler, EVENT_ICC_LOCKED, null); mIccRecords.registerForNetworkLockedRecordsLoaded(mHandler, EVENT_NETWORK_LOCKED, null); } } private void unregisterCurrAppEvents() { if (mIccRecords != null) { mIccRecords.unregisterForLockedRecordsLoaded(this); mIccRecords.unregisterForNetworkLockedRecordsLoaded(this); mIccRecords.unregisterForLockedRecordsLoaded(mHandler); mIccRecords.unregisterForNetworkLockedRecordsLoaded(mHandler); } } Loading Loading @@ -886,7 +890,7 @@ public class UiccProfile extends Handler implements IccCard { log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + ics.mCardState); if (mCarrierPrivilegeRules == null && ics.mCardState == CardState.CARDSTATE_PRESENT) { mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this, obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED)); mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED)); } else if (mCarrierPrivilegeRules != null && ics.mCardState != CardState.CARDSTATE_PRESENT) { mCarrierPrivilegeRules = null; Loading Loading @@ -1234,7 +1238,7 @@ public class UiccProfile extends Handler implements IccCard { loglocal("iccOpenLogicalChannel: " + aid + " , " + p2 + " by pid:" + Binder.getCallingPid() + " uid:" + Binder.getCallingUid()); mCi.iccOpenLogicalChannel(aid, p2, obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response)); mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, response)); } /** Loading @@ -1243,7 +1247,7 @@ public class UiccProfile extends Handler implements IccCard { public void iccCloseLogicalChannel(int channel, Message response) { loglocal("iccCloseLogicalChannel: " + channel); mCi.iccCloseLogicalChannel(channel, obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response)); mHandler.obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response)); } /** Loading @@ -1252,7 +1256,7 @@ public class UiccProfile extends Handler implements IccCard { 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, obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); } /** Loading @@ -1261,7 +1265,7 @@ public class UiccProfile extends Handler implements IccCard { 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, obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response)); data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE, response)); } /** Loading @@ -1270,7 +1274,7 @@ public class UiccProfile extends Handler implements IccCard { 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, obtainMessage(EVENT_SIM_IO_DONE, response)); mHandler.obtainMessage(EVENT_SIM_IO_DONE, response)); } /** Loading
tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +39 −0 Original line number Diff line number Diff line Loading @@ -57,8 +57,10 @@ import android.telephony.gsm.GsmCellLocation; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccException; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.UiccProfile; import org.junit.After; import org.junit.Before; Loading @@ -79,6 +81,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { private static final int EVENT_EMERGENCY_CALLBACK_MODE_EXIT = 1; private static final int EVENT_EMERGENCY_CALL_TOGGLE = 2; private static final int EVENT_SET_ICC_LOCK_ENABLED = 3; private class GsmCdmaPhoneTestHandler extends HandlerThread { Loading Loading @@ -812,4 +815,40 @@ public class GsmCdmaPhoneTest extends TelephonyTest { waitForMs(100); verify(mEriManager, times(1)).loadEriFile(); } @Test @SmallTest public void testGetEmptyIccCard() { doReturn(null).when(mUiccController).getUiccProfileForPhone(anyInt()); IccCard iccCard = mPhoneUT.getIccCard(); // The iccCard should be a dummy object, not null. assertTrue(!(iccCard instanceof UiccProfile)); assertTrue(iccCard != null); assertEquals(IccCardConstants.State.UNKNOWN, iccCard.getState()); assertEquals(null, iccCard.getIccRecords()); assertEquals(false, iccCard.getIccLockEnabled()); assertEquals(false, iccCard.getIccFdnEnabled()); assertEquals(false, iccCard.isApplicationOnIcc( IccCardApplicationStatus.AppType.APPTYPE_SIM)); assertEquals(false, iccCard.hasIccCard()); assertEquals(false, iccCard.getIccPin2Blocked()); assertEquals(false, iccCard.getIccPuk2Blocked()); Message onComplete = mTestHandler.obtainMessage(EVENT_SET_ICC_LOCK_ENABLED); iccCard.setIccLockEnabled(true, "password", onComplete); waitForMs(100); ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); // Verify that message is sent back with exception. verify(mTestHandler, times(1)).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong()); Message message = messageArgumentCaptor.getAllValues().get(0); AsyncResult ret = (AsyncResult) message.obj; assertEquals(EVENT_SET_ICC_LOCK_ENABLED, message.what); assertTrue(ret.exception != null); } }
tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java +10 −5 Original line number Diff line number Diff line Loading @@ -286,7 +286,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(3, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); assertEquals(mUiccProfile.getState(), State.NOT_READY); } Loading Loading @@ -318,7 +319,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(3, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); // state is loaded as all records are loaded right away as SimulatedCommands returns // response for them right away. Ideally applications and records should be mocked. Loading Loading @@ -352,7 +354,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(3, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); // state is loaded as all records are loaded right away as SimulatedCommands returns // response for them right away. Ideally applications and records should be mocked. Loading @@ -376,7 +379,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(0, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); // state is loaded since there is no applications. assertEquals(State.NOT_READY, mUiccProfile.getState()); Loading @@ -402,7 +406,8 @@ public class UiccProfileTest extends TelephonyTest { waitForMs(50); assertEquals(1, mUiccProfile.getNumApplications()); mUiccProfile.sendMessage(mUiccProfile.obtainMessage(UiccProfile.EVENT_APP_READY)); mUiccProfile.mHandler.sendMessage( mUiccProfile.mHandler.obtainMessage(UiccProfile.EVENT_APP_READY)); waitForMs(SCARY_SLEEP_MS); // state is loaded since there is no applications. assertEquals(State.NOT_READY, mUiccProfile.getState()); Loading