Add emergency SUPL DDS switch for DP only roaming partners
Although an operator may support control plane fallback for
emergency SUPL requests, a roaming operator may not. Define
a new CarrierConfig for known roaming partners of an operator
that do not support CP fallback and in those cases, perform
a DDS switch before placing the emergency call if possible.
Bug: 144383368
Test: manual; atest TeleServiceTests
Merged-In: I7bd81ddb9730cd2cff7c246f0321af090eb6b2c6
Change-Id: I7bd81ddb9730cd2cff7c246f0321af090eb6b2c6
diff --git a/src/com/android/services/telephony/DeviceState.java b/src/com/android/services/telephony/DeviceState.java
new file mode 100644
index 0000000..7cd2d7e
--- /dev/null
+++ b/src/com/android/services/telephony/DeviceState.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.telecom.TelecomManager;
+
+import com.android.internal.telephony.PhoneConstants;
+import com.android.phone.R;
+
+/**
+ * Abstracts device state and settings for better testability.
+ */
+public class DeviceState {
+
+ public boolean shouldCheckSimStateBeforeOutgoingCall(Context context) {
+ return context.getResources().getBoolean(
+ R.bool.config_checkSimStateBeforeOutgoingCall);
+ }
+
+ public boolean isSuplDdsSwitchRequiredForEmergencyCall(Context context) {
+ return context.getResources().getBoolean(
+ R.bool.config_gnss_supl_requires_default_data_for_emergency);
+ }
+
+ public boolean isRadioPowerDownAllowedOnBluetooth(Context context) {
+ return context.getResources().getBoolean(R.bool.config_allowRadioPowerDownOnBluetooth);
+ }
+
+ public boolean isAirplaneModeOn(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) > 0;
+ }
+
+ public int getCellOnStatus(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(), Settings.Global.CELL_ON,
+ PhoneConstants.CELL_ON_FLAG);
+ }
+
+ public boolean isTtyModeEnabled(Context context) {
+ return android.provider.Settings.Secure.getInt(context.getContentResolver(),
+ android.provider.Settings.Secure.PREFERRED_TTY_MODE,
+ TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF;
+ }
+}
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 996c8ea..38672a8 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -1340,7 +1340,7 @@
b.getBoolean(CarrierConfigManager.KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL);
}
- private PersistableBundle getCarrierConfig() {
+ public PersistableBundle getCarrierConfig() {
Phone phone = getPhone();
if (phone == null) {
return null;
@@ -2188,7 +2188,7 @@
* 3. If call is a video call, carrier supports video conference calls.
* 4. If call is a wifi call and VoWIFI is disabled and carrier supports merging these calls.
*/
- private void refreshConferenceSupported() {
+ void refreshConferenceSupported() {
boolean isVideoCall = VideoProfile.isVideo(getVideoState());
Phone phone = getPhone();
if (phone == null) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 6637e19..c517cd8 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -156,12 +156,7 @@
new TelephonyConferenceController(mTelephonyConnectionServiceProxy);
private final CdmaConferenceController mCdmaConferenceController =
new CdmaConferenceController(this);
- private final ImsConferenceController mImsConferenceController =
- new ImsConferenceController(TelecomAccountRegistry.getInstance(this),
- mTelephonyConnectionServiceProxy,
- // FeatureFlagProxy; used to determine if standalone call emulation is enabled.
- // TODO: Move to carrier config
- () -> true);
+ private ImsConferenceController mImsConferenceController;
private ComponentName mExpectedComponentName = null;
private RadioOnHelper mRadioOnHelper;
@@ -176,6 +171,7 @@
// destroyed.
@VisibleForTesting
public Pair<WeakReference<TelephonyConnection>, Queue<Phone>> mEmergencyRetryCache;
+ private DeviceState mDeviceState = new DeviceState();
/**
* Keeps track of the status of a SIM slot.
@@ -195,7 +191,10 @@
}
}
- // SubscriptionManager Proxy interface for testing
+ /**
+ * SubscriptionManager dependencies for testing.
+ */
+ @VisibleForTesting
public interface SubscriptionManagerProxy {
int getDefaultVoicePhoneId();
int getSimStateForSlotIdx(int slotId);
@@ -219,7 +218,9 @@
}
};
- // TelephonyManager Proxy interface for testing
+ /**
+ * TelephonyManager dependencies for testing.
+ */
@VisibleForTesting
public interface TelephonyManagerProxy {
int getPhoneCount();
@@ -259,7 +260,9 @@
}
}
- //PhoneFactory proxy interface for testing
+ /**
+ * PhoneFactory Dependencies for testing.
+ */
@VisibleForTesting
public interface PhoneFactoryProxy {
Phone getPhone(int index);
@@ -284,22 +287,156 @@
}
};
+ /**
+ * PhoneUtils dependencies for testing.
+ */
+ @VisibleForTesting
+ public interface PhoneUtilsProxy {
+ int getSubIdForPhoneAccountHandle(PhoneAccountHandle accountHandle);
+ PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone);
+ PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(Phone phone, String prefix,
+ boolean isEmergency);
+ }
+
+ private PhoneUtilsProxy mPhoneUtilsProxy = new PhoneUtilsProxy() {
+ @Override
+ public int getSubIdForPhoneAccountHandle(PhoneAccountHandle accountHandle) {
+ return PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle);
+ }
+
+ @Override
+ public PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) {
+ return PhoneUtils.makePstnPhoneAccountHandle(phone);
+ }
+
+ @Override
+ public PhoneAccountHandle makePstnPhoneAccountHandleWithPrefix(Phone phone, String prefix,
+ boolean isEmergency) {
+ return PhoneUtils.makePstnPhoneAccountHandleWithPrefix(phone, prefix, isEmergency);
+ }
+ };
+
+ /**
+ * PhoneNumberUtils dependencies for testing.
+ */
+ @VisibleForTesting
+ public interface PhoneNumberUtilsProxy {
+ String convertToEmergencyNumber(Context context, String number);
+ }
+
+ private PhoneNumberUtilsProxy mPhoneNumberUtilsProxy = new PhoneNumberUtilsProxy() {
+ @Override
+ public String convertToEmergencyNumber(Context context, String number) {
+ return PhoneNumberUtils.convertToEmergencyNumber(context, number);
+ }
+ };
+
+ /**
+ * PhoneSwitcher dependencies for testing.
+ */
+ @VisibleForTesting
+ public interface PhoneSwitcherProxy {
+ PhoneSwitcher getPhoneSwitcher();
+ }
+
+ private PhoneSwitcherProxy mPhoneSwitcherProxy = new PhoneSwitcherProxy() {
+ @Override
+ public PhoneSwitcher getPhoneSwitcher() {
+ return PhoneSwitcher.getInstance();
+ }
+ };
+
+ /**
+ * DisconnectCause depends on PhoneGlobals in order to get a system context. Mock out
+ * dependency for testing.
+ */
+ @VisibleForTesting
+ public interface DisconnectCauseFactory {
+ DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause, String reason);
+ DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause,
+ String reason, int phoneId);
+ }
+
+ private DisconnectCauseFactory mDisconnectCauseFactory = new DisconnectCauseFactory() {
+ @Override
+ public DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause,
+ String reason) {
+ return DisconnectCauseUtil.toTelecomDisconnectCause(telephonyDisconnectCause, reason);
+ }
+
+ @Override
+ public DisconnectCause toTelecomDisconnectCause(int telephonyDisconnectCause, String reason,
+ int phoneId) {
+ return DisconnectCauseUtil.toTelecomDisconnectCause(telephonyDisconnectCause, reason,
+ phoneId);
+ }
+ };
+
+ /**
+ * Overrides SubscriptionManager dependencies for testing.
+ */
@VisibleForTesting
public void setSubscriptionManagerProxy(SubscriptionManagerProxy proxy) {
mSubscriptionManagerProxy = proxy;
}
+ /**
+ * Overrides TelephonyManager dependencies for testing.
+ */
@VisibleForTesting
public void setTelephonyManagerProxy(TelephonyManagerProxy proxy) {
mTelephonyManagerProxy = proxy;
}
+ /**
+ * Overrides PhoneFactory dependencies for testing.
+ */
@VisibleForTesting
public void setPhoneFactoryProxy(PhoneFactoryProxy proxy) {
mPhoneFactoryProxy = proxy;
}
/**
+ * Overrides configuration and settings dependencies for testing.
+ */
+ @VisibleForTesting
+ public void setDeviceState(DeviceState state) {
+ mDeviceState = state;
+ }
+
+ /**
+ * Overrides PhoneSwitcher dependencies for testing.
+ */
+ @VisibleForTesting
+ public void setPhoneSwitcherProxy(PhoneSwitcherProxy proxy) {
+ mPhoneSwitcherProxy = proxy;
+ }
+
+ /**
+ * Overrides PhoneNumberUtils dependencies for testing.
+ */
+ @VisibleForTesting
+ public void setPhoneNumberUtilsProxy(PhoneNumberUtilsProxy proxy) {
+ mPhoneNumberUtilsProxy = proxy;
+ }
+
+ /**
+ * Overrides PhoneUtils dependencies for testing.
+ */
+ @VisibleForTesting
+ public void setPhoneUtilsProxy(PhoneUtilsProxy proxy) {
+ mPhoneUtilsProxy = proxy;
+ }
+
+ /**
+ * Override DisconnectCause creation for testing.
+ */
+ @VisibleForTesting
+ public void setDisconnectCauseFactory(DisconnectCauseFactory factory) {
+ mDisconnectCauseFactory = factory;
+ }
+
+ /**
* A listener to actionable events specific to the TelephonyConnection.
*/
private final TelephonyConnection.TelephonyConnectionListener mTelephonyConnectionListener =
@@ -319,12 +456,18 @@
public void onCreate() {
super.onCreate();
Log.initLogging(this);
+ mImsConferenceController = new ImsConferenceController(
+ TelecomAccountRegistry.getInstance(this),
+ mTelephonyConnectionServiceProxy,
+ // FeatureFlagProxy; used to determine if standalone call emulation is enabled.
+ // TODO: Move to carrier config
+ () -> true);
setTelephonyManagerProxy(new TelephonyManagerProxyImpl(getApplicationContext()));
mExpectedComponentName = new ComponentName(this, this.getClass());
mEmergencyTonePlayer = new EmergencyTonePlayer(this);
TelecomAccountRegistry.getInstance(this).setTelephonyConnectionService(this);
mHoldTracker = new HoldTracker();
- mIsTtyEnabled = isTtyModeEnabled(getApplicationContext());
+ mIsTtyEnabled = mDeviceState.isTtyModeEnabled(this);
IntentFilter intentFilter = new IntentFilter(
TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
@@ -347,7 +490,7 @@
if (handle == null) {
Log.d(this, "onCreateOutgoingConnection, handle is null");
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.NO_PHONE_NUMBER_SUPPLIED,
"No phone number supplied"));
}
@@ -362,7 +505,7 @@
if (phone == null) {
Log.d(this, "onCreateOutgoingConnection, phone is null");
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUT_OF_SERVICE,
"Phone is null"));
}
@@ -370,7 +513,7 @@
if (TextUtils.isEmpty(number)) {
Log.d(this, "onCreateOutgoingConnection, no voicemail number set.");
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.VOICEMAIL_NUMBER_MISSING,
"Voicemail scheme provided but no voicemail number set.",
phone.getPhoneId()));
@@ -382,7 +525,7 @@
if (!PhoneAccount.SCHEME_TEL.equals(scheme)) {
Log.d(this, "onCreateOutgoingConnection, Handle %s is not type tel", scheme);
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.INVALID_NUMBER,
"Handle scheme is not type tel"));
}
@@ -391,7 +534,7 @@
if (TextUtils.isEmpty(number)) {
Log.d(this, "onCreateOutgoingConnection, unable to parse number");
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.INVALID_NUMBER,
"Unable to parse number"));
}
@@ -412,7 +555,7 @@
if (disableActivation) {
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause
.CDMA_ALREADY_ACTIVATED,
"Tried to dial *228",
@@ -436,7 +579,8 @@
// service.
if (phone == null || phone.getServiceState().getState()
!= ServiceState.STATE_IN_SERVICE) {
- String convertedNumber = PhoneNumberUtils.convertToEmergencyNumber(this, number);
+ String convertedNumber = mPhoneNumberUtilsProxy.convertToEmergencyNumber(this,
+ number);
if (!TextUtils.equals(convertedNumber, number)) {
Log.i(this, "onCreateOutgoingConnection, converted to emergency number");
number = convertedNumber;
@@ -447,8 +591,7 @@
final String numberToDial = number;
- final boolean isAirplaneModeOn = Settings.Global.getInt(getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) > 0;
+ final boolean isAirplaneModeOn = mDeviceState.isAirplaneModeOn(this);
boolean needToTurnOnRadio = (isEmergencyNumber && (!isRadioOn() || isAirplaneModeOn))
|| isRadioPowerDownOnBluetooth();
@@ -457,7 +600,7 @@
final Uri resultHandle = handle;
// By default, Connection based on the default Phone, since we need to return to Telecom
// now.
- final int originalPhoneType = PhoneFactory.getDefaultPhone().getPhoneType();
+ final int originalPhoneType = mPhoneFactoryProxy.getDefaultPhone().getPhoneType();
final Connection resultConnection = getTelephonyConnection(request, numberToDial,
isEmergencyNumber, resultHandle, PhoneFactory.getDefaultPhone());
if (mRadioOnHelper == null) {
@@ -571,12 +714,8 @@
* Whether the cellular radio is power off because the device is on Bluetooth.
*/
private boolean isRadioPowerDownOnBluetooth() {
- final Context context = getApplicationContext();
- final boolean allowed = context.getResources().getBoolean(
- R.bool.config_allowRadioPowerDownOnBluetooth);
- final int cellOn = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.CELL_ON,
- PhoneConstants.CELL_ON_FLAG);
+ final boolean allowed = mDeviceState.isRadioPowerDownAllowedOnBluetooth(this);
+ final int cellOn = mDeviceState.getCellOnStatus(this);
return (allowed && cellOn == PhoneConstants.CELL_ON_FLAG && !isRadioOn());
}
@@ -615,7 +754,7 @@
} else {
Log.w(this, "onCreateOutgoingConnection, failed to turn on radio");
originalConnection.setDisconnected(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.POWER_OFF,
"Failed to turn on radio."));
originalConnection.destroy();
@@ -641,11 +780,11 @@
boolean noActiveSimCard = SubscriptionController.getInstance()
.getActiveSubInfoCount(phone.getContext().getOpPackageName()) == 0;
// If there's no active sim card and the device is in emergency mode, use E account.
- addExistingConnection(PhoneUtils.makePstnPhoneAccountHandleWithPrefix(
+ addExistingConnection(mPhoneUtilsProxy.makePstnPhoneAccountHandleWithPrefix(
phone, "", isEmergencyNumber && noActiveSimCard), repConnection);
// Remove the old connection from Telecom after.
connectionToEvaluate.setDisconnected(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUTGOING_CANCELED,
"Reconnecting outgoing Emergency Call.",
phone.getPhoneId()));
@@ -675,7 +814,7 @@
if (phone == null) {
final Context context = getApplicationContext();
- if (context.getResources().getBoolean(R.bool.config_checkSimStateBeforeOutgoingCall)) {
+ if (mDeviceState.shouldCheckSimStateBeforeOutgoingCall(this)) {
// Check SIM card state before the outgoing call.
// Start the SIM unlock activity if PIN_REQUIRED.
final Phone defaultPhone = mPhoneFactoryProxy.getDefaultPhone();
@@ -700,7 +839,7 @@
}
}
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUT_OF_SERVICE,
"SIM_STATE_PIN_REQUIRED"));
}
@@ -708,7 +847,7 @@
Log.d(this, "onCreateOutgoingConnection, phone is null");
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUT_OF_SERVICE, "Phone is null"));
}
@@ -736,7 +875,7 @@
if (!allowNonEmergencyCalls) {
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.CDMA_NOT_EMERGENCY,
"Cannot make non-emergency call in ECM mode.",
phone.getPhoneId()));
@@ -754,7 +893,7 @@
break;
} else {
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUT_OF_SERVICE,
"ServiceState.STATE_OUT_OF_SERVICE",
phone.getPhoneId()));
@@ -765,25 +904,25 @@
break;
}
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.POWER_OFF,
"ServiceState.STATE_POWER_OFF",
phone.getPhoneId()));
default:
Log.d(this, "onCreateOutgoingConnection, unknown service state: %d", state);
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUTGOING_FAILURE,
"Unknown service state " + state,
phone.getPhoneId()));
}
}
- final Context context = getApplicationContext();
- final boolean isTtyModeEnabled = isTtyModeEnabled(context);
+ final boolean isTtyModeEnabled = mDeviceState.isTtyModeEnabled(this);
if (VideoProfile.isVideo(request.getVideoState()) && isTtyModeEnabled
&& !isEmergencyNumber) {
- return Connection.createFailedConnection(DisconnectCauseUtil.toTelecomDisconnectCause(
+ return Connection.createFailedConnection(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED,
null, phone.getPhoneId()));
}
@@ -797,7 +936,7 @@
// Check roaming status to see if we should block custom call forwarding codes
if (blockCallForwardingNumberWhileRoaming(phone, number)) {
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.DIALED_CALL_FORWARDING_WHILE_ROAMING,
"Call forwarding while roaming",
phone.getPhoneId()));
@@ -809,7 +948,7 @@
request.getTelecomCallId(), request.getAddress(), request.getVideoState());
if (connection == null) {
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.OUTGOING_FAILURE,
"Invalid phone type",
phone.getPhoneId()));
@@ -842,7 +981,7 @@
request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
if (phone == null) {
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.ERROR_UNSPECIFIED,
"Phone is null"));
}
@@ -851,7 +990,7 @@
if (!call.getState().isRinging()) {
Log.i(this, "onCreateIncomingConnection, no ringing call");
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.INCOMING_MISSED,
"Found no ringing call",
phone.getPhoneId()));
@@ -955,7 +1094,7 @@
request.getAddress() == null ? null : request.getAddress().getSchemeSpecificPart());
if (phone == null) {
return Connection.createFailedConnection(
- DisconnectCauseUtil.toTelecomDisconnectCause(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.ERROR_UNSPECIFIED,
"Phone is null"));
}
@@ -1211,7 +1350,7 @@
}
private void updatePhoneAccount(TelephonyConnection connection, Phone phone) {
- PhoneAccountHandle pHandle = PhoneUtils.makePstnPhoneAccountHandle(phone);
+ PhoneAccountHandle pHandle = mPhoneUtilsProxy.makePstnPhoneAccountHandle(phone);
// For ECall handling on MSIM, until the request reaches here (i.e PhoneApp), we don't know
// on which phone account ECall can be placed. After deciding, we should notify Telecom of
// the change so that the proper PhoneAccount can be displayed.
@@ -1263,7 +1402,7 @@
cause = android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS;
break;
}
- connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+ connection.setDisconnected(mDisconnectCauseFactory.toTelecomDisconnectCause(
cause, e.getMessage(), phone.getPhoneId()));
connection.clearOriginalConnection();
connection.destroy();
@@ -1287,7 +1426,7 @@
startActivity(intent);
}
Log.d(this, "placeOutgoingConnection, phone.dial returned null");
- connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+ connection.setDisconnected(mDisconnectCauseFactory.toTelecomDisconnectCause(
telephonyDisconnectCause, "Connection is null", phone.getPhoneId()));
connection.clearOriginalConnection();
connection.destroy();
@@ -1354,7 +1493,7 @@
private Phone getPhoneForAccount(PhoneAccountHandle accountHandle, boolean isEmergency,
@Nullable String emergencyNumberAddress) {
Phone chosenPhone = null;
- int subId = PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle);
+ int subId = mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(accountHandle);
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
int phoneId = mSubscriptionManagerProxy.getPhoneId(subId);
chosenPhone = mPhoneFactoryProxy.getPhone(phoneId);
@@ -1395,13 +1534,21 @@
*/
private CompletableFuture<Boolean> possiblyOverrideDefaultDataForEmergencyCall(
@NonNull Phone phone) {
- TelephonyManager telephony = TelephonyManager.from(phone.getContext());
- int phoneCount = telephony.getPhoneCount();
+ int phoneCount = mTelephonyManagerProxy.getPhoneCount();
// Do not override DDS if this is a single SIM device.
if (phoneCount <= PhoneConstants.MAX_PHONE_COUNT_SINGLE_SIM) {
return CompletableFuture.completedFuture(Boolean.TRUE);
}
+ // Do not switch Default data if this device supports emergency SUPL on non-DDS.
+ final boolean gnssSuplRequiresDefaultData =
+ mDeviceState.isSuplDdsSwitchRequiredForEmergencyCall(this);
+ if (!gnssSuplRequiresDefaultData) {
+ Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, does not "
+ + "require DDS switch.");
+ return CompletableFuture.completedFuture(Boolean.TRUE);
+ }
+
CarrierConfigManager cfgManager = (CarrierConfigManager)
phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (cfgManager == null) {
@@ -1410,34 +1557,41 @@
+ "CarrierConfigManager");
return CompletableFuture.completedFuture(Boolean.TRUE);
}
- // Only override default data if we are IN_SERVICE and on a home network. We don't want to
- // perform a DDS switch of we are on a roaming network, where SUPL may not be available.
- boolean isPhoneAvailableForEmergency = isAvailableForEmergencyCalls(phone);
+
+ // Only override default data if we are IN_SERVICE already.
+ if (!isAvailableForEmergencyCalls(phone)) {
+ Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS");
+ return CompletableFuture.completedFuture(Boolean.TRUE);
+ }
+
+ // Only override default data if we are not roaming, we do not want to switch onto a network
+ // that only supports data plane only (if we do not know).
boolean isRoaming = phone.getServiceState().getVoiceRoaming();
- if (!isPhoneAvailableForEmergency || isRoaming) {
- Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, avail = "
- + isPhoneAvailableForEmergency + ", roaming = " + isRoaming);
+ // In some roaming conditions, we know the roaming network doesn't support control plane
+ // fallback even though the home operator does. For these operators we will need to do a DDS
+ // switch anyway to make sure the SUPL request doesn't fail.
+ boolean roamingNetworkSupportsControlPlaneFallback = true;
+ String[] dataPlaneRoamPlmns = cfgManager.getConfigForSubId(phone.getSubId()).getStringArray(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY);
+ if (dataPlaneRoamPlmns != null && Arrays.asList(dataPlaneRoamPlmns).contains(
+ phone.getServiceState().getOperatorNumeric())) {
+ roamingNetworkSupportsControlPlaneFallback = false;
+ }
+ if (isRoaming && roamingNetworkSupportsControlPlaneFallback) {
+ Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: roaming network is assumed "
+ + "to support CP fallback, not switching DDS.");
return CompletableFuture.completedFuture(Boolean.TRUE);
}
-
- // Do not switch Default data if this device supports emergency SUPL on non-DDS.
- final boolean gnssSuplRequiresDefaultData = phone.getContext().getResources().getBoolean(
- R.bool.config_gnss_supl_requires_default_data_for_emergency);
- if (!gnssSuplRequiresDefaultData) {
- Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, does not "
- + "require DDS switch.");
- return CompletableFuture.completedFuture(Boolean.TRUE);
- }
-
+ // Do not try to swap default data if we support CS fallback or it is assumed that the
+ // roaming network supports control plane fallback, we do not want to introduce
+ // a lag in emergency call setup time if possible.
final boolean supportsCpFallback = cfgManager.getConfigForSubId(phone.getSubId())
.getInt(CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_ONLY)
!= CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY;
- if (supportsCpFallback) {
+ if (supportsCpFallback && roamingNetworkSupportsControlPlaneFallback) {
Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, carrier "
+ "supports CP fallback.");
- // Do not try to swap default data if we support CS fallback, do not want to introduce
- // a lag in emergency call setup time if possible.
return CompletableFuture.completedFuture(Boolean.TRUE);
}
@@ -1445,7 +1599,7 @@
// CarrierConfig default if format fails.
int extensionTime = 0;
try {
- extensionTime = Integer.valueOf(cfgManager.getConfigForSubId(phone.getSubId())
+ extensionTime = Integer.parseInt(cfgManager.getConfigForSubId(phone.getSubId())
.getString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"));
} catch (NumberFormatException e) {
// Just use default.
@@ -1454,12 +1608,13 @@
try {
Log.d(this, "possiblyOverrideDefaultDataForEmergencyCall: overriding DDS for "
+ extensionTime + "seconds");
- PhoneSwitcher.getInstance().overrideDefaultDataForEmergency(phone.getPhoneId(),
- extensionTime, modemResultFuture);
+ mPhoneSwitcherProxy.getPhoneSwitcher().overrideDefaultDataForEmergency(
+ phone.getPhoneId(), extensionTime, modemResultFuture);
// Catch all exceptions, we want to continue with emergency call if possible.
} catch (Exception e) {
Log.w(this, "possiblyOverrideDefaultDataForEmergencyCall: exception = "
+ e.getMessage());
+ modemResultFuture = CompletableFuture.completedFuture(Boolean.FALSE);
}
return modemResultFuture;
}
@@ -1768,13 +1923,6 @@
return null; // null means nothing went wrong, and call should continue.
}
- private boolean isTtyModeEnabled(Context context) {
- return (android.provider.Settings.Secure.getInt(
- context.getContentResolver(),
- android.provider.Settings.Secure.PREFERRED_TTY_MODE,
- TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF);
- }
-
/**
* For outgoing dialed calls, potentially send a ConnectionEvent if the user is on WFC and is
* dialing an international number.
diff --git a/tests/Android.mk b/tests/Android.mk
index 44bf176..76140ac 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -31,6 +31,7 @@
LOCAL_INSTRUMENTATION_FOR := TeleService
LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.test.mock \
androidx.test.rules \
mockito-target-minus-junit4 \
androidx.test.espresso.core \
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index d30ae6b..01267d8 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -16,13 +16,10 @@
package com.android;
-import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
-import androidx.test.InstrumentationRegistry;
-
import org.mockito.MockitoAnnotations;
import java.util.concurrent.CountDownLatch;
@@ -33,11 +30,11 @@
*/
public class TelephonyTestBase {
- protected Context mContext;
+ protected TestContext mContext;
public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
MockitoAnnotations.initMocks(this);
+ mContext = new TestContext();
// Set up the looper if it does not exist on the test thread.
if (Looper.myLooper() == null) {
Looper.prepare();
@@ -86,4 +83,8 @@
Log.e("TelephonyTestBase", "InterruptedException while waiting: " + e);
}
}
+
+ protected TestContext getTestContext() {
+ return mContext;
+ }
}
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
new file mode 100644
index 0000000..4868647
--- /dev/null
+++ b/tests/src/com/android/TestContext.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.test.mock.MockContext;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class TestContext extends MockContext {
+
+ @Mock CarrierConfigManager mMockCarrierConfigManager;
+ @Mock TelecomManager mMockTelecomManager;
+ @Mock TelephonyManager mMockTelephonyManager;
+ @Mock SubscriptionManager mMockSubscriptionManager;
+ @Mock Resources mMockResources;
+
+ private PersistableBundle mCarrierConfig = new PersistableBundle();
+
+ public TestContext() {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mCarrierConfig).when(mMockCarrierConfigManager).getConfigForSubId(anyInt());
+ doReturn("test").when(mMockResources).getText(anyInt());
+ }
+
+ @Override
+ public Context getApplicationContext() {
+ return this;
+ }
+
+ @Override
+ public String getPackageName() {
+ return "com.android.phone.tests";
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ return null;
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
+ return null;
+ }
+
+ @Override
+ public Resources getResources() {
+ return mMockResources;
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler) {
+ return null;
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler, int flags) {
+ return null;
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ switch (name) {
+ case (Context.CARRIER_CONFIG_SERVICE) : {
+ return mMockCarrierConfigManager;
+ }
+ case (Context.TELECOM_SERVICE) : {
+ return mMockTelecomManager;
+ }
+ case (Context.TELEPHONY_SERVICE) : {
+ return mMockTelephonyManager;
+ }
+ case (Context.TELEPHONY_SUBSCRIPTION_SERVICE) : {
+ return mMockSubscriptionManager;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ if (serviceClass == CarrierConfigManager.class) {
+ return Context.CARRIER_CONFIG_SERVICE;
+ }
+ if (serviceClass == TelecomManager.class) {
+ return Context.TELECOM_SERVICE;
+ }
+ if (serviceClass == TelephonyManager.class) {
+ return Context.TELEPHONY_SERVICE;
+ }
+ if (serviceClass == SubscriptionManager.class) {
+ return Context.TELEPHONY_SUBSCRIPTION_SERVICE;
+ }
+ return null;
+ }
+
+ public PersistableBundle getCarrierConfig() {
+ return mCarrierConfig;
+ }
+}
diff --git a/tests/src/com/android/phone/CallFeaturesSettingTest.java b/tests/src/com/android/phone/CallFeaturesSettingTest.java
index 78d68e3..2468de4 100644
--- a/tests/src/com/android/phone/CallFeaturesSettingTest.java
+++ b/tests/src/com/android/phone/CallFeaturesSettingTest.java
@@ -31,6 +31,7 @@
import com.android.internal.telephony.PhoneConstants;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
@@ -54,6 +55,7 @@
mActivity = mRule.getActivity();
}
+ @Ignore
@FlakyTest
@Test
public void onResume_fdnIsAvailable_shouldShowFdnMenu() throws NoSuchFieldException,
@@ -69,6 +71,7 @@
onView(withText(R.string.fdn)).check(matches(isDisplayed()));
}
+ @Ignore
@FlakyTest
@Test
public void onResume_iccCardIsNull_shouldNotShowFdnMenu() throws NoSuchFieldException,
@@ -83,6 +86,7 @@
onView(withText(R.string.fdn)).check(doesNotExist());
}
+ @Ignore
@FlakyTest
@Test
public void onResume_fdnIsNotAvailable_shouldNotShowFdnMenu() throws NoSuchFieldException,
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 1329a77..583b498 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -17,35 +17,45 @@
package com.android.services.telephony;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
+import android.content.Context;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
+import android.telecom.ConnectionRequest;
import android.telecom.DisconnectCause;
+import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
import android.test.suitebuilder.annotation.SmallTest;
-import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.TelephonyTestBase;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneSwitcher;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import org.junit.After;
@@ -56,6 +66,8 @@
import org.mockito.Mock;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
/**
@@ -69,19 +81,65 @@
private static final int SLOT_0_PHONE_ID = 0;
private static final int SLOT_1_PHONE_ID = 1;
+ 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 PhoneAccountHandle PHONE_ACCOUNT_HANDLE_1 = new PhoneAccountHandle(
+ TEST_COMPONENT_NAME, TEST_ACCOUNT_ID1);
+ private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_2 = new PhoneAccountHandle(
+ TEST_COMPONENT_NAME, TEST_ACCOUNT_ID2);
+ private static final Uri TEST_ADDRESS = Uri.parse("tel:+16505551212");
+
@Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
@Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
@Mock TelephonyConnectionService.PhoneFactoryProxy mPhoneFactoryProxy;
+ @Mock DeviceState mDeviceState;
+ @Mock TelephonyConnectionService.PhoneSwitcherProxy mPhoneSwitcherProxy;
+ @Mock TelephonyConnectionService.PhoneNumberUtilsProxy mPhoneNumberUtilsProxy;
+ @Mock TelephonyConnectionService.PhoneUtilsProxy mPhoneUtilsProxy;
+ @Mock TelephonyConnectionService.DisconnectCauseFactory mDisconnectCauseFactory;
+ @Mock EmergencyNumberTracker mEmergencyNumberTracker;
+ @Mock PhoneSwitcher mPhoneSwitcher;
- TelephonyConnectionService mTestConnectionService;
+ private static class TestTelephonyConnectionService extends TelephonyConnectionService {
+
+ private final Context mContext;
+
+ TestTelephonyConnectionService(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void onCreate() {
+ // attach test context.
+ attachBaseContext(mContext);
+ super.onCreate();
+ }
+ }
+
+ private TelephonyConnectionService mTestConnectionService;
@Before
public void setUp() throws Exception {
super.setUp();
- mTestConnectionService = new TelephonyConnectionService();
+ mTestConnectionService = new TestTelephonyConnectionService(mContext);
mTestConnectionService.setPhoneFactoryProxy(mPhoneFactoryProxy);
- mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
mTestConnectionService.setSubscriptionManagerProxy(mSubscriptionManagerProxy);
+ // Set configurations statically
+ doReturn(false).when(mDeviceState).shouldCheckSimStateBeforeOutgoingCall(any());
+ mTestConnectionService.setPhoneSwitcherProxy(mPhoneSwitcherProxy);
+ doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
+ mTestConnectionService.setPhoneNumberUtilsProxy(mPhoneNumberUtilsProxy);
+ mTestConnectionService.setPhoneUtilsProxy(mPhoneUtilsProxy);
+ mTestConnectionService.setDeviceState(mDeviceState);
+ doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
+ .toTelecomDisconnectCause(anyInt(), any());
+ doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
+ .toTelecomDisconnectCause(anyInt(), any(), anyInt());
+ mTestConnectionService.setDisconnectCauseFactory(mDisconnectCauseFactory);
+ mTestConnectionService.onCreate();
+ mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
}
@After
@@ -522,7 +580,6 @@
* called.
*/
@Test
- @FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialTempFailOneSlot() {
TestTelephonyConnection c = new TestTelephonyConnection();
@@ -531,7 +588,7 @@
List<Phone> phones = new ArrayList<>(1);
phones.add(slot0Phone);
setPhones(phones);
- c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+ c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
@@ -554,7 +611,6 @@
* not called.
*/
@Test
- @FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialPermFailOneSlot() {
TestTelephonyConnection c = new TestTelephonyConnection();
@@ -563,7 +619,7 @@
List<Phone> phones = new ArrayList<>(1);
phones.add(slot0Phone);
setPhones(phones);
- c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+ c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
@@ -588,7 +644,6 @@
* PhoneAccount.
*/
@Test
- @FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot() {
TestTelephonyConnection c = new TestTelephonyConnection();
@@ -597,11 +652,15 @@
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
- c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+ c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
List<Phone> phones = new ArrayList<>(2);
phones.add(slot0Phone);
phones.add(slot1Phone);
setPhones(phones);
+ doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+ slot0Phone);
+ doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+ slot1Phone);
mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
@@ -626,7 +685,6 @@
* PhoneAccount.
*/
@Test
- @FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot() {
TestTelephonyConnection c = new TestTelephonyConnection();
@@ -635,11 +693,15 @@
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
- c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+ c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
List<Phone> phones = new ArrayList<>(2);
phones.add(slot0Phone);
phones.add(slot1Phone);
setPhones(phones);
+ doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+ slot0Phone);
+ doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+ slot1Phone);
mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
@@ -664,7 +726,6 @@
* notified of this twice.
*/
@Test
- @FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialTempFailTwoSlot_twoFailure() {
TestTelephonyConnection c = new TestTelephonyConnection();
@@ -673,11 +734,15 @@
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
- c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+ c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
List<Phone> phones = new ArrayList<>(2);
phones.add(slot0Phone);
phones.add(slot1Phone);
setPhones(phones);
+ doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+ slot0Phone);
+ doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+ slot1Phone);
// First Temporary failure
mTestConnectionService.retryOutgoingOriginalConnection(c, false /*isPermanentFailure*/);
@@ -716,7 +781,6 @@
* notified of the change to slot 1.
*/
@Test
- @FlakyTest
@SmallTest
public void testRetryOutgoingOriginalConnection_redialPermFailTwoSlot_twoFailure() {
TestTelephonyConnection c = new TestTelephonyConnection();
@@ -725,11 +789,15 @@
Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
false /*isEmergencyOnly*/);
setPhonesDialConnection(slot1Phone, c.getOriginalConnection());
- c.setAddress(Uri.parse("tel:+16505551212"), TelecomManager.PRESENTATION_ALLOWED);
+ c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
List<Phone> phones = new ArrayList<>(2);
phones.add(slot0Phone);
phones.add(slot1Phone);
setPhones(phones);
+ doReturn(PHONE_ACCOUNT_HANDLE_1).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+ slot0Phone);
+ doReturn(PHONE_ACCOUNT_HANDLE_2).when(mPhoneUtilsProxy).makePstnPhoneAccountHandle(
+ slot1Phone);
// First Permanent failure
mTestConnectionService.retryOutgoingOriginalConnection(c, true /*isPermanentFailure*/);
@@ -767,6 +835,7 @@
// registration to occur.
Phone phone = c.getPhone();
c.setOriginalConnection(c.getOriginalConnection());
+ doReturn(mContext).when(phone).getContext();
// When the registration occurs, we'll capture the handler and message so we can post our
// own messages to it.
@@ -803,6 +872,252 @@
extras.getInt(TelephonyManager.EXTRA_NOTIFICATION_CODE));
}
+ /**
+ * Test that the TelephonyConnectionService successfully performs a DDS switch before a call
+ * when we are not roaming and the carrier only supports SUPL over the data plane.
+ */
+ @Test
+ @SmallTest
+ public void testCreateOutgoingEmergencyConnection_delayDial_carrierconfig_dds() {
+ ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+ .setAddress(TEST_ADDRESS)
+ .build();
+ Phone testPhone = setupConnectionServiceForDelayDial();
+ // Setup test to not support SUPL on the non-DDS subscription
+ doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+ getTestContext().getCarrierConfig().putStringArray(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+ null);
+ testPhone.getServiceState().setRoaming(false);
+ getTestContext().getCarrierConfig().putInt(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+ CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+ getTestContext().getCarrierConfig().putString(
+ CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "150");
+
+ android.telecom.Connection testConnection = mTestConnectionService
+ .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+ assertNotNull("test connection was not set up correctly.", testConnection);
+
+ verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+ eq(150) /*extensionTime*/, any());
+ }
+
+ /**
+ * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
+ * supports control-plane fallback.
+ */
+ @Test
+ @SmallTest
+ public void testCreateOutgoingEmergencyConnection_delayDial_nocarrierconfig() {
+ ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+ .setAddress(TEST_ADDRESS)
+ .build();
+ Phone testPhone = setupConnectionServiceForDelayDial();
+ // Setup test to not support SUPL on the non-DDS subscription
+ doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+ getTestContext().getCarrierConfig().putStringArray(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+ null);
+ testPhone.getServiceState().setRoaming(false);
+ getTestContext().getCarrierConfig().putInt(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+ CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+ getTestContext().getCarrierConfig().putString(
+ CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+ android.telecom.Connection testConnection = mTestConnectionService
+ .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+ assertNotNull("test connection was not set up correctly.", testConnection);
+
+ verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+ }
+
+ /**
+ * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
+ * supports control-plane fallback.
+ */
+ @Test
+ @SmallTest
+ public void testCreateOutgoingEmergencyConnection_delayDial_supportsuplondds() {
+ ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+ .setAddress(TEST_ADDRESS)
+ .build();
+ Phone testPhone = setupConnectionServiceForDelayDial();
+ // If the non-DDS supports SUPL, dont switch data
+ doReturn(false).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+ getTestContext().getCarrierConfig().putStringArray(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+ null);
+ testPhone.getServiceState().setRoaming(false);
+ getTestContext().getCarrierConfig().putInt(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+ CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+ getTestContext().getCarrierConfig().putString(
+ CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+ android.telecom.Connection testConnection = mTestConnectionService
+ .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+ assertNotNull("test connection was not set up correctly.", testConnection);
+
+ verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+ }
+
+ /**
+ * Test that the TelephonyConnectionService does not perform a DDS switch when the carrier does
+ * not support control-plane fallback CarrierConfig while roaming.
+ */
+ @Test
+ @SmallTest
+ public void testCreateOutgoingEmergencyConnection_delayDial_roaming_nocarrierconfig() {
+ ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+ .setAddress(TEST_ADDRESS)
+ .build();
+ Phone testPhone = setupConnectionServiceForDelayDial();
+ // Setup test to not support SUPL on the non-DDS subscription
+ doReturn(true).when(mDeviceState).isSuplDdsSwitchRequiredForEmergencyCall(any());
+ getTestContext().getCarrierConfig().putStringArray(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+ null);
+ testPhone.getServiceState().setRoaming(true);
+ getTestContext().getCarrierConfig().putInt(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+ CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY);
+ getTestContext().getCarrierConfig().putString(
+ CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+ android.telecom.Connection testConnection = mTestConnectionService
+ .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+ assertNotNull("test connection was not set up correctly.", testConnection);
+
+ verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
+ }
+
+ /**
+ * Test that the TelephonyConnectionService does perform a DDS switch even though the carrier
+ * supports control-plane fallback CarrierConfig and the roaming partner is configured to look
+ * like a home network.
+ */
+ @Test
+ @SmallTest
+ public void testCreateOutgoingEmergencyConnection_delayDial_roamingcarrierconfig() {
+ ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+ .setAddress(TEST_ADDRESS)
+ .build();
+ Phone testPhone = setupConnectionServiceForDelayDial();
+ // 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().putStringArray(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+ roamingPlmns);
+ getTestContext().getCarrierConfig().putInt(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+ CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+ getTestContext().getCarrierConfig().putString(
+ CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+ android.telecom.Connection testConnection = mTestConnectionService
+ .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+ assertNotNull("test connection was not set up correctly.", testConnection);
+
+ verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+ eq(0) /*extensionTime*/, any());
+ }
+
+ /**
+ * Test that the TelephonyConnectionService does perform a DDS switch even though the carrier
+ * supports control-plane fallback CarrierConfig if we are roaming and the roaming partner is
+ * configured to use data plane only SUPL.
+ */
+ @Test
+ @SmallTest
+ public void testCreateOutgoingEmergencyConnection_delayDial__roaming_roamingcarrierconfig() {
+ ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+ .setAddress(TEST_ADDRESS)
+ .build();
+ Phone testPhone = setupConnectionServiceForDelayDial();
+ // 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());
+ String[] roamingPlmns = new String[1];
+ roamingPlmns[0] = testRoamingOperator;
+ getTestContext().getCarrierConfig().putStringArray(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY,
+ roamingPlmns);
+ getTestContext().getCarrierConfig().putInt(
+ CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT,
+ CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK);
+ getTestContext().getCarrierConfig().putString(
+ CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0");
+
+ android.telecom.Connection testConnection = mTestConnectionService
+ .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+ assertNotNull("test connection was not set up correctly.", testConnection);
+
+ verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /*phoneId*/ ,
+ eq(0) /*extensionTime*/, any());
+ }
+
+ /**
+ * Set up a mock MSIM device with TEST_ADDRESS set as an emergency number.
+ * @return the Phone associated with slot 0.
+ */
+ private Phone setupConnectionServiceForDelayDial() {
+ Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_IN_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ List<Phone> phones = new ArrayList<>(2);
+ doReturn(true).when(testPhone0).isRadioOn();
+ doReturn(true).when(testPhone1).isRadioOn();
+ phones.add(testPhone0);
+ phones.add(testPhone1);
+ setPhones(phones);
+ setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
+ setupDeviceConfig(testPhone0, testPhone1, 1);
+ doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
+ TEST_ADDRESS.getSchemeSpecificPart());
+ HashMap<Integer, List<EmergencyNumber>> emergencyNumbers = new HashMap<>(1);
+ List<EmergencyNumber> numbers = new ArrayList<>();
+ numbers.add(setupEmergencyNumber(TEST_ADDRESS));
+ emergencyNumbers.put(0 /*subId*/, numbers);
+ doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
+ doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
+
+ return testPhone0;
+ }
+
+ private EmergencyNumber setupEmergencyNumber(Uri address) {
+ return new EmergencyNumber(address.getSchemeSpecificPart(), "", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+ Collections.emptyList(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY);
+ }
+
+ private void setupHandleToPhoneMap(PhoneAccountHandle handle, Phone phone) {
+ // use subId 0
+ when(mPhoneUtilsProxy.getSubIdForPhoneAccountHandle(handle)).thenReturn(0);
+ when(mSubscriptionManagerProxy.getPhoneId(0)).thenReturn(0);
+ when(mPhoneFactoryProxy.getPhone(0)).thenReturn(phone);
+ }
+
private AsyncResult getSuppServiceNotification(int notificationType, int code) {
SuppServiceNotification notification = new SuppServiceNotification();
notification.notificationType = notificationType;
@@ -815,6 +1130,7 @@
ServiceState testServiceState = new ServiceState();
testServiceState.setState(serviceState);
testServiceState.setEmergencyOnly(isEmergencyOnly);
+ when(phone.getContext()).thenReturn(mContext);
when(phone.getServiceState()).thenReturn(testServiceState);
when(phone.getPhoneId()).thenReturn(phoneId);
when(phone.getDefaultPhone()).thenReturn(phone);
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
index b6e4bf3..c4d6568 100644
--- a/tests/src/com/android/services/telephony/TestTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.telecom.PhoneAccountHandle;
import static org.mockito.ArgumentMatchers.any;
@@ -125,6 +126,18 @@
// Do nothing since the original connection is mock object
}
+ @Override
+ public PersistableBundle getCarrierConfig() {
+ // Depends on PhoneGlobals for context in TelephonyConnection, do not implement during
+ // testing.
+ return new PersistableBundle();
+ }
+
+ @Override
+ void refreshConferenceSupported() {
+ // Requires ImsManager dependencies, do not implement during testing.
+ }
+
public int getNotifyPhoneAccountChangedCount() {
return mNotifyPhoneAccountChangedCount;
}