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

Commit a098ad4b authored by Hwangoo Park's avatar Hwangoo Park Committed by Android (Google) Code Review
Browse files

Merge "Add cross stack redialing during emergency call" into main

parents 32ab53f9 e2174101
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -71,3 +71,14 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

# OWNER=hwangoo TARGET=25Q2
flag {
    name: "perform_cross_stack_redial_check_for_emergency_call"
    namespace: "telephony"
    description: "This flag performs a quick cross stack redial if the subscription is being invalid and an exception occurs, while an emergency call is in progress."
    bug:"389190613"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+26 −8
Original line number Diff line number Diff line
@@ -312,8 +312,24 @@ public class EmergencyStateTracker {
                    maybeNotifyTransportChangeCompleted(emergencyType, false);

                    if (emergencyType == EMERGENCY_TYPE_CALL) {
                        // If the emergency registration result(mLastEmergencyRegistrationResult) is
                        // null, it means that the emergency mode is not set properly on the modem.
                        // Therefore, based on the emergency registration result and current
                        // subscription status, the current phone is not available for an emergency
                        // call, so we check if an emergency call is possible through cross stack.
                        if (mFeatureFlags.performCrossStackRedialCheckForEmergencyCall()
                                && mLastEmergencyRegistrationResult == null
                                && mPhone != null
                                && !SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())
                                && needToSwitchPhone(mPhone)) {
                            Rlog.i(TAG, "setEmergencyMode failed: need to switch stacks.");
                            mEmergencyMode = MODE_EMERGENCY_NONE;
                            completeEmergencyMode(emergencyType,
                                    DisconnectCause.EMERGENCY_PERM_FAILURE);
                        } else {
                            setIsInEmergencyCall(true);
                            completeEmergencyMode(emergencyType);
                        }

                        // Case 1) When the emergency call is setting the emergency mode and
                        // the emergency SMS is being sent, completes the SMS future also.
@@ -861,23 +877,25 @@ public class EmergencyStateTracker {

    private void completeEmergencyMode(@EmergencyType int emergencyType,
            @DisconnectCauses int result) {
        CompletableFuture<Integer> emergencyModeFuture = null;

        if (emergencyType == EMERGENCY_TYPE_CALL) {
            if (mCallEmergencyModeFuture != null && !mCallEmergencyModeFuture.isDone()) {
                mCallEmergencyModeFuture.complete(result);
            }
            emergencyModeFuture = mCallEmergencyModeFuture;

            if (result != DisconnectCause.NOT_DISCONNECTED) {
                clearEmergencyCallInfo();
            }
        } else if (emergencyType == EMERGENCY_TYPE_SMS) {
            if (mSmsEmergencyModeFuture != null && !mSmsEmergencyModeFuture.isDone()) {
                mSmsEmergencyModeFuture.complete(result);
            }
            emergencyModeFuture = mSmsEmergencyModeFuture;

            if (result != DisconnectCause.NOT_DISCONNECTED) {
                clearEmergencySmsInfo();
            }
        }

        if (emergencyModeFuture != null && !emergencyModeFuture.isDone()) {
            emergencyModeFuture.complete(result);
        }
    }

    /**
+89 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS_PS;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
import static android.telephony.TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL;
import static android.telephony.TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS;

@@ -74,10 +75,12 @@ import androidx.test.filters.SmallTest;

import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.GsmCdmaPhone;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.data.PhoneSwitcher;
@@ -107,6 +110,12 @@ public class EmergencyStateTrackerTest extends TelephonyTest {
    private static final int TEST_WAIT_FOR_IN_SERVICE_TIMEOUT_MS = 3000;
    private static final EmergencyRegistrationResult E_REG_RESULT = new EmergencyRegistrationResult(
            EUTRAN, REGISTRATION_STATE_HOME, DOMAIN_CS_PS, true, true, 0, 1, "001", "01", "US");
    private static final EmergencyRegistrationResult UNKNOWN_E_REG_RESULT =
            new EmergencyRegistrationResult(
                    AccessNetworkConstants.AccessNetworkType.UNKNOWN,
                    REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING,
                    NetworkRegistrationInfo.DOMAIN_UNKNOWN,
                    false, false, 0, 0, "", "", "");

    @Mock EmergencyStateTracker.PhoneFactoryProxy mPhoneFactoryProxy;
    @Mock EmergencyStateTracker.PhoneSwitcherProxy mPhoneSwitcherProxy;
@@ -125,6 +134,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest {
                .when(mTelephonyManagerProxy).getSimState(anyInt());
        doReturn(true).when(mFeatureFlags).emergencyCallbackModeNotification();
        doReturn(true).when(mFeatureFlags).disableEcbmBasedOnRat();
        doReturn(true).when(mFeatureFlags).performCrossStackRedialCheckForEmergencyCall();
    }

    @After
@@ -3491,6 +3501,74 @@ public class EmergencyStateTrackerTest extends TelephonyTest {
        verify(phone1, never()).setEmergencyMode(anyInt(), any(Message.class));
    }

    @Test
    @SmallTest
    public void testSwitchPhoneWhenNonEmergencyNtnSessionInProgress() {
        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
                /* isRadioOn= */ true);
        setUpAsyncResultForSetEmergencyMode(
                phone0, UNKNOWN_E_REG_RESULT, RILConstants.INTERNAL_ERR);
        // Start an emergency call over Phone0
        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(phone0,
                mTestConnection1, false);

        Phone phone1 = getPhone(1);
        // Phone0: Disable NTN
        doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
                .when(phone0).getSubId();
        doReturn(TelephonyManager.SIM_STATE_ABSENT)
                .when(mTelephonyManagerProxy).getSimState(eq(0));
        // Phone1: Enable TN
        doReturn(2).when(phone1).getSubId();
        doReturn(TelephonyManager.SIM_STATE_READY)
                .when(mTelephonyManagerProxy).getSimState(eq(1));

        processAllMessages();

        verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
        assertFalse(emergencyStateTracker.isInEmergencyMode());
        assertTrue(future.isDone());
        // Expect: DisconnectCause#EMERGENCY_PERM_FAILURE
        assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED),
                Integer.valueOf(DisconnectCause.EMERGENCY_PERM_FAILURE));
    }

    @Test
    @SmallTest
    public void testSwitchPhoneWhenNonEmergencyNtnSessionInProgressAndFlagDisabled() {
        doReturn(false).when(mFeatureFlags).performCrossStackRedialCheckForEmergencyCall();
        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
                /* isRadioOn= */ true);
        setUpAsyncResultForSetEmergencyMode(
                phone0, UNKNOWN_E_REG_RESULT, RILConstants.INTERNAL_ERR);
        // Start an emergency call over Phone0
        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(phone0,
                mTestConnection1, false);

        Phone phone1 = getPhone(1);
        // Phone0: Disable NTN
        doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
                .when(phone0).getSubId();
        doReturn(TelephonyManager.SIM_STATE_ABSENT)
                .when(mTelephonyManagerProxy).getSimState(eq(0));
        // Phone1: Enable TN
        doReturn(2).when(phone1).getSubId();
        doReturn(TelephonyManager.SIM_STATE_READY)
                .when(mTelephonyManagerProxy).getSimState(eq(1));

        processAllMessages();

        verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
        assertTrue(future.isDone());
        // Expect: DisconnectCause#NOT_DISCONNECTED
        assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED),
                Integer.valueOf(DisconnectCause.NOT_DISCONNECTED));
    }

    private EmergencyStateTracker setupEmergencyStateTracker(
            boolean isSuplDdsSwitchRequiredForEmergencyCall) {
        doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
@@ -3571,6 +3649,17 @@ public class EmergencyStateTrackerTest extends TelephonyTest {
        }).when(phone).setEmergencyMode(anyInt(), any(Message.class));
    }

    private void setUpAsyncResultForSetEmergencyMode(Phone phone,
            EmergencyRegistrationResult regResult, int rilError) {
        doAnswer((invocation) -> {
            Object[] args = invocation.getArguments();
            final Message msg = (Message) args[1];
            AsyncResult.forMessage(msg, regResult, CommandException.fromRilErrno(rilError));
            msg.sendToTarget();
            return null;
        }).when(phone).setEmergencyMode(anyInt(), any(Message.class));
    }

    private void setUpAsyncResultForExitEmergencyMode(Phone phone) {
        doAnswer((invocation) -> {
            Object[] args = invocation.getArguments();