Provide ability to place normal routed e-call on in-service sim first.

Handle the case where an emergency number has normal routing, and a
carrier wants to use the in-service SIM to place a normal routed
emergency call.  Ensures we'll prefer the in-service SIM in this case over
trying to use a limited service one.

Add '100' as a normal routed emergency number in India.

Test: testCreateOutgoingConnectionForNormalRoutedEmergencyCall - this
verifies the end-to-end case this bug was raised for and ensures that we
will prefer the in-service sim over the limited service sim.
Test: testIsNormalRoutedEmergencyCallForCarrier - this verifies the
new method isNormalRoutedEmergencyCallForCarrier to ensure it can properly
detect a normal routed emergency call for carriers that prefer to use an
in service sim.
Test: testIsAvailableForEmergencyCallsNotForCrossSim - regression tests
the method which was refactored and covers the new cases.
Test: testIsAvailableForEmergencyCallsForEmergencyRoutingInEmergencyOnly -
verifies that we can recognize whether a phone is available when the
phone is limited service.
Test: testIsAvailableForEmergencyCallsForEmergencyRoutingInService -
verifies that we can recognize a phone is available when the phone is in
service.
Test: testGetPhoneForNormalRoutedEmergencyCallWhenCarrierDoesntSupport -
verifies that if the carrier doesn't support using normal routing on the
in service phone we won't return anything.
Test: testGetPhoneForNormalRoutedEmergencyCallWhenCarrierDoesSupport -
verifies that if the carries does support using normal routing on the
in service phone we'll find it.
Test: testGetPhoneForNormalRoutedEmergencyCallWhenCarrierDoesSupportMultiSim
Similar to the latter but with multisim specifically.
Test: com.android.phone.ecc.EccDataTest#testEccDataContent
Bug: 281934614
Flag: This is a cherry-pick from udc-qpr-dev, so no flag is needed.
Change-Id: I308285585a78052a4f95ffc7f3f503629b11dda9
diff --git a/ecc/input/eccdata.txt b/ecc/input/eccdata.txt
index 7252480..83b5c39 100644
--- a/ecc/input/eccdata.txt
+++ b/ecc/input/eccdata.txt
@@ -1372,6 +1372,13 @@
     types: AMBULANCE
     types: FIRE
   }
+  eccs {
+    phone_number: "100"
+    types: POLICE
+    types: AMBULANCE
+    types: FIRE
+    routing: NORMAL
+  }
   ecc_fallback: "112"
 }
 countries {
diff --git a/ecc/output/eccdata b/ecc/output/eccdata
index fc86961..3f28a3a 100644
--- a/ecc/output/eccdata
+++ b/ecc/output/eccdata
Binary files differ
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index a381d7c..651bbd1 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -116,6 +116,7 @@
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.regex.Pattern;
+import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
@@ -2579,15 +2580,32 @@
 
     private boolean isNormalRouting(Phone phone, String number) {
         if (phone.getEmergencyNumberTracker() != null) {
-            EmergencyNumber num = phone.getEmergencyNumberTracker().getEmergencyNumber(number);
-            if (num != null) {
-                return num.getEmergencyCallRouting()
-                        == EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL;
-            }
+            // Note: There can potentially be multiple instances of EmergencyNumber found; if any of
+            // them have normal routing, then use normal routing.
+            List<EmergencyNumber> nums = phone.getEmergencyNumberTracker().getEmergencyNumbers(
+                    number);
+            return nums.stream().anyMatch(n ->
+                    n.getEmergencyCallRouting() == EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
         }
         return false;
     }
 
+    /**
+     * Determines the phone to use for a normal routed emergency call.
+     * @param number The emergency number.
+     * @return The {@link Phone} to place the normal routed emergency call on, or {@code null} if
+     * none was found.
+     */
+    @VisibleForTesting
+    public Phone getPhoneForNormalRoutedEmergencyCall(String number) {
+        return Stream.of(mPhoneFactoryProxy.getPhones())
+                .filter(p -> p.shouldPreferInServiceSimForNormalRoutedEmergencyCall()
+                        && isNormalRouting(p, number)
+                        && isAvailableForEmergencyCalls(p,
+                                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL))
+                .findFirst().orElse(null);
+    }
+
     private boolean isVoiceInService(Phone phone, boolean imsVoiceCapable) {
         // Dialing normal call is available.
         if (phone.isWifiCallingEnabled()) {
@@ -3035,15 +3053,34 @@
         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             int phoneId = mSubscriptionManagerProxy.getPhoneId(subId);
             chosenPhone = mPhoneFactoryProxy.getPhone(phoneId);
+            Log.i(this, "getPhoneForAccount: handle=%s, subId=%s", accountHandle,
+                    (chosenPhone == null ? "null" : chosenPhone.getSubId()));
         }
-        // If this is an emergency call and the phone we originally planned to make this call
+
+        // If this isn't an emergency call, just use the chosen phone (or null if none was found).
+        if (!isEmergency) {
+            return chosenPhone;
+        }
+
+        // Check if this call should be treated as a normal routed emergency call; we'll return null
+        // if this is not a normal routed emergency call.
+        Phone normalRoutingPhone = getPhoneForNormalRoutedEmergencyCall(emergencyNumberAddress);
+        if (normalRoutingPhone != null) {
+            Log.i(this, "getPhoneForAccount: normal routed emergency number,"
+                            + "using phoneId=%d/subId=%d", normalRoutingPhone.getPhoneId(),
+                    normalRoutingPhone.getSubId());
+            return normalRoutingPhone;
+        }
+
+        // Default emergency call phone selection logic:
+        // This is an emergency call and the phone we originally planned to make this call
         // with is not in service or was invalid, try to find one that is in service, using the
         // default as a last chance backup.
-        if (isEmergency && (chosenPhone == null || !isAvailableForEmergencyCalls(chosenPhone))) {
+        if (chosenPhone == null || !isAvailableForEmergencyCalls(chosenPhone)) {
             Log.d(this, "getPhoneForAccount: phone for phone acct handle %s is out of service "
                     + "or invalid for emergency call.", accountHandle);
             chosenPhone = getPhoneForEmergencyCall(emergencyNumberAddress);
-            Log.d(this, "getPhoneForAccount: using subId: " +
+            Log.i(this, "getPhoneForAccount: emergency call - using subId: %s",
                     (chosenPhone == null ? "null" : chosenPhone.getSubId()));
         }
         return chosenPhone;
@@ -3463,10 +3500,20 @@
         }
     }
 
-    /**
-     * Returns true if the state of the Phone is IN_SERVICE or available for emergency calling only.
-     */
     private boolean isAvailableForEmergencyCalls(Phone phone) {
+        return isAvailableForEmergencyCalls(phone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY);
+    }
+
+    /**
+     * Determines if the phone is available for an emergency call given the specified routing.
+     *
+     * @param phone the phone to check the service availability for
+     * @param routing the emergency call routing for this call
+     */
+    @VisibleForTesting
+    public boolean isAvailableForEmergencyCalls(Phone phone,
+            @EmergencyNumber.EmergencyCallRouting int routing) {
         if (phone.getImsRegistrationTech() == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
             // When a Phone is registered to Cross-SIM calling, there must always be a Phone on the
             // other sub which is registered to cellular, so that must be selected.
@@ -3474,8 +3521,17 @@
                     + phone + " as it is registered to CROSS_SIM");
             return false;
         }
-        return ServiceState.STATE_IN_SERVICE == phone.getServiceState().getState() ||
-                phone.getServiceState().isEmergencyOnly();
+
+        // In service phones are always appropriate for emergency calls.
+        if (ServiceState.STATE_IN_SERVICE == phone.getServiceState().getState()) {
+            return true;
+        }
+
+        // If the call routing is unknown or is using emergency routing, an emergency only attach is
+        // sufficient for placing the emergency call.  Normal routed emergency calls cannot be
+        // placed on an emergency-only phone.
+        return (routing != EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL
+                && phone.getServiceState().isEmergencyOnly());
     }
 
     /**
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 34cbfdd..36513cf 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -32,6 +32,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
@@ -63,6 +64,7 @@
 import android.telecom.Conferenceable;
 import android.telecom.ConnectionRequest;
 import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.AccessNetworkConstants;
@@ -76,7 +78,9 @@
 import android.telephony.TelephonyManager;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -120,8 +124,10 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Unit tests for TelephonyConnectionService.
@@ -130,6 +136,33 @@
 @RunWith(AndroidJUnit4.class)
 public class TelephonyConnectionServiceTest extends TelephonyTestBase {
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    private static final String NORMAL_ROUTED_EMERGENCY_NUMBER = "110";
+    private static final String EMERGENCY_ROUTED_EMERGENCY_NUMBER = "911";
+    private static final EmergencyNumber MOCK_NORMAL_NUMBER = new EmergencyNumber(
+            NORMAL_ROUTED_EMERGENCY_NUMBER,
+            "US" /* country */,
+            null /* mcc */,
+            EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+            Collections.emptyList() /* categories */,
+            EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
+            EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+    private static final EmergencyNumber MOCK_NORMAL_NUMBER_WITH_UNKNOWN_ROUTING =
+            new EmergencyNumber(
+                    NORMAL_ROUTED_EMERGENCY_NUMBER,
+                    "US" /* country */,
+                    "455" /* mcc */,
+                    EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+                    Collections.emptyList() /* categories */,
+                    EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
+                    EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
+    private static final EmergencyNumber MOCK_EMERGENCY_NUMBER = new EmergencyNumber(
+            EMERGENCY_ROUTED_EMERGENCY_NUMBER,
+            "US" /* country */,
+            null /* mcc */,
+            EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+            Collections.emptyList() /* categories */,
+            EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
+            EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY);
 
     /**
      * Unlike {@link TestTelephonyConnection}, a bare minimal {@link TelephonyConnection} impl
@@ -180,8 +213,8 @@
 
     private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
             "com.android.phone.tests", TelephonyConnectionServiceTest.class.getName());
-    private static final String TEST_ACCOUNT_ID1 = "id1";
-    private static final String TEST_ACCOUNT_ID2 = "id2";
+    private static final String TEST_ACCOUNT_ID1 = "0"; // subid 0
+    private static final String TEST_ACCOUNT_ID2 = "1"; // subid 1
     private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_1 = new PhoneAccountHandle(
             TEST_COMPONENT_NAME, TEST_ACCOUNT_ID1);
     private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_2 = new PhoneAccountHandle(
@@ -1305,6 +1338,82 @@
     }
 
     /**
+     * Test that the TelephonyConnectionService successfully dials an outgoing normal routed
+     * emergency call on an in-service sim.
+     */
+    @Test
+    @SmallTest
+    public void testCreateOutgoingConnectionForNormalRoutedEmergencyCall()
+            throws CallStateException {
+        // A whole load of annoying mocks to set up to test this scenario.
+        // We'll purposely try to start the call on the limited service phone.
+        ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+                .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+                .setAddress(Uri.fromParts(PhoneAccount.SCHEME_TEL, NORMAL_ROUTED_EMERGENCY_NUMBER,
+                        null))
+                .build();
+
+        // First phone is in limited service.
+        Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_EMERGENCY_ONLY,
+                true /*isEmergencyOnly*/);
+        doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_LTE).when(testPhone0)
+                .getImsRegistrationTech();
+        doReturn(0).when(testPhone0).getSubId();
+        setupMockEmergencyNumbers(testPhone0, List.of(MOCK_NORMAL_NUMBER,
+                MOCK_NORMAL_NUMBER_WITH_UNKNOWN_ROUTING, MOCK_EMERGENCY_NUMBER));
+
+        // Second phone is in full service; this is ultimately the one we want to pick.
+        Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_IN_SERVICE,
+                false /*isEmergencyOnly*/);
+        doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_LTE).when(testPhone1)
+                .getImsRegistrationTech();
+        doReturn(1).when(testPhone1).getSubId();
+        setupMockEmergencyNumbers(testPhone1, List.of(MOCK_NORMAL_NUMBER,
+                MOCK_NORMAL_NUMBER_WITH_UNKNOWN_ROUTING, MOCK_EMERGENCY_NUMBER));
+
+        // Make sure both phones are going to prefer in service for normal routed ecalls.
+        doReturn(true).when(testPhone0).shouldPreferInServiceSimForNormalRoutedEmergencyCall();
+        doReturn(true).when(testPhone1).shouldPreferInServiceSimForNormalRoutedEmergencyCall();
+
+        // A whole load of other stuff that needs to be setup for this to work.
+        doReturn(GSM_PHONE).when(testPhone0).getPhoneType();
+        doReturn(GSM_PHONE).when(testPhone1).getPhoneType();
+        List<Phone> phones = new ArrayList<>(2);
+        doReturn(true).when(testPhone0).isRadioOn();
+        doReturn(true).when(testPhone1).isRadioOn();
+        phones.add(testPhone0);
+        phones.add(testPhone1);
+        setPhones(phones);
+        doReturn(0).when(mPhoneUtilsProxy).getSubIdForPhoneAccountHandle(
+                eq(PHONE_ACCOUNT_HANDLE_1));
+        doReturn(1).when(mPhoneUtilsProxy).getSubIdForPhoneAccountHandle(
+                eq(PHONE_ACCOUNT_HANDLE_2));
+        setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
+        setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_2, testPhone1);
+        setupDeviceConfig(testPhone0, testPhone1, 0);
+        doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
+                eq(NORMAL_ROUTED_EMERGENCY_NUMBER));
+        HashMap<Integer, List<EmergencyNumber>> emergencyNumbers = new HashMap<>(1);
+        List<EmergencyNumber> numbers = new ArrayList<>();
+        numbers.add(MOCK_EMERGENCY_NUMBER);
+        numbers.add(MOCK_NORMAL_NUMBER);
+        numbers.add(MOCK_NORMAL_NUMBER_WITH_UNKNOWN_ROUTING);
+        emergencyNumbers.put(0 /*subId*/, numbers);
+        doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
+        doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
+
+        // All of that for... this.
+        mConnection = mTestConnectionService.onCreateOutgoingConnection(
+                PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+        assertNotNull("test connection was not set up correctly.", mConnection);
+
+        // Lets make sure we DID try to place the call on phone 1, which is the in service phone.
+        verify(testPhone1).dial(anyString(), any(DialArgs.class), any(Consumer.class));
+        // And make sure we DID NOT try to place the call on phone 0, which is in limited service.
+        verify(testPhone0, never()).dial(anyString(), any(DialArgs.class), any(Consumer.class));
+    }
+
+    /**
      * Test that the TelephonyConnectionService successfully turns satellite off before placing the
      * emergency call.
      */
@@ -2110,6 +2219,8 @@
         setupForDialForDomainSelection(mPhone0, selectedDomain, false);
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
         doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
+                anyString());
 
         mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
                 createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
@@ -2152,6 +2263,8 @@
 
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
         doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
+                anyString());
 
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
 
@@ -2199,6 +2312,8 @@
 
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
         doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
+                anyString());
 
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
 
@@ -2240,6 +2355,8 @@
 
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
         doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
+                anyString());
 
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
 
@@ -2293,6 +2410,8 @@
 
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
         doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
+                anyString());
 
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
 
@@ -2347,6 +2466,8 @@
 
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
         doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+        doReturn(Arrays.asList(emergencyNumber)).when(mEmergencyNumberTracker).getEmergencyNumbers(
+                anyString());
 
         when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
 
@@ -3025,6 +3146,153 @@
                 disconnectCause.getTelephonyDisconnectCause());
     }
 
+    @Test
+    public void testIsAvailableForEmergencyCallsNotForCrossSim() {
+        Phone mockPhone = Mockito.mock(Phone.class);
+        when(mockPhone.getImsRegistrationTech()).thenReturn(
+                ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM);
+        assertFalse(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY));
+        assertFalse(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL));
+        assertFalse(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+    }
+
+    @Test
+    public void testIsAvailableForEmergencyCallsForEmergencyRoutingInEmergencyOnly() {
+        ServiceState mockService = Mockito.mock(ServiceState.class);
+        when(mockService.isEmergencyOnly()).thenReturn(true);
+        when(mockService.getState()).thenReturn(ServiceState.STATE_EMERGENCY_ONLY);
+
+        Phone mockPhone = Mockito.mock(Phone.class);
+        when(mockPhone.getImsRegistrationTech()).thenReturn(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        when(mockPhone.getServiceState()).thenReturn(mockService);
+
+        assertTrue(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY));
+        assertFalse(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL));
+        assertTrue(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+    }
+
+    @Test
+    public void testIsAvailableForEmergencyCallsForEmergencyRoutingInService() {
+        ServiceState mockService = Mockito.mock(ServiceState.class);
+        when(mockService.isEmergencyOnly()).thenReturn(false);
+        when(mockService.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+
+        Phone mockPhone = Mockito.mock(Phone.class);
+        when(mockPhone.getImsRegistrationTech()).thenReturn(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+        when(mockPhone.getServiceState()).thenReturn(mockService);
+
+        assertTrue(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY));
+        assertTrue(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL));
+        assertTrue(mTestConnectionService.isAvailableForEmergencyCalls(mockPhone,
+                EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN));
+    }
+
+    /**
+     * Verify that is the carrier config indicates that the carrier does not prefer to use an in
+     * service sim for a normal routed emergency call that we'll get no result.
+     */
+    @Test
+    public void testGetPhoneForNormalRoutedEmergencyCallWhenCarrierDoesntSupport() {
+        ServiceState mockService = Mockito.mock(ServiceState.class);
+        when(mockService.isEmergencyOnly()).thenReturn(false);
+        when(mockService.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+
+        Phone mockPhone = Mockito.mock(Phone.class);
+        when(mockPhone.shouldPreferInServiceSimForNormalRoutedEmergencyCall()).thenReturn(
+                false);
+        setupMockEmergencyNumbers(mockPhone, List.of(MOCK_NORMAL_NUMBER));
+        when(mPhoneFactoryProxy.getPhones()).thenReturn(new Phone[] {mockPhone});
+
+        assertNull(mTestConnectionService.getPhoneForNormalRoutedEmergencyCall(
+                NORMAL_ROUTED_EMERGENCY_NUMBER));
+    }
+
+    /**
+     * Verify that is the carrier config indicates that the carrier prefers to use an in service sim
+     * for a normal routed emergency call that we'll get the in service sim that supports it.
+     */
+    @Test
+    public void testGetPhoneForNormalRoutedEmergencyCallWhenCarrierDoesSupport() {
+        ServiceState mockService = Mockito.mock(ServiceState.class);
+        when(mockService.isEmergencyOnly()).thenReturn(false);
+        when(mockService.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+
+        Phone mockPhone = Mockito.mock(Phone.class);
+        when(mockPhone.shouldPreferInServiceSimForNormalRoutedEmergencyCall()).thenReturn(
+                true);
+        when(mockPhone.getServiceState()).thenReturn(mockService);
+        setupMockEmergencyNumbers(mockPhone, List.of(MOCK_NORMAL_NUMBER));
+        when(mPhoneFactoryProxy.getPhones()).thenReturn(new Phone[] {mockPhone});
+
+        assertEquals(mockPhone,
+                mTestConnectionService.getPhoneForNormalRoutedEmergencyCall(
+                        NORMAL_ROUTED_EMERGENCY_NUMBER));
+    }
+
+    /**
+     * Verify where there are two sims, one in limited service, and another in full service, if the
+     * carrier prefers to use an in-service sim, we choose the in-service sim.
+     */
+    @Test
+    public void testGetPhoneForNormalRoutedEmergencyCallWhenCarrierDoesSupportMultiSim() {
+        ServiceState mockInService = Mockito.mock(ServiceState.class);
+        when(mockInService.isEmergencyOnly()).thenReturn(false);
+        when(mockInService.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+        ServiceState mockLimitedService = Mockito.mock(ServiceState.class);
+        when(mockLimitedService.isEmergencyOnly()).thenReturn(true);
+        when(mockLimitedService.getState()).thenReturn(ServiceState.STATE_EMERGENCY_ONLY);
+
+        Phone mockInservicePhone = Mockito.mock(Phone.class);
+        when(mockInservicePhone.shouldPreferInServiceSimForNormalRoutedEmergencyCall()).thenReturn(
+                true);
+        when(mockInservicePhone.getServiceState()).thenReturn(mockInService);
+        setupMockEmergencyNumbers(mockInservicePhone, List.of(MOCK_NORMAL_NUMBER));
+
+        Phone mockLimitedServicePhone = Mockito.mock(Phone.class);
+        when(mockLimitedServicePhone.shouldPreferInServiceSimForNormalRoutedEmergencyCall())
+                .thenReturn(true);
+        when(mockLimitedServicePhone.getServiceState()).thenReturn(mockLimitedService);
+        setupMockEmergencyNumbers(mockLimitedServicePhone, List.of(MOCK_NORMAL_NUMBER));
+
+        when(mPhoneFactoryProxy.getPhones()).thenReturn(new Phone[] {mockLimitedServicePhone,
+                mockInservicePhone});
+
+        assertEquals(mockInservicePhone,
+                mTestConnectionService.getPhoneForNormalRoutedEmergencyCall(
+                        NORMAL_ROUTED_EMERGENCY_NUMBER));
+    }
+
+    private void setupMockEmergencyNumbers(Phone mockPhone, List<EmergencyNumber> numbers) {
+        EmergencyNumberTracker emergencyNumberTracker = Mockito.mock(EmergencyNumberTracker.class);
+        // Yuck.  There should really be a fake emergency number class which makes it easy to inject
+        // the numbers for testing.
+        ArrayMap<String, List<EmergencyNumber>> numbersMap = new ArrayMap<>();
+        for (EmergencyNumber number : numbers) {
+            when(emergencyNumberTracker.getEmergencyNumber(eq(number.getNumber())))
+                    .thenReturn(number);
+            if (!numbersMap.containsKey(number.getNumber())) {
+                numbersMap.put(number.getNumber(), new ArrayList<>());
+            }
+            numbersMap.get(number.getNumber()).add(number);
+        }
+        // Double yuck.
+        for (Map.Entry<String, List<EmergencyNumber>> entry : numbersMap.entrySet()) {
+            when(emergencyNumberTracker.getEmergencyNumbers(eq(entry.getKey()))).thenReturn(
+                    entry.getValue());
+        }
+        when(mockPhone.getEmergencyNumberTracker()).thenReturn(emergencyNumberTracker);
+    }
+
     private void setupForDialForDomainSelection(Phone mockPhone, int domain, boolean isEmergency) {
         if (isEmergency) {
             doReturn(mEmergencyCallDomainSelectionConnection).when(mDomainSelectionResolver)
@@ -3233,10 +3501,14 @@
     }
 
     private void setupHandleToPhoneMap(PhoneAccountHandle handle, Phone phone) {
-        // use subId 0
-        when(mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(eq(handle))).thenReturn(0);
-        when(mSubscriptionManagerProxy.getPhoneId(eq(0))).thenReturn(0);
-        when(mPhoneFactoryProxy.getPhone(eq(0))).thenReturn(phone);
+        // The specified handle has an id which is subID
+        doReturn(Integer.parseInt(handle.getId())).when(mPhoneUtilsProxy)
+                .getSubIdForPhoneAccountHandle(eq(handle));
+        // The specified sub id in the passed handle will correspond to the phone's phone id.
+        doReturn(phone.getPhoneId()).when(mSubscriptionManagerProxy)
+                .getPhoneId(eq(Integer.parseInt(handle.getId())));
+        int phoneId = phone.getPhoneId();
+        doReturn(phone).when(mPhoneFactoryProxy).getPhone(eq(phoneId));
     }
 
     private AsyncResult getSuppServiceNotification(int notificationType, int code) {