Loading src/java/com/android/internal/telephony/GsmCdmaPhone.java +46 −2 Original line number Diff line number Diff line Loading @@ -154,7 +154,7 @@ public class GsmCdmaPhone extends Phone { private String mMeid; // string to define how the carrier specifies its own ota sp number private String mCarrierOtaSpNumSchema; private boolean mUiccApplicationsEnabled = true; private Boolean mUiccApplicationsEnabled = null; // A runnable which is used to automatically exit from Ecm after a period of time. private Runnable mExitEcmRunnable = new Runnable() { Loading Loading @@ -2859,9 +2859,26 @@ public class GsmCdmaPhone extends Phone { return; } mUiccApplicationsEnabled = (boolean) ar.result; mUiccApplicationsEnabled = (Boolean) ar.result; reapplyUiccAppsEnablementIfNeeded(); break; } case EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE: { ar = (AsyncResult) msg.obj; if (ar == null || ar.exception == null) return; // TODO: b/146181737 don't throw exception and uncomment the retry below. boolean expectedValue = (boolean) ar.userObj; CommandException.Error error = ((CommandException) ar.exception).getCommandError(); throw new RuntimeException("Error received when re-applying uicc application" + " setting to " + expectedValue + " on phone " + mPhoneId + " Error code: " + error); // if (error == INTERNAL_ERR || error == SIM_BUSY) { // // Retry for certain errors, but not for others like RADIO_NOT_AVAILABLE or // // SIM_ABSENT, as they will trigger it whey they become available. // postDelayed(()->reapplyUiccAppsEnablementIfNeeded(), 1000); // } // break; } default: super.handleMessage(msg); } Loading Loading @@ -2959,6 +2976,8 @@ public class GsmCdmaPhone extends Phone { updateDataConnectionTracker(); } } reapplyUiccAppsEnablementIfNeeded(); } private void processIccRecordEvents(int eventCode) { Loading Loading @@ -4061,6 +4080,31 @@ public class GsmCdmaPhone extends Phone { updateUiTtyMode(ttyMode); } private void reapplyUiccAppsEnablementIfNeeded() { UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId); // If no card is present or we don't have mUiccApplicationsEnabled yet, do nothing. if (slot == null || slot.getCardState() != IccCardStatus.CardState.CARDSTATE_PRESENT || mUiccApplicationsEnabled == null) { return; } String iccId = slot.getIccId(); if (iccId == null) return; SubscriptionInfo info = SubscriptionController.getInstance().getSubInfoForIccId(iccId); // If info is null, it could be a new subscription. By default we enable it. boolean expectedValue = info == null ? true : info.areUiccApplicationsEnabled(); // If for any reason current state is different from configured state, re-apply the // configured state. if (expectedValue != mUiccApplicationsEnabled) { mCi.enableUiccApplications(expectedValue, Message.obtain( this, EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE, expectedValue)); } } // Enable or disable uicc applications. @Override public void enableUiccApplications(boolean enable, Message onCompleteMessage) { Loading src/java/com/android/internal/telephony/Phone.java +4 −1 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import com.android.ims.ImsCall; import com.android.ims.ImsConfig; import com.android.ims.ImsManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.dataconnection.DataConnectionReasons; import com.android.internal.telephony.dataconnection.DataEnabledSettings; import com.android.internal.telephony.dataconnection.DcTracker; Loading Loading @@ -169,7 +170,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // other protected static final int EVENT_SET_NETWORK_AUTOMATIC = 28; protected static final int EVENT_ICC_RECORD_EVENTS = 29; private static final int EVENT_ICC_CHANGED = 30; @VisibleForTesting protected static final int EVENT_ICC_CHANGED = 30; // Single Radio Voice Call Continuity private static final int EVENT_SRVCC_STATE_CHANGED = 31; private static final int EVENT_INITIATE_SILENT_REDIAL = 32; Loading Loading @@ -198,6 +200,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private static final int EVENT_ALL_DATA_DISCONNECTED = 52; protected static final int EVENT_UICC_APPS_ENABLEMENT_CHANGED = 53; protected static final int EVENT_GET_UICC_APPS_ENABLEMENT_DONE = 54; protected static final int EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE = 55; protected static final int EVENT_LAST = EVENT_ALL_DATA_DISCONNECTED; Loading tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +98 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.internal.telephony; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_CHANGED; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static org.junit.Assert.assertEquals; Loading Loading @@ -1224,4 +1226,100 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.enableUiccApplications(true, message); verify(mMockCi).enableUiccApplications(eq(true), eq(message)); } @Test @SmallTest public void testReapplyUiccApplicationEnablementNotNeeded() throws Exception { mPhoneUT.mCi = mMockCi; // UiccSlot is null, or not present, or mUiccApplicationsEnabled is not available, or IccId // is not available, Doing nothing. doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt()); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); processAllMessages(); doReturn(IccCardStatus.CardState.CARDSTATE_ABSENT).when(mUiccSlot).getCardState(); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); processAllMessages(); doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState(); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED, new AsyncResult(null, true, null)).sendToTarget(); processAllMessages(); verify(mSubscriptionController, never()).getSubInfoForIccId(any()); // Have IccId defined. But expected value and current value are the same. So no RIL command // should be sent. String iccId = "Fake iccId"; doReturn(iccId).when(mUiccSlot).getIccId(); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); processAllMessages(); verify(mSubscriptionController).getSubInfoForIccId(iccId); verify(mMockCi, never()).enableUiccApplications(anyBoolean(), any()); } @Test @SmallTest public void testReapplyUiccApplicationEnablementSuccess() throws Exception { mPhoneUT.mCi = mMockCi; // Set SIM to be present, with a fake iccId, and notify enablement being false. doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt()); doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState(); String iccId = "Fake iccId"; doReturn(iccId).when(mUiccSlot).getIccId(); Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED, new AsyncResult(null, false, null)).sendToTarget(); processAllMessages(); // Should try to enable uicc applications as by default hey are expected to be true. ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mMockCi, times(1)).enableUiccApplications(eq(true), messageCaptor.capture()); // Send message back with no exception. AsyncResult.forMessage(messageCaptor.getValue(), null, null); messageCaptor.getValue().sendToTarget(); processAllMessages(); // There shouldn't be any retry message. moveTimeForward(5000); processAllMessages(); verify(mMockCi, times(1)).enableUiccApplications(eq(true), any()); } // TODO: b/146181737 uncomment below test. // @Test // @SmallTest // public void testReapplyUiccApplicationEnablementRetry() throws Exception { // mPhoneUT.mCi = mMockCi; // // Set SIM to be present, with a fake iccId, and notify enablement being false. // doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt()); // doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState(); // String iccId = "Fake iccId"; // doReturn(iccId).when(mUiccSlot).getIccId(); // Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED, // new AsyncResult(null, false, null)).sendToTarget(); // processAllMessages(); // // // Should try to enable uicc applications as by default hey are expected to be true. // ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); // verify(mMockCi).enableUiccApplications(eq(true), messageCaptor.capture()); // clearInvocations(mMockCi); // // Send message back with SIM_BUSY exception. Should retry. // AsyncResult.forMessage(messageCaptor.getValue(), null, new CommandException( // CommandException.Error.SIM_BUSY)); // messageCaptor.getValue().sendToTarget(); // processAllMessages(); // // There should be a retry message. // moveTimeForward(5000); // processAllMessages(); // verify(mMockCi).enableUiccApplications(eq(true), messageCaptor.capture()); // clearInvocations(mMockCi); // // // Send message back with NOT_SUPPORTED exception. Should retry. // AsyncResult.forMessage(messageCaptor.getValue(), null, new CommandException( // CommandException.Error.REQUEST_NOT_SUPPORTED)); // messageCaptor.getValue().sendToTarget(); // processAllMessages(); // // There should not be a retry message. // moveTimeForward(5000); // processAllMessages(); // verify(mMockCi, never()).enableUiccApplications(eq(true), messageCaptor.capture()); // } } Loading
src/java/com/android/internal/telephony/GsmCdmaPhone.java +46 −2 Original line number Diff line number Diff line Loading @@ -154,7 +154,7 @@ public class GsmCdmaPhone extends Phone { private String mMeid; // string to define how the carrier specifies its own ota sp number private String mCarrierOtaSpNumSchema; private boolean mUiccApplicationsEnabled = true; private Boolean mUiccApplicationsEnabled = null; // A runnable which is used to automatically exit from Ecm after a period of time. private Runnable mExitEcmRunnable = new Runnable() { Loading Loading @@ -2859,9 +2859,26 @@ public class GsmCdmaPhone extends Phone { return; } mUiccApplicationsEnabled = (boolean) ar.result; mUiccApplicationsEnabled = (Boolean) ar.result; reapplyUiccAppsEnablementIfNeeded(); break; } case EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE: { ar = (AsyncResult) msg.obj; if (ar == null || ar.exception == null) return; // TODO: b/146181737 don't throw exception and uncomment the retry below. boolean expectedValue = (boolean) ar.userObj; CommandException.Error error = ((CommandException) ar.exception).getCommandError(); throw new RuntimeException("Error received when re-applying uicc application" + " setting to " + expectedValue + " on phone " + mPhoneId + " Error code: " + error); // if (error == INTERNAL_ERR || error == SIM_BUSY) { // // Retry for certain errors, but not for others like RADIO_NOT_AVAILABLE or // // SIM_ABSENT, as they will trigger it whey they become available. // postDelayed(()->reapplyUiccAppsEnablementIfNeeded(), 1000); // } // break; } default: super.handleMessage(msg); } Loading Loading @@ -2959,6 +2976,8 @@ public class GsmCdmaPhone extends Phone { updateDataConnectionTracker(); } } reapplyUiccAppsEnablementIfNeeded(); } private void processIccRecordEvents(int eventCode) { Loading Loading @@ -4061,6 +4080,31 @@ public class GsmCdmaPhone extends Phone { updateUiTtyMode(ttyMode); } private void reapplyUiccAppsEnablementIfNeeded() { UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId); // If no card is present or we don't have mUiccApplicationsEnabled yet, do nothing. if (slot == null || slot.getCardState() != IccCardStatus.CardState.CARDSTATE_PRESENT || mUiccApplicationsEnabled == null) { return; } String iccId = slot.getIccId(); if (iccId == null) return; SubscriptionInfo info = SubscriptionController.getInstance().getSubInfoForIccId(iccId); // If info is null, it could be a new subscription. By default we enable it. boolean expectedValue = info == null ? true : info.areUiccApplicationsEnabled(); // If for any reason current state is different from configured state, re-apply the // configured state. if (expectedValue != mUiccApplicationsEnabled) { mCi.enableUiccApplications(expectedValue, Message.obtain( this, EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE, expectedValue)); } } // Enable or disable uicc applications. @Override public void enableUiccApplications(boolean enable, Message onCompleteMessage) { Loading
src/java/com/android/internal/telephony/Phone.java +4 −1 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import com.android.ims.ImsCall; import com.android.ims.ImsConfig; import com.android.ims.ImsManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.dataconnection.DataConnectionReasons; import com.android.internal.telephony.dataconnection.DataEnabledSettings; import com.android.internal.telephony.dataconnection.DcTracker; Loading Loading @@ -169,7 +170,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // other protected static final int EVENT_SET_NETWORK_AUTOMATIC = 28; protected static final int EVENT_ICC_RECORD_EVENTS = 29; private static final int EVENT_ICC_CHANGED = 30; @VisibleForTesting protected static final int EVENT_ICC_CHANGED = 30; // Single Radio Voice Call Continuity private static final int EVENT_SRVCC_STATE_CHANGED = 31; private static final int EVENT_INITIATE_SILENT_REDIAL = 32; Loading Loading @@ -198,6 +200,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private static final int EVENT_ALL_DATA_DISCONNECTED = 52; protected static final int EVENT_UICC_APPS_ENABLEMENT_CHANGED = 53; protected static final int EVENT_GET_UICC_APPS_ENABLEMENT_DONE = 54; protected static final int EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE = 55; protected static final int EVENT_LAST = EVENT_ALL_DATA_DISCONNECTED; Loading
tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +98 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.internal.telephony; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_CHANGED; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static org.junit.Assert.assertEquals; Loading Loading @@ -1224,4 +1226,100 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.enableUiccApplications(true, message); verify(mMockCi).enableUiccApplications(eq(true), eq(message)); } @Test @SmallTest public void testReapplyUiccApplicationEnablementNotNeeded() throws Exception { mPhoneUT.mCi = mMockCi; // UiccSlot is null, or not present, or mUiccApplicationsEnabled is not available, or IccId // is not available, Doing nothing. doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt()); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); processAllMessages(); doReturn(IccCardStatus.CardState.CARDSTATE_ABSENT).when(mUiccSlot).getCardState(); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); processAllMessages(); doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState(); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED, new AsyncResult(null, true, null)).sendToTarget(); processAllMessages(); verify(mSubscriptionController, never()).getSubInfoForIccId(any()); // Have IccId defined. But expected value and current value are the same. So no RIL command // should be sent. String iccId = "Fake iccId"; doReturn(iccId).when(mUiccSlot).getIccId(); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); processAllMessages(); verify(mSubscriptionController).getSubInfoForIccId(iccId); verify(mMockCi, never()).enableUiccApplications(anyBoolean(), any()); } @Test @SmallTest public void testReapplyUiccApplicationEnablementSuccess() throws Exception { mPhoneUT.mCi = mMockCi; // Set SIM to be present, with a fake iccId, and notify enablement being false. doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt()); doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState(); String iccId = "Fake iccId"; doReturn(iccId).when(mUiccSlot).getIccId(); Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED, new AsyncResult(null, false, null)).sendToTarget(); processAllMessages(); // Should try to enable uicc applications as by default hey are expected to be true. ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mMockCi, times(1)).enableUiccApplications(eq(true), messageCaptor.capture()); // Send message back with no exception. AsyncResult.forMessage(messageCaptor.getValue(), null, null); messageCaptor.getValue().sendToTarget(); processAllMessages(); // There shouldn't be any retry message. moveTimeForward(5000); processAllMessages(); verify(mMockCi, times(1)).enableUiccApplications(eq(true), any()); } // TODO: b/146181737 uncomment below test. // @Test // @SmallTest // public void testReapplyUiccApplicationEnablementRetry() throws Exception { // mPhoneUT.mCi = mMockCi; // // Set SIM to be present, with a fake iccId, and notify enablement being false. // doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt()); // doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState(); // String iccId = "Fake iccId"; // doReturn(iccId).when(mUiccSlot).getIccId(); // Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_CHANGED, // new AsyncResult(null, false, null)).sendToTarget(); // processAllMessages(); // // // Should try to enable uicc applications as by default hey are expected to be true. // ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); // verify(mMockCi).enableUiccApplications(eq(true), messageCaptor.capture()); // clearInvocations(mMockCi); // // Send message back with SIM_BUSY exception. Should retry. // AsyncResult.forMessage(messageCaptor.getValue(), null, new CommandException( // CommandException.Error.SIM_BUSY)); // messageCaptor.getValue().sendToTarget(); // processAllMessages(); // // There should be a retry message. // moveTimeForward(5000); // processAllMessages(); // verify(mMockCi).enableUiccApplications(eq(true), messageCaptor.capture()); // clearInvocations(mMockCi); // // // Send message back with NOT_SUPPORTED exception. Should retry. // AsyncResult.forMessage(messageCaptor.getValue(), null, new CommandException( // CommandException.Error.REQUEST_NOT_SUPPORTED)); // messageCaptor.getValue().sendToTarget(); // processAllMessages(); // // There should not be a retry message. // moveTimeForward(5000); // processAllMessages(); // verify(mMockCi, never()).enableUiccApplications(eq(true), messageCaptor.capture()); // } }