Merge "Fix for NPE when subscription is not found" into main
diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
index 26d4e1b..14bd273 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
@@ -509,7 +509,8 @@
                         obtainCompleteMessage());
                     }
                 };
-                EmergencyStateTracker.getInstance().exitEmergencyCallbackMode(onComplete);
+                EmergencyStateTracker.getInstance().exitEmergencyCallbackMode(onComplete,
+                        TelephonyManager.STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED);
             } else {
                 mPhone.exitEmergencyCallbackMode();
                 mPhone.setOnEcbModeExitResponse(this, EVENT_EXIT_ECM_RESPONSE_CDMA, null);
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index 53a3fe8..e5ea0c0 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -20,6 +20,12 @@
 import static android.telecom.Connection.STATE_DISCONNECTED;
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL;
 import static android.telephony.CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL;
+import static android.telephony.TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL;
+import static android.telephony.TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS;
+import static android.telephony.TelephonyManager.STOP_REASON_EMERGENCY_SMS_SENT;
+import static android.telephony.TelephonyManager.STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED;
+import static android.telephony.TelephonyManager.STOP_REASON_TIMER_EXPIRED;
+import static android.telephony.TelephonyManager.STOP_REASON_UNKNOWN;
 
 import static com.android.internal.telephony.TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED;
 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK;
@@ -65,6 +71,7 @@
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.data.PhoneSwitcher;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
 import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.telephony.Rlog;
@@ -148,7 +155,8 @@
     /** For emergency calls */
     private final long mEcmExitTimeoutMs;
     // A runnable which is used to automatically exit from Ecm after a period of time.
-    private final Runnable mExitEcmRunnable = this::exitEmergencyCallbackMode;
+    private final Runnable mExitEcmRunnable = () -> exitEmergencyCallbackMode(
+            STOP_REASON_TIMER_EXPIRED);
     // Tracks emergency calls by callId that have reached {@link Call.State#ACTIVE}.
     private final Set<android.telecom.Connection> mActiveEmergencyCalls = new ArraySet<>();
     private Phone mPhone;
@@ -184,6 +192,8 @@
     private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener =
             (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigurationChanged(
                     slotIndex, subId);
+    /** Feature flags */
+    private final FeatureFlags mFeatureFlags;
 
     /**
      * Listens for Emergency Callback Mode state change intents
@@ -326,12 +336,14 @@
                                     if (!isSamePhone(mPhone, mSmsPhone)) {
                                         completeEmergencyMode(emergencyType,
                                                 DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED);
-                                        exitEmergencySmsCallbackMode();
+                                        exitEmergencySmsCallbackMode(
+                                                STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED);
                                     }
                                 } else {
                                     completeEmergencyMode(emergencyType);
                                     mIsEmergencyCallStartedDuringEmergencySms = false;
-                                    exitEmergencySmsCallbackMode();
+                                    exitEmergencySmsCallbackMode(
+                                            STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED);
                                     turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL,
                                             mIsTestEmergencyNumber);
                                 }
@@ -343,7 +355,8 @@
 
                             if (mIsEmergencyCallStartedDuringEmergencySms) {
                                 mIsEmergencyCallStartedDuringEmergencySms = false;
-                                exitEmergencySmsCallbackMode();
+                                exitEmergencySmsCallbackMode(
+                                        STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED);
                                 turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL,
                                         mIsTestEmergencyNumber);
                             }
@@ -409,7 +422,8 @@
                         // the emergency call was started, needs to exit the emergency mode first.
                         if (mIsEmergencyCallStartedDuringEmergencySms) {
                             final Phone smsPhone = mSmsPhone;
-                            exitEmergencySmsCallbackMode();
+                            exitEmergencySmsCallbackMode(
+                                    STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED);
 
                             if (mPhone != null && smsPhone != null
                                     && !isSamePhone(mPhone, smsPhone)) {
@@ -428,7 +442,7 @@
                     break;
                 }
                 case MSG_EXIT_SCBM: {
-                    exitEmergencySmsCallbackModeAndEmergencyMode();
+                    exitEmergencySmsCallbackModeAndEmergencyMode(STOP_REASON_TIMER_EXPIRED);
                     break;
                 }
                 case MSG_NEW_RINGING_CONNECTION: {
@@ -457,11 +471,13 @@
      * @param context                                 The context of the application.
      * @param isSuplDdsSwitchRequiredForEmergencyCall Whether gnss supl requires default data for
      *                                                emergency call.
+     * @param featureFlags                            The telephony feature flags.
      */
-    public static void make(Context context, boolean isSuplDdsSwitchRequiredForEmergencyCall) {
+    public static void make(Context context, boolean isSuplDdsSwitchRequiredForEmergencyCall,
+            @NonNull FeatureFlags featureFlags) {
         if (INSTANCE == null) {
             INSTANCE = new EmergencyStateTracker(context, Looper.myLooper(),
-                    isSuplDdsSwitchRequiredForEmergencyCall);
+                    isSuplDdsSwitchRequiredForEmergencyCall, featureFlags);
         }
     }
 
@@ -481,12 +497,12 @@
      * Initializes EmergencyStateTracker.
      */
     private EmergencyStateTracker(Context context, Looper looper,
-            boolean isSuplDdsSwitchRequiredForEmergencyCall) {
+            boolean isSuplDdsSwitchRequiredForEmergencyCall, @NonNull FeatureFlags featureFlags) {
         mEcmExitTimeoutMs = DEFAULT_ECM_EXIT_TIMEOUT_MS;
         mContext = context;
         mHandler = new MyHandler(looper);
         mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall;
-
+        mFeatureFlags = featureFlags;
         PowerManager pm = context.getSystemService(PowerManager.class);
         mWakeLock = (pm != null) ? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                 "telephony:" + TAG) : null;
@@ -523,12 +539,13 @@
      * @param telephonyManagerProxy                   The {@link TelephonyManagerProxy} to be
      *                                                injected.
      * @param radioOnHelper                           The {@link RadioOnHelper} to be injected.
+     * @param featureFlags                            The {@link FeatureFlags} to be injected.
      */
     @VisibleForTesting
     public EmergencyStateTracker(Context context, Looper looper,
             boolean isSuplDdsSwitchRequiredForEmergencyCall, PhoneFactoryProxy phoneFactoryProxy,
             PhoneSwitcherProxy phoneSwitcherProxy, TelephonyManagerProxy telephonyManagerProxy,
-            RadioOnHelper radioOnHelper, long ecmExitTimeoutMs) {
+            RadioOnHelper radioOnHelper, long ecmExitTimeoutMs, FeatureFlags featureFlags) {
         mContext = context;
         mHandler = new MyHandler(looper);
         mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall;
@@ -537,6 +554,7 @@
         mTelephonyManagerProxy = telephonyManagerProxy;
         mRadioOnHelper = radioOnHelper;
         mEcmExitTimeoutMs = ecmExitTimeoutMs;
+        mFeatureFlags = featureFlags;
         mWakeLock = null; // Don't declare a wakelock in tests
         mConfigManager = context.getSystemService(CarrierConfigManager.class);
         mConfigManager.registerCarrierConfigChangeListener(mHandler::post,
@@ -574,7 +592,7 @@
             // Case1) When 2nd emergency call is initiated during an active call on the same phone.
             // Case2) While the device is in ECBM, an emergency call is initiated on the same phone.
             if (isSamePhone(mPhone, phone) && (!mActiveEmergencyCalls.isEmpty() || isInEcm())) {
-                exitEmergencySmsCallbackMode();
+                exitEmergencySmsCallbackMode(STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED);
                 mOngoingConnection = c;
                 mIsTestEmergencyNumber = isTestEmergencyNumber;
                 if (isInEcm()) {
@@ -622,7 +640,7 @@
                     mIsEmergencyCallStartedDuringEmergencySms = false;
                 }
 
-                exitEmergencySmsCallbackMode();
+                exitEmergencySmsCallbackMode(STOP_REASON_OUTGOING_EMERGENCY_CALL_INITIATED);
             }
 
             if (mIsEmergencyCallStartedDuringEmergencySms) {
@@ -1087,7 +1105,7 @@
      * Handles the radio power off request.
      */
     public void onCellularRadioPowerOffRequested() {
-        exitEmergencySmsCallbackModeAndEmergencyMode();
+        exitEmergencySmsCallbackModeAndEmergencyMode(STOP_REASON_UNKNOWN);
         exitEmergencyCallbackMode();
     }
 
@@ -1159,10 +1177,14 @@
 
         setEmergencyCallbackMode(mPhone, EMERGENCY_TYPE_CALL);
 
-        // Post this runnable so we will automatically exit if no one invokes
-        // exitEmergencyCallbackMode() directly.
         long delayInMillis = TelephonyProperties.ecm_exit_timer()
                 .orElse(mEcmExitTimeoutMs);
+        if (mFeatureFlags.emergencyCallbackModeNotification()) {
+            mPhone.startEmergencyCallbackMode(EMERGENCY_CALLBACK_MODE_CALL, delayInMillis);
+        }
+
+        // Post this runnable so we will automatically exit if no one invokes
+        // exitEmergencyCallbackMode() directly.
         mHandler.postDelayed(mExitEcmRunnable, delayInMillis);
 
         // We don't want to go to sleep while in ECM.
@@ -1170,9 +1192,27 @@
     }
 
     /**
-     * Exits emergency callback mode and notifies relevant listeners.
+     * Exits the emergency callback mode.
+     *
+     * <p>This method exits the emergency callback mode with an unknown stop reason. It removes
+     * any pending exit requests and notifies relevant listeners about the change in status.
      */
     public void exitEmergencyCallbackMode() {
+        exitEmergencyCallbackMode(STOP_REASON_UNKNOWN);
+    }
+
+    /**
+     * Exits the emergency callback mode.
+     *
+     * <p>This method exits the emergency callback mode with the specified stop reason. It removes
+     * any pending exit requests and notifies relevant listeners about the change in status,
+     * providing the reason for exiting.
+     *
+     * @param reason The reason for exiting. See
+     *               {@link TelephonyManager.EmergencyCallbackModeStopReason} for possible values.
+     */
+    public void exitEmergencyCallbackMode(
+            @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
         Rlog.d(TAG, "exit ECBM");
         // Remove pending exit ECM runnable, if any.
         mHandler.removeCallbacks(mExitEcmRunnable);
@@ -1191,6 +1231,10 @@
             sendEmergencyCallbackModeChange();
             gsmCdmaPhone.notifyEmergencyCallRegistrants(false);
 
+            if (mFeatureFlags.emergencyCallbackModeNotification()) {
+                gsmCdmaPhone.stopEmergencyCallbackMode(EMERGENCY_CALLBACK_MODE_CALL, reason);
+            }
+
             // Exit emergency mode on modem.
             exitEmergencyMode(gsmCdmaPhone, EMERGENCY_TYPE_CALL);
         }
@@ -1213,11 +1257,20 @@
     }
 
     /**
-     * Exits emergency callback mode and triggers runnable after exit response is received.
+     * Exits the emergency callback mode and triggers {@link Runnable} after exit response is
+     * received.
+     *
+     * <p>This method exits the emergency callback mode with the specified stop reason and then
+     * executes the provided {@link Runnable}.
+     *
+     * @param onComplete The {@link Runnable} to execute after exiting emergency callback mode.
+     * @param reason The reason for exiting. See
+     *               {@link TelephonyManager.EmergencyCallbackModeStopReason} for possible values.
      */
-    public void exitEmergencyCallbackMode(Runnable onComplete) {
+    public void exitEmergencyCallbackMode(Runnable onComplete,
+            @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
         mOnEcmExitCompleteRunnable = onComplete;
-        exitEmergencyCallbackMode();
+        exitEmergencyCallbackMode(reason);
     }
 
     /**
@@ -1323,7 +1376,7 @@
                 // emergency SMS callback mode first.
                 exitScbmInOtherPhone = true;
                 mIsEmergencySmsStartedDuringScbm = true;
-                exitEmergencySmsCallbackModeAndEmergencyMode();
+                exitEmergencySmsCallbackModeAndEmergencyMode(STOP_REASON_EMERGENCY_SMS_SENT);
             } else {
                 Rlog.e(TAG, "Emergency SMS is in progress on the other slot.");
                 return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED);
@@ -1460,6 +1513,9 @@
      */
     private void enterEmergencySmsCallbackMode() {
         Rlog.d(TAG, "enter SCBM while " + (isInScbm() ? "in" : "not in") + " SCBM");
+
+        boolean shouldRestartEcm = isInScbm();
+
         // Remove pending message if present.
         mHandler.removeMessages(MSG_EXIT_SCBM);
 
@@ -1484,17 +1540,29 @@
         // Post the message so we will automatically exit if no one invokes
         // exitEmergencySmsCallbackModeAndEmergencyMode() directly.
         mHandler.sendEmptyMessageDelayed(MSG_EXIT_SCBM, delayInMillis);
+
+        if (mFeatureFlags.emergencyCallbackModeNotification()) {
+            if (shouldRestartEcm) {
+                mSmsPhone.restartEmergencyCallbackMode(EMERGENCY_CALLBACK_MODE_SMS, delayInMillis);
+            } else {
+                mSmsPhone.startEmergencyCallbackMode(EMERGENCY_CALLBACK_MODE_SMS, delayInMillis);
+            }
+        }
     }
 
     /**
      * Exits emergency SMS callback mode and emergency mode if the device is in SCBM and
      * the emergency mode is in CALLBACK.
+     *
+     * @param reason The reason for exiting. See
+     *               {@link TelephonyManager.EmergencyCallbackModeStopReason} for possible values.
      */
-    private void exitEmergencySmsCallbackModeAndEmergencyMode() {
+    private void exitEmergencySmsCallbackModeAndEmergencyMode(
+            @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
         Rlog.d(TAG, "exit SCBM and emergency mode");
         final Phone smsPhone = mSmsPhone;
         boolean wasInScbm = isInScbm();
-        exitEmergencySmsCallbackMode();
+        exitEmergencySmsCallbackMode(reason);
 
         // The emergency mode needs to be checked to ensure that there is no ongoing emergency SMS.
         if (wasInScbm && mOngoingEmergencySmsIds.isEmpty()) {
@@ -1505,13 +1573,22 @@
 
     /**
      * Exits emergency SMS callback mode.
+     *
+     * @param reason The reason for exiting. See
+     *               {@link TelephonyManager.EmergencyCallbackModeStopReason} for possible values.
      */
-    private void exitEmergencySmsCallbackMode() {
+    private void exitEmergencySmsCallbackMode(
+            @TelephonyManager.EmergencyCallbackModeStopReason int reason) {
         // Remove pending message if present.
         mHandler.removeMessages(MSG_EXIT_SCBM);
 
         if (isInScbm()) {
             Rlog.i(TAG, "exit SCBM");
+
+            if (mFeatureFlags.emergencyCallbackModeNotification()) {
+                mSmsPhone.stopEmergencyCallbackMode(EMERGENCY_CALLBACK_MODE_SMS, reason);
+            }
+
             setIsInScbm(false);
         }
 
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index e802b3e..d47f05b 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -1797,7 +1797,8 @@
                                 dialArgs.intentExtras);
                     }
                 };
-                EmergencyStateTracker.getInstance().exitEmergencyCallbackMode(onComplete);
+                EmergencyStateTracker.getInstance().exitEmergencyCallbackMode(onComplete,
+                        TelephonyManager.STOP_REASON_OUTGOING_NORMAL_CALL_INITIATED);
             } else {
                 try {
                     getEcbmInterface().exitEmergencyCallbackMode();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
index 2664ff3..6694e98 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -21,6 +21,8 @@
 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.TelephonyManager.EMERGENCY_CALLBACK_MODE_CALL;
+import static android.telephony.TelephonyManager.EMERGENCY_CALLBACK_MODE_SMS;
 
 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK;
 import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN;
@@ -36,6 +38,7 @@
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.anyVararg;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
@@ -121,6 +124,7 @@
 
         doReturn(TelephonyManager.SIM_STATE_READY)
                 .when(mTelephonyManagerProxy).getSimState(anyInt());
+        doReturn(true).when(mFeatureFlags).emergencyCallbackModeNotification();
     }
 
     @After
@@ -135,7 +139,7 @@
             EmergencyStateTracker.getInstance();
         });
 
-        EmergencyStateTracker.make(mContext, true);
+        EmergencyStateTracker.make(mContext, true, mFeatureFlags);
 
         assertNotNull(EmergencyStateTracker.getInstance());
     }
@@ -143,7 +147,7 @@
     @Test
     @SmallTest
     public void getInstance_returnsSameInstance() {
-        EmergencyStateTracker.make(mContext, true);
+        EmergencyStateTracker.make(mContext, true, mFeatureFlags);
         EmergencyStateTracker instance1 = EmergencyStateTracker.getInstance();
         EmergencyStateTracker instance2 = EmergencyStateTracker.getInstance();
 
@@ -761,6 +765,8 @@
                 .getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, true));
         // Verify emergency callback mode set on modem
         verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any());
+        // Verify emergency callback mode started with the correct emergency type
+        verify(testPhone).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_CALL), anyLong());
     }
 
     /**
@@ -819,6 +825,9 @@
 
         processAllFutureMessages();
 
+        // Verify emergency callback mode stopped with the correct emergency type and reason.
+        verify(testPhone).stopEmergencyCallbackMode(eq(EmergencyStateTracker.EMERGENCY_TYPE_CALL),
+                eq(TelephonyManager.STOP_REASON_TIMER_EXPIRED));
         // Verify exitEmergencyMode() is called after timeout
         verify(testPhone).exitEmergencyMode(any(Message.class));
         assertFalse(emergencyStateTracker.isInEmergencyMode());
@@ -854,6 +863,9 @@
 
         emergencyStateTracker.onCellularRadioPowerOffRequested();
 
+        // Verify emergency callback mode stopped with the correct emergency type and reason.
+        verify(testPhone).stopEmergencyCallbackMode(eq(EmergencyStateTracker.EMERGENCY_TYPE_CALL),
+                eq(TelephonyManager.STOP_REASON_UNKNOWN));
         // Verify exitEmergencyMode() is called.
         verify(testPhone).exitEmergencyMode(any(Message.class));
         assertFalse(emergencyStateTracker.isInEcm());
@@ -1005,7 +1017,8 @@
         assertTrue(emergencyStateTracker.isInEcm());
         verify(phone0, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
         verify(phone0, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
-
+        verify(phone0, times(1)).startEmergencyCallbackMode(
+                eq(EMERGENCY_CALLBACK_MODE_CALL), anyLong());
         // Second emergency call started.
         CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(phone0,
                 mTestConnection2, false);
@@ -1013,6 +1026,8 @@
         assertFalse(future.isDone());
         verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
         verify(phone0, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
+        verify(phone0, times(1)).startEmergencyCallbackMode(
+                eq(EMERGENCY_CALLBACK_MODE_CALL), anyLong());
     }
 
     @Test
@@ -1087,6 +1102,10 @@
         verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WLAN), any(Message.class));
         verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
         verify(phone0, never()).exitEmergencyMode(any(Message.class));
+        verify(phone0, times(2)).startEmergencyCallbackMode(
+                eq(EMERGENCY_CALLBACK_MODE_CALL), anyLong());
+        verify(phone0, never()).stopEmergencyCallbackMode(
+                eq(EMERGENCY_CALLBACK_MODE_CALL), anyInt());
     }
 
     @Test
@@ -1224,6 +1243,7 @@
         verify(mCarrierConfigManager).getConfigForSubId(anyInt(),
                 eq(CarrierConfigManager.KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT));
         verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
+        verify(phone0).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_SMS), anyLong());
         assertTrue(emergencyStateTracker.isInEmergencyMode());
         assertTrue(emergencyStateTracker.isInScbm());
     }
@@ -1256,6 +1276,7 @@
         verify(mCarrierConfigManager).getConfigForSubId(anyInt(),
                 eq(CarrierConfigManager.KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT));
         verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
+        verify(phone0).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_SMS), anyLong());
         assertTrue(emergencyStateTracker.isInEmergencyMode());
         assertTrue(emergencyStateTracker.isInScbm());
     }
@@ -1288,6 +1309,8 @@
         verify(mCarrierConfigManager, times(2)).getConfigForSubId(anyInt(),
                 eq(CarrierConfigManager.KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT));
         verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
+        verify(phone0).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_SMS), anyLong());
+        verify(phone0).restartEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_SMS), anyLong());
         assertTrue(emergencyStateTracker.isInEmergencyMode());
         assertTrue(emergencyStateTracker.isInScbm());
     }
@@ -1413,6 +1436,7 @@
         processAllMessages();
 
         verify(phone0, times(2)).setEmergencyMode(anyInt(), any(Message.class));
+        verify(phone0).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_CALL), anyLong());
         // Expect: DisconnectCause#NOT_DISCONNECTED.
         assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED),
                 Integer.valueOf(DisconnectCause.NOT_DISCONNECTED));
@@ -1473,6 +1497,8 @@
         CompletableFuture<Integer> future = emergencyStateTracker.startEmergencySms(phone1,
                 TEST_SMS_ID_2, false);
 
+        verify(phone0).stopEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_SMS),
+                eq(TelephonyManager.STOP_REASON_EMERGENCY_SMS_SENT));
         verify(phone0).exitEmergencyMode(any(Message.class));
         // Waits for exiting emergency mode on other phone.
         assertFalse(future.isDone());
@@ -1726,6 +1752,7 @@
         assertFalse(emergencyStateTracker.isInEmergencyCall());
         assertTrue(emergencyStateTracker.isInScbm());
         verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
+        verify(phone0).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_SMS), anyLong());
     }
 
     @Test
@@ -2156,6 +2183,7 @@
         processAllMessages();
 
         verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
+        verify(phone0).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_CALL), anyLong());
         assertTrue(emergencyStateTracker.isInEmergencyMode());
         assertTrue(emergencyStateTracker.isInEcm());
         assertFalse(emergencyStateTracker.isInEmergencyCall());
@@ -2212,6 +2240,8 @@
 
         // Enter emergency callback mode and emergency mode changed by SMS end.
         verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
+        verify(phone0).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_CALL), anyLong());
+        verify(phone0).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_SMS), anyLong());
         assertTrue(emergencyStateTracker.isInEmergencyMode());
         assertTrue(emergencyStateTracker.isInEcm());
         assertFalse(emergencyStateTracker.isInEmergencyCall());
@@ -3379,7 +3409,7 @@
                 anyInt(), anyInt(), any());
         return new EmergencyStateTracker(mContext, mTestableLooper.getLooper(),
                 isSuplDdsSwitchRequiredForEmergencyCall, mPhoneFactoryProxy, mPhoneSwitcherProxy,
-                mTelephonyManagerProxy, mRadioOnHelper, TEST_ECM_EXIT_TIMEOUT_MS);
+                mTelephonyManagerProxy, mRadioOnHelper, TEST_ECM_EXIT_TIMEOUT_MS, mFeatureFlags);
     }
 
     private Phone setupTestPhoneForEmergencyCall(boolean isRoaming, boolean isRadioOn) {
@@ -3483,6 +3513,7 @@
                 eq(CarrierConfigManager.KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT));
         if (!emergencyStateTracker.isInEcm() && !emergencyStateTracker.isInEmergencyCall()) {
             verify(phone).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
+            verify(phone).startEmergencyCallbackMode(eq(EMERGENCY_CALLBACK_MODE_SMS), anyLong());
         }
         assertTrue(emergencyStateTracker.isInEmergencyMode());
         assertTrue(emergencyStateTracker.isInScbm());