aboutsummaryrefslogtreecommitdiffstats
path: root/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
diff options
context:
space:
mode:
authorBrad Ebinger <breadley@google.com>2019-05-30 16:32:23 -0700
committerBrad Ebinger <breadley@google.com>2019-06-04 20:44:03 +0000
commit0484f14bb9e90b2fce7a274da00a66c72149a87b (patch)
treeccf2fbe16dbfa56d5a6c9d6eba7a546f93753b3b /tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
parent39fddc982fb6922d67150a2fc1baa2ce3d89589a (diff)
downloadandroid_frameworks_opt_telephony-0484f14bb9e90b2fce7a274da00a66c72149a87b.tar.gz
android_frameworks_opt_telephony-0484f14bb9e90b2fce7a274da00a66c72149a87b.tar.bz2
android_frameworks_opt_telephony-0484f14bb9e90b2fce7a274da00a66c72149a87b.zip
Switch DDS for MSIM emergency call
PhoneSwitcher now allows for the override of the DDS in the event that it needs to be swapped before an emergency call starts. This happens in DSDS situations on devices where the modem does not support emergency SUPL on the non-DDS. Fixes: 131203278 Test: atest FrameworksTelephonyTests#PhoneSwitcherTest Merged-In: I9b2e6eaf167411e3824f6bf909558d4fb2ccb8d2 Change-Id: I9b2e6eaf167411e3824f6bf909558d4fb2ccb8d2
Diffstat (limited to 'tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java')
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java355
1 files changed, 339 insertions, 16 deletions
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
index f9176afb1..3be7dfd33 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
@@ -18,6 +18,7 @@ package com.android.internal.telephony;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -28,6 +29,7 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -37,6 +39,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.StringNetworkSpecifier;
+import android.os.AsyncResult;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -45,11 +48,21 @@ import android.telephony.PhoneCapability;
import android.telephony.SubscriptionManager;
import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
public class PhoneSwitcherTest extends TelephonyTest {
private static final String[] sNetworkAttributes = new String[] {
"mobile,0,0,0,-1,true", "mobile_mms,2,0,2,60000,true",
@@ -63,6 +76,8 @@ public class PhoneSwitcherTest extends TelephonyTest {
@Mock
private ITelephonyRegistry.Stub mTelRegistryMock;
@Mock
+ private ITelephonyRegistry mTelRegistryInterfaceMock;
+ @Mock
private CommandsInterface mCommandsInterface0;
@Mock
private CommandsInterface mCommandsInterface1;
@@ -93,6 +108,11 @@ public class PhoneSwitcherTest extends TelephonyTest {
PhoneCapability phoneCapability = new PhoneCapability(1, 1, 0, null, false);
doReturn(phoneCapability).when(mPhoneConfigurationManager).getCurrentPhoneCapability();
+ mServiceManagerMockedServices.put("telephony.registry", mTelRegistryMock);
+ doReturn(mTelRegistryInterfaceMock).when(mTelRegistryMock).queryLocalInterface(any());
+
+ doReturn(Call.State.ACTIVE).when(mActiveCall).getState();
+ doReturn(Call.State.IDLE).when(mInactiveCall).getState();
}
@After
@@ -542,31 +562,18 @@ public class PhoneSwitcherTest extends TelephonyTest {
assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 0));
assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 1));
clearInvocations(mMockRadioConfig);
-
- doReturn(Call.State.ACTIVE).when(mActiveCall).getState();
- doReturn(Call.State.IDLE).when(mInactiveCall).getState();
- doReturn(mInactiveCall).when(mPhone).getForegroundCall();
- doReturn(mInactiveCall).when(mPhone).getBackgroundCall();
- doReturn(mInactiveCall).when(mPhone).getRingingCall();
- doReturn(mInactiveCall).when(mPhone2).getForegroundCall();
- doReturn(mInactiveCall).when(mPhone2).getBackgroundCall();
- doReturn(mInactiveCall).when(mPhone2).getRingingCall();
-
+ setAllPhonesInactive();
// Initialization done.
// Phone2 has active call. So data switch to it.
- doReturn(mActiveCall).when(mPhone2).getForegroundCall();
- mPhoneSwitcher.mPhoneStateListener.onPreciseCallStateChanged(null);
- waitABit();
+ notifyPhoneAsInCall(mPhone2);
verify(mMockRadioConfig).setPreferredDataModem(eq(1), any());
assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 1));
assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 0));
clearInvocations(mMockRadioConfig);
// Phone2 call ended. So data switch back to default data sub.
- doReturn(mInactiveCall).when(mPhone2).getForegroundCall();
- mPhoneSwitcher.mPhoneStateListener.onPreciseCallStateChanged(null);
- waitABit();
+ notifyPhoneAsInactive(mPhone2);
verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 0));
assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, 1));
@@ -603,8 +610,324 @@ public class PhoneSwitcherTest extends TelephonyTest {
mHandlerThread.quit();
}
+ @Test
+ @SmallTest
+ public void testEmergencyOverrideSuccessBeforeCallStarts() throws Exception {
+ final int numPhones = 2;
+ final int maxActivePhones = 1;
+ doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
+ initialize(numPhones, maxActivePhones);
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setMsimDefaultDataSubId(numPhones, 1);
+ clearInvocations(mMockRadioConfig);
+
+ // override the phone ID in prep for emergency call
+ CountDownLatch latch = new CountDownLatch(1);
+ CompletableFuture<Boolean> futurePhone = new CompletableFuture<>();
+ futurePhone.whenComplete((result, error) -> {
+ assertTrue(result);
+ latch.countDown();
+ });
+ mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, futurePhone);
+ sendPreferredDataSuccessResult(1);
+ assertTrue(latch.await(2, TimeUnit.SECONDS));
+ // Make sure the correct broadcast is sent out for the overridden phone ID
+ verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(2));
+
+ mHandlerThread.quit();
+ }
+
+ @Test
+ @SmallTest
+ public void testEmergencyOverrideNoDdsChange() throws Exception {
+ final int numPhones = 2;
+ final int maxActivePhones = 1;
+ doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
+ initialize(numPhones, maxActivePhones);
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setMsimDefaultDataSubId(numPhones, 1);
+ clearInvocations(mMockRadioConfig);
+
+ // override the phone ID in prep for emergency call
+ CountDownLatch latch = new CountDownLatch(1);
+ CompletableFuture<Boolean> futurePhone = new CompletableFuture<>();
+ futurePhone.whenComplete((result, error) -> {
+ assertTrue(result);
+ latch.countDown();
+ });
+ mPhoneSwitcher.overrideDefaultDataForEmergency(0, 1, futurePhone);
+ waitABit();
+ // The radio command should never be called because the DDS hasn't changed.
+ verify(mMockRadioConfig, never()).setPreferredDataModem(eq(0), any());
+ assertTrue(latch.await(2, TimeUnit.SECONDS));
+
+ mHandlerThread.quit();
+ }
+
+ @Test
+ @SmallTest
+ public void testEmergencyOverrideEndSuccess() throws Exception {
+ PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS = 500;
+ final int numPhones = 2;
+ final int maxActivePhones = 1;
+ doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
+ initialize(numPhones, maxActivePhones);
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setMsimDefaultDataSubId(numPhones, 1);
+ setAllPhonesInactive();
+ clearInvocations(mMockRadioConfig);
+ clearInvocations(mTelRegistryInterfaceMock);
+
+ // override the phone ID in prep for emergency call
+ CountDownLatch latch = new CountDownLatch(1);
+ CompletableFuture<Boolean> futurePhone = new CompletableFuture<>();
+ futurePhone.whenComplete((result, error) -> {
+ assertTrue(result);
+ latch.countDown();
+ });
+ mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, futurePhone);
+ sendPreferredDataSuccessResult(1);
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+
+ // Start and end the emergency call, which will start override timer
+ notifyPhoneAsInCall(mPhone2);
+ notifyPhoneAsInactive(mPhone2);
+
+ // Verify that the DDS is successfully switched back after 1 second + base ECBM timeout
+ verify(mMockRadioConfig,
+ timeout(PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS + 2000))
+ .setPreferredDataModem(eq(0), any());
+ // Make sure the correct broadcast is sent out for the phone ID
+ verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(1));
+
+ mHandlerThread.quit();
+ }
+
+ @Test
+ @SmallTest
+ public void testEmergencyOverrideEcbmStartEnd() throws Exception {
+ PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS = 500;
+ final int numPhones = 2;
+ final int maxActivePhones = 1;
+ doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
+ initialize(numPhones, maxActivePhones);
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setMsimDefaultDataSubId(numPhones, 1);
+ setAllPhonesInactive();
+ clearInvocations(mMockRadioConfig);
+ clearInvocations(mTelRegistryInterfaceMock);
+
+ // override the phone ID in prep for emergency call
+ CountDownLatch latch = new CountDownLatch(1);
+ CompletableFuture<Boolean> futurePhone = new CompletableFuture<>();
+ futurePhone.whenComplete((result, error) -> {
+ assertTrue(result);
+ latch.countDown();
+ });
+ mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, futurePhone);
+ sendPreferredDataSuccessResult(1);
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+
+ // Start and end the emergency call, which will start override timer
+ notifyPhoneAsInCall(mPhone2);
+ notifyPhoneAsInactive(mPhone2);
+ // Start ECBM
+ Message ecbmMessage = getEcbmRegistration(mPhone2);
+ notifyEcbmStart(mPhone2, ecbmMessage);
+
+ // DDS should not be switched back until ECBM ends, make sure there is no further
+ // interaction.
+ Thread.sleep(PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS + 2000);
+ verify(mMockRadioConfig, never()).setPreferredDataModem(eq(0), any());
+ // Make sure the correct broadcast is sent out for the phone ID
+ verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(2));
+
+ // End ECBM
+ ecbmMessage = getEcbmRegistration(mPhone2);
+ notifyEcbmEnd(mPhone2, ecbmMessage);
+ // Verify that the DDS is successfully switched back after 1 second.
+ verify(mMockRadioConfig, timeout(2000)).setPreferredDataModem(eq(0), any());
+ // Make sure the correct broadcast is sent out for the phone ID
+ verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(1));
+
+
+ mHandlerThread.quit();
+ }
+
+ @Test
+ @SmallTest
+ public void testEmergencyOverrideNoCallStart() throws Exception {
+ PhoneSwitcher.DEFAULT_DATA_OVERRIDE_TIMEOUT_MS = 500;
+ final int numPhones = 2;
+ final int maxActivePhones = 1;
+ doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
+ initialize(numPhones, maxActivePhones);
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setMsimDefaultDataSubId(numPhones, 1);
+ setAllPhonesInactive();
+ clearInvocations(mMockRadioConfig);
+ clearInvocations(mTelRegistryInterfaceMock);
+
+ // override the phone ID in prep for emergency call
+ CountDownLatch latch = new CountDownLatch(1);
+ CompletableFuture<Boolean> futurePhone = new CompletableFuture<>();
+ futurePhone.whenComplete((result, error) -> {
+ assertTrue(result);
+ latch.countDown();
+ });
+ mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, futurePhone);
+ sendPreferredDataSuccessResult(1);
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+
+ // Do not start the call and make sure the override is removed once the timeout expires
+ verify(mMockRadioConfig,
+ timeout(PhoneSwitcher.DEFAULT_DATA_OVERRIDE_TIMEOUT_MS + 1000))
+ .setPreferredDataModem(eq(0), any());
+ // Make sure the correct broadcast is sent out for the phone ID
+ verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(1));
+
+
+ mHandlerThread.quit();
+ }
+
+ @Test
+ @SmallTest
+ public void testEmergencyOverrideMultipleOverrideRequests() throws Exception {
+ PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS = 500;
+ final int numPhones = 2;
+ final int maxActivePhones = 1;
+ doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
+ initialize(numPhones, maxActivePhones);
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setMsimDefaultDataSubId(numPhones, 1);
+ setAllPhonesInactive();
+ clearInvocations(mMockRadioConfig);
+ clearInvocations(mTelRegistryInterfaceMock);
+
+ // override the phone ID in prep for emergency call
+ LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
+ CompletableFuture<Boolean> futurePhone = new CompletableFuture<>();
+ futurePhone.whenComplete((r, error) -> queue.offer(r));
+ mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, futurePhone);
+ sendPreferredDataSuccessResult(1);
+ Boolean result = queue.poll(1, TimeUnit.SECONDS);
+ assertNotNull(result);
+ assertTrue(result);
+
+ // try override the phone ID again while there is an existing override for a different phone
+ futurePhone = new CompletableFuture<>();
+ futurePhone.whenComplete((r, error) -> queue.offer(r));
+ mPhoneSwitcher.overrideDefaultDataForEmergency(0, 1, futurePhone);
+ result = queue.poll(1, TimeUnit.SECONDS);
+ assertNotNull(result);
+ assertFalse(result);
+ verify(mMockRadioConfig, never()).setPreferredDataModem(eq(0), any());
+
+ // Start and end the emergency call, which will start override timer
+ notifyPhoneAsInCall(mPhone2);
+ notifyPhoneAsInactive(mPhone2);
+
+ // Verify that the DDS is successfully switched back after 1 second + base ECBM timeout
+ verify(mMockRadioConfig,
+ timeout(PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS + 2000))
+ .setPreferredDataModem(eq(0), any());
+ // Make sure the correct broadcast is sent out for the phone ID
+ verify(mTelRegistryInterfaceMock).notifyActiveDataSubIdChanged(eq(1));
+
+
+ mHandlerThread.quit();
+ }
+
/* Private utility methods start here */
+ private void setAllPhonesInactive() {
+ doReturn(mInactiveCall).when(mPhone).getForegroundCall();
+ doReturn(mInactiveCall).when(mPhone).getBackgroundCall();
+ doReturn(mInactiveCall).when(mPhone).getRingingCall();
+ doReturn(mInactiveCall).when(mPhone2).getForegroundCall();
+ doReturn(mInactiveCall).when(mPhone2).getBackgroundCall();
+ doReturn(mInactiveCall).when(mPhone2).getRingingCall();
+ }
+
+ private void notifyPhoneAsInCall(Phone phone) {
+ doReturn(mActiveCall).when(phone).getForegroundCall();
+ mPhoneSwitcher.mPhoneStateListener.onPreciseCallStateChanged(null);
+ waitABit();
+ }
+
+ private void notifyPhoneAsInactive(Phone phone) {
+ doReturn(mInactiveCall).when(phone).getForegroundCall();
+ mPhoneSwitcher.mPhoneStateListener.onPreciseCallStateChanged(null);
+ waitABit();
+ }
+
+ private Message getEcbmRegistration(Phone phone) {
+ ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
+ ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class);
+
+ verify(phone).registerForEmergencyCallToggle(handlerCaptor.capture(), intCaptor.capture(),
+ any());
+ assertNotNull(handlerCaptor.getValue());
+ assertNotNull(intCaptor.getValue());
+ Message message = Message.obtain(handlerCaptor.getValue(), intCaptor.getValue());
+ return message;
+ }
+
+ private void notifyEcbmStart(Phone phone, Message ecmMessage) {
+ doReturn(mInactiveCall).when(phone).getForegroundCall();
+ doReturn(true).when(phone).isInEcm();
+ ecmMessage.sendToTarget();
+ waitABit();
+ }
+
+ private void notifyEcbmEnd(Phone phone, Message ecmMessage) {
+ doReturn(false).when(phone).isInEcm();
+ ecmMessage.sendToTarget();
+ waitABit();
+ }
+
+ private void sendPreferredDataSuccessResult(int phoneId) {
+ // make sure the radio command is called and then send a success result
+ ArgumentCaptor<Message> msgCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mMockRadioConfig, timeout(500)).setPreferredDataModem(eq(phoneId),
+ msgCaptor.capture());
+ assertNotNull(msgCaptor.getValue());
+ // Send back successful result
+ AsyncResult.forMessage(msgCaptor.getValue(), null, null);
+ msgCaptor.getValue().sendToTarget();
+ waitABit();
+ }
+
+ private void setMsimDefaultDataSubId(int numPhones, int defaultDataSub) throws Exception {
+ for (int i = 0; i < numPhones; i++) {
+ setSlotIndexToSubId(i, i + 1);
+ }
+ setDefaultDataSubId(defaultDataSub);
+ waitABit();
+ NetworkRequest internetRequest = addInternetNetworkRequest(null, 50);
+ waitABit();
+ for (int i = 0; i < numPhones; i++) {
+ if (defaultDataSub == (i + 1)) {
+ // sub id is always phoneId+1 for testing
+ assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, i));
+ } else {
+ assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest(internetRequest, i));
+ }
+ }
+ }
+
private void sendDefaultDataSubChanged() {
final Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
mContext.sendBroadcast(intent);