summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-10-20 21:56:49 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-10-20 21:56:49 +0000
commit2bfb9f00140730b96c4c543b6b2e722601900158 (patch)
tree1d49760d5dedb85780da1c21ccb474f8520b6b6e
parent3956de147c434663bfd9154a6065487a07ec6e81 (diff)
parent66840a93b6b6e2e2d849b94daeab8d03d8f8acfd (diff)
downloadTelephony-android14-qpr1-s2-release.tar.gz
Change-Id: I3c60e75a550f86c8dbb3c506ccf020462dbc2872
-rw-r--r--ecc/input/eccdata.txt7
-rw-r--r--ecc/output/eccdatabin2136 -> 2142 bytes
-rw-r--r--src/com/android/services/telephony/TelephonyConnectionService.java80
-rw-r--r--tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java285
4 files changed, 354 insertions, 18 deletions
diff --git a/ecc/input/eccdata.txt b/ecc/input/eccdata.txt
index 7252480e3..83b5c39a1 100644
--- a/ecc/input/eccdata.txt
+++ b/ecc/input/eccdata.txt
@@ -1372,6 +1372,13 @@ countries {
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 fc8696124..3f28a3a88 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 93a38ddd9..fcf9531a5 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -114,6 +114,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
import javax.annotation.Nullable;
@@ -2576,15 +2577,32 @@ public class TelephonyConnectionService extends ConnectionService {
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()) {
@@ -3032,15 +3050,34 @@ public class TelephonyConnectionService extends ConnectionService {
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 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;
}
- // If this is an emergency call and the phone we originally planned to make this call
+
+ // 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;
@@ -3460,10 +3497,20 @@ public class TelephonyConnectionService extends ConnectionService {
}
}
+ private boolean isAvailableForEmergencyCalls(Phone phone) {
+ return isAvailableForEmergencyCalls(phone,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY);
+ }
+
/**
- * Returns true if the state of the Phone is IN_SERVICE or available for emergency calling only.
+ * 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
*/
- private boolean isAvailableForEmergencyCalls(Phone phone) {
+ @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.
@@ -3471,8 +3518,17 @@ public class TelephonyConnectionService extends ConnectionService {
+ 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 9e1ea24d1..090fc6e05 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 com.android.services.telephony.TelephonyConnectionService.TIMEOUT_
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;
@@ -62,6 +63,7 @@ import android.telecom.Conference;
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;
@@ -75,7 +77,9 @@ import android.telephony.SubscriptionManager;
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;
@@ -117,8 +121,10 @@ import java.util.Collection;
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.
@@ -126,6 +132,34 @@ import java.util.concurrent.Executor;
@RunWith(AndroidJUnit4.class)
public class TelephonyConnectionServiceTest extends TelephonyTestBase {
+ 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
* that does not try to configure anything.
@@ -175,8 +209,8 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
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(
@@ -1298,6 +1332,82 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
}
/**
+ * 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.
*/
@@ -2037,6 +2147,8 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
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,
@@ -2079,6 +2191,8 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
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);
@@ -2126,6 +2240,8 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
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);
@@ -2167,6 +2283,8 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
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);
@@ -2220,6 +2338,8 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
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);
@@ -2274,6 +2394,8 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
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);
@@ -2930,6 +3052,153 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
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)
@@ -3138,10 +3407,14 @@ public class TelephonyConnectionServiceTest extends TelephonyTestBase {
}
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) {