Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d59af15d authored by David Lin's avatar David Lin Committed by Android (Google) Code Review
Browse files

Merge "Switch phones if PUK locked in DSDS configuration" into 24D1-dev

parents 408c543f 026ad2e3
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -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.
@@ -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;
    }
}
+201 −0
Original line number Diff line number Diff line
@@ -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();