Merge "Move emergency call to main thread" into sc-dev
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 824bb4b..2e82743 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -28,9 +28,6 @@
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
import android.os.ParcelUuid;
import android.telecom.Conference;
import android.telecom.Connection;
@@ -87,7 +84,7 @@
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
@@ -176,8 +173,6 @@
// destroyed.
@VisibleForTesting
public Pair<WeakReference<TelephonyConnection>, Queue<Phone>> mEmergencyRetryCache;
- private Handler mDdsSwitchHandler;
- private HandlerThread mHandlerThread;
private DeviceState mDeviceState = new DeviceState();
/**
@@ -364,27 +359,6 @@
};
/**
- * Factory for Handler creation in order to remove flakiness during t esting.
- */
- @VisibleForTesting
- public interface HandlerFactory {
- HandlerThread createHandlerThread(String name);
- Handler createHandler(Looper looper);
- }
-
- private HandlerFactory mHandlerFactory = new HandlerFactory() {
- @Override
- public HandlerThread createHandlerThread(String name) {
- return new HandlerThread(name);
- }
-
- @Override
- public Handler createHandler(Looper looper) {
- return new Handler(looper);
- }
- };
-
- /**
* DisconnectCause depends on PhoneGlobals in order to get a system context. Mock out
* dependency for testing.
*/
@@ -475,14 +449,6 @@
}
/**
- * Override Handler creation factory for testing.
- */
- @VisibleForTesting
- public void setHandlerFactory(HandlerFactory handlerFactory) {
- mHandlerFactory = handlerFactory;
- }
-
- /**
* Override DisconnectCause creation for testing.
*/
@VisibleForTesting
@@ -533,16 +499,11 @@
IntentFilter intentFilter = new IntentFilter(
TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
registerReceiver(mTtyBroadcastReceiver, intentFilter);
- mHandlerThread = mHandlerFactory.createHandlerThread("DdsSwitchHandlerThread");
- mHandlerThread.start();
- Looper looper = mHandlerThread.getLooper();
- mDdsSwitchHandler = mHandlerFactory.createHandler(looper);
}
@Override
public boolean onUnbind(Intent intent) {
unregisterReceiver(mTtyBroadcastReceiver);
- mHandlerThread.quitSafely();
return super.onUnbind(intent);
}
@@ -876,14 +837,9 @@
} else {
final Connection resultConnection = getTelephonyConnection(request, numberToDial,
true, handle, phone);
- mDdsSwitchHandler.post(new Runnable() {
- @Override
- public void run() {
- boolean result = delayDialForDdsSwitch(phone);
- Log.i(this,
- "onCreateOutgoingConn - delayDialForDdsSwitch result = " + result);
+ delayDialForDdsSwitch(phone, (result) -> {
+ Log.i(this, "onCreateOutgoingConn - delayDialForDdsSwitch result = " + result);
placeOutgoingConnection(request, resultConnection, phone);
- }
});
return resultConnection;
}
@@ -965,18 +921,14 @@
adjustAndPlaceOutgoingConnection(phone, originalConnection, request, numberToDial,
handle, originalPhoneType, false);
} else {
- mDdsSwitchHandler.post(new Runnable() {
- @Override
- public void run() {
- boolean result = delayDialForDdsSwitch(phone);
- Log.i(this, "handleOnComplete - delayDialForDdsSwitch result = " + result);
- adjustAndPlaceOutgoingConnection(phone, originalConnection, request,
- numberToDial, handle, originalPhoneType, true);
- mIsEmergencyCallPending = false;
- }
+ delayDialForDdsSwitch(phone, result -> {
+ Log.i(this, "handleOnComplete - delayDialForDdsSwitch "
+ + "result = " + result);
+ adjustAndPlaceOutgoingConnection(phone, originalConnection, request,
+ numberToDial, handle, originalPhoneType, true);
+ mIsEmergencyCallPending = false;
});
}
-
} else {
Log.w(this, "onCreateOutgoingConnection, failed to turn on radio");
closeOrDestroyConnection(originalConnection,
@@ -1978,18 +1930,32 @@
/**
* If needed, block until the the default data is is switched for outgoing emergency call, or
* timeout expires.
+ * @param phone The Phone to switch the DDS on.
+ * @param completeConsumer The consumer to call once the default data subscription has been
+ * switched, provides {@code true} result if the switch happened
+ * successfully or {@code false} if the operation timed out/failed.
*/
- private boolean delayDialForDdsSwitch(Phone phone) {
+ private void delayDialForDdsSwitch(Phone phone, Consumer<Boolean> completeConsumer) {
if (phone == null) {
- return true;
+ // Do not block indefinitely.
+ completeConsumer.accept(false);
}
try {
- return possiblyOverrideDefaultDataForEmergencyCall(phone).get(
- DEFAULT_DATA_SWITCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ // Waiting for PhoneSwitcher to complete the operation.
+ CompletableFuture<Boolean> future = possiblyOverrideDefaultDataForEmergencyCall(phone);
+ // In the case that there is an issue or bug in PhoneSwitcher logic, do not wait
+ // indefinitely for the future to complete. Instead, set a timeout that will complete
+ // the future as to not block the outgoing call indefinitely.
+ CompletableFuture<Boolean> timeout = new CompletableFuture<>();
+ phone.getContext().getMainThreadHandler().postDelayed(
+ () -> timeout.complete(false), DEFAULT_DATA_SWITCH_TIMEOUT_MS);
+ // Also ensure that the Consumer is completed on the main thread.
+ future.acceptEitherAsync(timeout, completeConsumer,
+ phone.getContext().getMainExecutor());
} catch (Exception e) {
Log.w(this, "delayDialForDdsSwitch - exception= "
+ e.getMessage());
- return false;
+
}
}
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 84ab543..898b5ad 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -26,7 +26,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -43,8 +42,6 @@
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
import android.telecom.ConnectionRequest;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccountHandle;
@@ -128,7 +125,6 @@
@Mock TelephonyConnectionService.PhoneSwitcherProxy mPhoneSwitcherProxy;
@Mock TelephonyConnectionService.PhoneNumberUtilsProxy mPhoneNumberUtilsProxy;
@Mock TelephonyConnectionService.PhoneUtilsProxy mPhoneUtilsProxy;
- @Mock TelephonyConnectionService.HandlerFactory mHandlerFactory;
@Mock TelephonyConnectionService.DisconnectCauseFactory mDisconnectCauseFactory;
@Mock Handler mMockHandler;
@Mock EmergencyNumberTracker mEmergencyNumberTracker;
@@ -175,11 +171,6 @@
.thenAnswer(invocation -> invocation.getArgument(1));
mTestConnectionService.setPhoneNumberUtilsProxy(mPhoneNumberUtilsProxy);
mTestConnectionService.setPhoneUtilsProxy(mPhoneUtilsProxy);
- HandlerThread mockHandlerThread = mock(HandlerThread.class);
- doReturn(mockHandlerThread).when(mHandlerFactory).createHandlerThread(anyString());
- doReturn(null).when(mockHandlerThread).getLooper();
- doReturn(mMockHandler).when(mHandlerFactory).createHandler(any());
- mTestConnectionService.setHandlerFactory(mHandlerFactory);
mTestConnectionService.setDeviceState(mDeviceState);
mTestConnectionService.setRadioOnHelper(mRadioOnHelper);
doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
@@ -960,22 +951,20 @@
@Test
@SmallTest
public void testCreateOutgoingEmergencyConnection_delayDial_carrierconfig_dds() {
- Phone testPhone = setupConnectionServiceForDelayDial();
- Runnable delayDialRunnable = verifyRunnablePosted();
-
// Setup test to not support SUPL on the non-DDS subscription
doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
null);
- testPhone.getServiceState().setRoaming(false);
getTestContext().getCarrierConfig(0 /*subId*/).putInt(
CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
getTestContext().getCarrierConfig(0 /*subId*/).putString(
CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "150");
- delayDialRunnable.run();
+ Phone testPhone = setupConnectionServiceForDelayDial(
+ false /* isRoaming */, false /* setOperatorName */, null /* operator long name*/,
+ null /* operator short name */, null /* operator numeric name */);
verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
eq(150) /*extensionTime*/, any());
}
@@ -1026,11 +1015,9 @@
assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
callback.getValue().onComplete(null, true);
- Runnable delayDialRunnable = verifyRunnablePosted();
try {
doAnswer(invocation -> null).when(mContext).startActivity(any());
- delayDialRunnable.run();
verify(testPhone).dial(anyString(), any());
} catch (CallStateException e) {
// This shouldn't happen
@@ -1045,22 +1032,20 @@
@Test
@SmallTest
public void testCreateOutgoingEmergencyConnection_delayDial_nocarrierconfig() {
- Phone testPhone = setupConnectionServiceForDelayDial();
- Runnable delayDialRunnable = verifyRunnablePosted();
-
// Setup test to not support SUPL on the non-DDS subscription
doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
null);
- testPhone.getServiceState().setRoaming(false);
getTestContext().getCarrierConfig(0 /*subId*/).putInt(
CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
getTestContext().getCarrierConfig(0 /*subId*/).putString(
CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
- delayDialRunnable.run();
+ Phone testPhone = setupConnectionServiceForDelayDial(
+ false /* isRoaming */, false /* setOperatorName */, null /* operator long name*/,
+ null /* operator short name */, null /* operator numeric name */);
verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
}
@@ -1071,22 +1056,20 @@
@Test
@SmallTest
public void testCreateOutgoingEmergencyConnection_delayDial_supportsuplondds() {
- Phone testPhone = setupConnectionServiceForDelayDial();
- Runnable delayDialRunnable = verifyRunnablePosted();
-
// If the non-DDS supports SUPL, dont switch data
doReturn(false).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
null);
- testPhone.getServiceState().setRoaming(false);
getTestContext().getCarrierConfig(0 /*subId*/).putInt(
CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
getTestContext().getCarrierConfig(0 /*subId*/).putString(
CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
- delayDialRunnable.run();
+ Phone testPhone = setupConnectionServiceForDelayDial(
+ false /* isRoaming */, false /* setOperatorName */, null /* operator long name*/,
+ null /* operator short name */, null /* operator numeric name */);
verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
}
@@ -1097,22 +1080,20 @@
@Test
@SmallTest
public void testCreateOutgoingEmergencyConnection_delayDial_roaming_nocarrierconfig() {
- Phone testPhone = setupConnectionServiceForDelayDial();
- Runnable delayDialRunnable = verifyRunnablePosted();
-
// Setup test to not support SUPL on the non-DDS subscription
doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
null);
- testPhone.getServiceState().setRoaming(true);
getTestContext().getCarrierConfig(0 /*subId*/).putInt(
CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
getTestContext().getCarrierConfig(0 /*subId*/).putString(
CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
- delayDialRunnable.run();
+ Phone testPhone = setupConnectionServiceForDelayDial(
+ true /* isRoaming */, false /* setOperatorName */, null /* operator long name*/,
+ null /* operator short name */, null /* operator numeric name */);
verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
}
@@ -1124,16 +1105,10 @@
@Test
@SmallTest
public void testCreateOutgoingEmergencyConnection_delayDial_roamingcarrierconfig() {
- Phone testPhone = setupConnectionServiceForDelayDial();
- Runnable delayDialRunnable = verifyRunnablePosted();
-
+ doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
// Setup voice roaming scenario
String testRoamingOperator = "001001";
- // In some roaming conditions, we are not technically "roaming"
- testPhone.getServiceState().setRoaming(false);
- testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator);
// Setup test to not support SUPL on the non-DDS subscription
- doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
String[] roamingPlmns = new String[1];
roamingPlmns[0] = testRoamingOperator;
getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
@@ -1144,8 +1119,11 @@
CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
getTestContext().getCarrierConfig(0 /*subId*/).putString(
CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
- delayDialRunnable.run();
+ Phone testPhone = setupConnectionServiceForDelayDial(
+ false /* isRoaming */, true /* setOperatorName */,
+ "TestTel" /* operator long name*/, "TestTel" /* operator short name */,
+ testRoamingOperator /* operator numeric name */);
verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
eq(0) /*extensionTime*/, any());
}
@@ -1158,15 +1136,10 @@
@Test
@SmallTest
public void testCreateOutgoingEmergencyConnection_delayDial__roaming_roamingcarrierconfig() {
- Phone testPhone = setupConnectionServiceForDelayDial();
- Runnable delayDialRunnable = verifyRunnablePosted();
-
- // Setup voice roaming scenario
- String testRoamingOperator = "001001";
- testPhone.getServiceState().setRoaming(true);
- testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator);
// Setup test to not support SUPL on the non-DDS subscription
doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+ // Setup voice roaming scenario
+ String testRoamingOperator = "001001";
String[] roamingPlmns = new String[1];
roamingPlmns[0] = testRoamingOperator;
getTestContext().getCarrierConfig(0 /*subId*/).putStringArray(
@@ -1177,8 +1150,11 @@
CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
getTestContext().getCarrierConfig(0 /*subId*/).putString(
CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
- delayDialRunnable.run();
+ Phone testPhone = setupConnectionServiceForDelayDial(
+ false /* isRoaming */, true /* setOperatorName */,
+ "TestTel" /* operator long name*/, "TestTel" /* operator short name */,
+ testRoamingOperator /* operator numeric name */);
verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
eq(0) /*extensionTime*/, any());
}
@@ -1383,9 +1359,16 @@
/**
* Set up a mock MSIM device with TEST_ADDRESS set as an emergency number.
+ * @param isRoaming whether it is roaming
+ * @param setOperatorName whether operator name needs to set
+ * @param operatorNameLongName the operator long name if needs to set
+ * @param operatorNameShortName the operator short name if needs to set
+ * @param operatorNameNumeric the operator numeric name if needs to set
* @return the Phone associated with slot 0.
*/
- private Phone setupConnectionServiceForDelayDial() {
+ private Phone setupConnectionServiceForDelayDial(boolean isRoaming, boolean setOperatorName,
+ String operatorNameLongName, String operatorNameShortName,
+ String operatorNameNumeric) {
ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
.setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
.setAddress(TEST_ADDRESS)
@@ -1410,15 +1393,17 @@
emergencyNumbers.put(0 /*subId*/, numbers);
doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
-
+ testPhone0.getServiceState().setRoaming(isRoaming);
+ if (setOperatorName) {
+ testPhone0.getServiceState().setOperatorName(operatorNameLongName,
+ operatorNameShortName, operatorNameNumeric);
+ }
mConnection = mTestConnectionService.onCreateOutgoingConnection(
PHONE_ACCOUNT_HANDLE_1, connectionRequest);
assertNotNull("test connection was not set up correctly.", mConnection);
-
return testPhone0;
}
-
/**
* Set up a mock MSIM device with TEST_ADDRESS set as an emergency number in airplane mode.
* @return the Phone associated with slot 0.
@@ -1458,15 +1443,6 @@
return testPhone0;
}
- private Runnable verifyRunnablePosted() {
- ArgumentCaptor<Message> runnableCaptor = ArgumentCaptor.forClass(Message.class);
- verify(mMockHandler).sendMessageDelayed(runnableCaptor.capture(), anyLong());
- assertNotNull("Invalid Message created", runnableCaptor.getValue());
- Runnable runnable = runnableCaptor.getValue().getCallback();
- assertNotNull("sendMessageDelayed never occurred.", runnableCaptor);
- return runnable;
- }
-
private EmergencyNumber setupEmergencyNumber(Uri address) {
return new EmergencyNumber(address.getSchemeSpecificPart(), "", "",
EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,