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

Commit 5b81bc38 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Merge cherrypicks of ['googleplex-android-review.googlesource.com/27833182'] into 24Q3-release.

Change-Id: I474b6ecc7dcb7dd075baf80d39982398c95e14d8
parents a8c1f495 130cc554
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();