Loading src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +64 −0 Original line number Diff line number Diff line Loading @@ -564,6 +564,11 @@ public class EmergencyStateTracker { Rlog.i(TAG, "startEmergencyCall: phoneId=" + phone.getPhoneId() + ", callId=" + c.getTelecomCallId()); if (needToSwitchPhone(phone)) { Rlog.e(TAG, "startEmergencyCall failed. need to switch stacks."); return CompletableFuture.completedFuture(DisconnectCause.EMERGENCY_PERM_FAILURE); } if (mPhone != null) { // Create new future to return as to not interfere with any uncompleted futures. // Case1) When 2nd emergency call is initiated during an active call on the same phone. Loading Loading @@ -2105,4 +2110,63 @@ public class EmergencyStateTracker { endNormalRoutingEmergencyCall(c); } } /** * Determines whether switching stacks is needed or not. * * @param phone the {@code Phone} on which to process the emergency call. * @return true if switching stacks is needed. */ @VisibleForTesting public boolean needToSwitchPhone(Phone phone) { int subId = phone.getSubId(); int phoneId = phone.getPhoneId(); if (isSimReady(phoneId, subId)) return false; boolean switchPhone = false; if (!SubscriptionManager.isValidSubscriptionId(subId)) { Rlog.i(TAG, "needToSwitchPhone SIM absent"); if (phoneId != 0 || isThereOtherPhone(phoneId, true)) { // Prefer default Phone or other Phone with a SIM regardless of lock state. switchPhone = true; } } else { Rlog.i(TAG, "needToSwitchPhone SIM not ready"); if ((phoneId == 0 && isThereOtherPhone(phoneId, false)) || (phoneId != 0 && isThereOtherPhone(phoneId, true))) { // If there is another one with a SIM ready, switch Phones. // Otherwise, prefer default Phone if both SIMs are locked. switchPhone = true; } } Rlog.i(TAG, "needToSwitchPhone " + switchPhone); return switchPhone; } private boolean isThereOtherPhone(int skipPhoneId, boolean ignoreLockState) { for (Phone phone : mPhoneFactoryProxy.getPhones()) { int phoneId = phone.getPhoneId(); if (phoneId == skipPhoneId) { continue; } int subId = phone.getSubId(); if (!SubscriptionManager.isValidSubscriptionId(subId)) { Rlog.i(TAG, "isThereOtherPhone phoneId=" + phoneId + ", subId=" + subId); continue; } int simState = mTelephonyManagerProxy.getSimState(phoneId); if ((simState == TelephonyManager.SIM_STATE_READY) || (ignoreLockState && simState != TelephonyManager.SIM_STATE_ABSENT && simState != TelephonyManager.SIM_STATE_NOT_READY)) { Rlog.i(TAG, "isThereOtherPhone found, ignoreLockState=" + ignoreLockState + ", phoneId=" + phoneId + ", simState=" + simState); return true; } Rlog.i(TAG, "isThereOtherPhone phoneId=" + phoneId + ", simState=" + simState); } return false; } } tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +201 −0 Original line number Diff line number Diff line Loading @@ -3171,6 +3171,207 @@ public class EmergencyStateTrackerTest extends TelephonyTest { anyBoolean(), eq(0)); } /** * Test Phone selection. * SIM absent and SIM ready on the other Phone. */ @Test @SmallTest public void testSwitchPhoneAbsentAndReady() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) .when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_ABSENT) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_READY) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone0, mTestConnection1, true); processAllMessages(); assertTrue(future.isDone()); // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE)); verify(phone0, never()).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * PIN locked and SIM ready on the other Phone. */ @Test @SmallTest public void testSwitchPhonePinLockedAndReady() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(1).when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_READY) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone0, mTestConnection1, true); processAllMessages(); assertTrue(future.isDone()); // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE)); verify(phone0, never()).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * SIM ready and SIM ready on the other Phone. */ @Test @SmallTest public void testSwitchPhoneReadyAndReady() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(1).when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_READY) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_READY) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone0, mTestConnection1, true); processAllMessages(); assertFalse(future.isDone()); verify(phone0).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * PIN locked and PIN locked on the other Phone. */ @Test @SmallTest public void testSwitchPhonePinLockedAndPinLocked() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(1).when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone0, mTestConnection1, true); processAllMessages(); assertFalse(future.isDone()); verify(phone0).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * SIM absent and SIM absent on default Phone. */ @Test @SmallTest public void testSwitchPhoneAbsentAndAbsentOnDefaultPhone() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) .when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_ABSENT) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) .when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_ABSENT) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone1, mTestConnection1, true); processAllMessages(); assertTrue(future.isDone()); // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE)); verify(phone1, never()).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * PIN locked and PIN locked on default Phone. */ @Test @SmallTest public void testSwitchPhonePinLockedandPinLockedOnDefaultPhone() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(1).when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone1, mTestConnection1, true); processAllMessages(); assertTrue(future.isDone()); // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE)); verify(phone1, never()).setEmergencyMode(anyInt(), any(Message.class)); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); Loading Loading
src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +64 −0 Original line number Diff line number Diff line Loading @@ -564,6 +564,11 @@ public class EmergencyStateTracker { Rlog.i(TAG, "startEmergencyCall: phoneId=" + phone.getPhoneId() + ", callId=" + c.getTelecomCallId()); if (needToSwitchPhone(phone)) { Rlog.e(TAG, "startEmergencyCall failed. need to switch stacks."); return CompletableFuture.completedFuture(DisconnectCause.EMERGENCY_PERM_FAILURE); } if (mPhone != null) { // Create new future to return as to not interfere with any uncompleted futures. // Case1) When 2nd emergency call is initiated during an active call on the same phone. Loading Loading @@ -2105,4 +2110,63 @@ public class EmergencyStateTracker { endNormalRoutingEmergencyCall(c); } } /** * Determines whether switching stacks is needed or not. * * @param phone the {@code Phone} on which to process the emergency call. * @return true if switching stacks is needed. */ @VisibleForTesting public boolean needToSwitchPhone(Phone phone) { int subId = phone.getSubId(); int phoneId = phone.getPhoneId(); if (isSimReady(phoneId, subId)) return false; boolean switchPhone = false; if (!SubscriptionManager.isValidSubscriptionId(subId)) { Rlog.i(TAG, "needToSwitchPhone SIM absent"); if (phoneId != 0 || isThereOtherPhone(phoneId, true)) { // Prefer default Phone or other Phone with a SIM regardless of lock state. switchPhone = true; } } else { Rlog.i(TAG, "needToSwitchPhone SIM not ready"); if ((phoneId == 0 && isThereOtherPhone(phoneId, false)) || (phoneId != 0 && isThereOtherPhone(phoneId, true))) { // If there is another one with a SIM ready, switch Phones. // Otherwise, prefer default Phone if both SIMs are locked. switchPhone = true; } } Rlog.i(TAG, "needToSwitchPhone " + switchPhone); return switchPhone; } private boolean isThereOtherPhone(int skipPhoneId, boolean ignoreLockState) { for (Phone phone : mPhoneFactoryProxy.getPhones()) { int phoneId = phone.getPhoneId(); if (phoneId == skipPhoneId) { continue; } int subId = phone.getSubId(); if (!SubscriptionManager.isValidSubscriptionId(subId)) { Rlog.i(TAG, "isThereOtherPhone phoneId=" + phoneId + ", subId=" + subId); continue; } int simState = mTelephonyManagerProxy.getSimState(phoneId); if ((simState == TelephonyManager.SIM_STATE_READY) || (ignoreLockState && simState != TelephonyManager.SIM_STATE_ABSENT && simState != TelephonyManager.SIM_STATE_NOT_READY)) { Rlog.i(TAG, "isThereOtherPhone found, ignoreLockState=" + ignoreLockState + ", phoneId=" + phoneId + ", simState=" + simState); return true; } Rlog.i(TAG, "isThereOtherPhone phoneId=" + phoneId + ", simState=" + simState); } return false; } }
tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +201 −0 Original line number Diff line number Diff line Loading @@ -3171,6 +3171,207 @@ public class EmergencyStateTrackerTest extends TelephonyTest { anyBoolean(), eq(0)); } /** * Test Phone selection. * SIM absent and SIM ready on the other Phone. */ @Test @SmallTest public void testSwitchPhoneAbsentAndReady() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) .when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_ABSENT) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_READY) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone0, mTestConnection1, true); processAllMessages(); assertTrue(future.isDone()); // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE)); verify(phone0, never()).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * PIN locked and SIM ready on the other Phone. */ @Test @SmallTest public void testSwitchPhonePinLockedAndReady() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(1).when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_READY) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone0, mTestConnection1, true); processAllMessages(); assertTrue(future.isDone()); // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE)); verify(phone0, never()).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * SIM ready and SIM ready on the other Phone. */ @Test @SmallTest public void testSwitchPhoneReadyAndReady() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(1).when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_READY) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_READY) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone0, mTestConnection1, true); processAllMessages(); assertFalse(future.isDone()); verify(phone0).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * PIN locked and PIN locked on the other Phone. */ @Test @SmallTest public void testSwitchPhonePinLockedAndPinLocked() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(1).when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone0, mTestConnection1, true); processAllMessages(); assertFalse(future.isDone()); verify(phone0).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * SIM absent and SIM absent on default Phone. */ @Test @SmallTest public void testSwitchPhoneAbsentAndAbsentOnDefaultPhone() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) .when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_ABSENT) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) .when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_ABSENT) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone1, mTestConnection1, true); processAllMessages(); assertTrue(future.isDone()); // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE)); verify(phone1, never()).setEmergencyMode(anyInt(), any(Message.class)); } /** * Test Phone selection. * PIN locked and PIN locked on default Phone. */ @Test @SmallTest public void testSwitchPhonePinLockedandPinLockedOnDefaultPhone() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); Phone phone1 = getPhone(1); // Phone0 doReturn(1).when(phone0).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(0)); // Phone1 doReturn(2).when(phone1).getSubId(); doReturn(TelephonyManager.SIM_STATE_PIN_REQUIRED) .when(mTelephonyManagerProxy).getSimState(eq(1)); CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall( phone1, mTestConnection1, true); processAllMessages(); assertTrue(future.isDone()); // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE)); verify(phone1, never()).setEmergencyMode(anyInt(), any(Message.class)); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); Loading