[QNS] Add handling emergency call over IMS
IMS ANE will monitor emergency call status if emergency call over IMS is
allowed.
Bug: 233581891
Test: atest QualifiedNetworksStatusTracker
Change-Id: I4612fffe90571ff416427bec981ed1cec6e3aed2
diff --git a/src/com/android/qns/AccessNetworkEvaluator.java b/src/com/android/qns/AccessNetworkEvaluator.java
index dde7303..6328fec 100644
--- a/src/com/android/qns/AccessNetworkEvaluator.java
+++ b/src/com/android/qns/AccessNetworkEvaluator.java
@@ -636,7 +636,11 @@
evaluate();
}
- private void onSetCallType(@QnsConstants.QnsCallType int callType) {
+ @VisibleForTesting
+ void onSetCallType(@QnsConstants.QnsCallType int callType) {
+ if (mApnType == ApnSetting.TYPE_IMS && callType == QnsConstants.CALL_TYPE_EMERGENCY) {
+ if (!mDataConnectionStatusTracker.isActiveState()) return;
+ }
mCallType = callType;
mRestrictManager.setQnsCallType(mCallType);
log("onSetCallType CallType:" + mCallType);
@@ -680,6 +684,10 @@
case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED:
needEvaluate = true;
initLastNotifiedQualifiedNetwork();
+ if (mApnType == ApnSetting.TYPE_IMS) {
+ if (mAltEventListener != null) mAltEventListener.clearNormalCallInfo();
+ }
+ mCallType = QnsConstants.CALL_TYPE_IDLE;
break;
case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED:
mHandler.post(() -> onDataConnectionConnected(info.getTransportType()));
@@ -1241,6 +1249,9 @@
: AccessNetworkType.IWLAN;
if (mConfigManager.isHandoverAllowedByPolicy(
mApnType, srcAccessNetwork, dstAccessNetwork, mCoverage)) {
+ if (mApnType == ApnSetting.TYPE_IMS && mCallType == QnsConstants.CALL_TYPE_EMERGENCY) {
+ return false;
+ }
return true;
} else {
if (mApnType == ApnSetting.TYPE_IMS && mCallType == QnsConstants.CALL_TYPE_IDLE) {
diff --git a/src/com/android/qns/AlternativeEventListener.java b/src/com/android/qns/AlternativeEventListener.java
index 5ca7aac..a1af8b5 100644
--- a/src/com/android/qns/AlternativeEventListener.java
+++ b/src/com/android/qns/AlternativeEventListener.java
@@ -17,6 +17,8 @@
package com.android.qns;
import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ACTIVE;
+import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ALERTING;
+import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_DIALING;
import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED;
import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_HOLDING;
import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -30,6 +32,7 @@
import android.os.Message;
import android.os.Registrant;
import android.telephony.Annotation;
+import android.telephony.PreciseDataConnectionState;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.util.Log;
@@ -359,6 +362,12 @@
}
}
+ void clearNormalCallInfo() {
+ mCallInfoManager.clearCallInfo();
+ mCallInfoManager.mLastReportedCallType = QnsConstants.CALL_TYPE_IDLE;
+ unregisterLowRtpQualityEvent(ApnSetting.TYPE_IMS, null);
+ }
+
@VisibleForTesting
void notifyRtpLowQuality(int callType, int reason) {
if (callType == QnsConstants.CALL_TYPE_VOICE) {
@@ -373,6 +382,14 @@
} else {
log("notifyRtpLowQuality mEmcLowRtpQuallityListener is null.");
}
+ if (mCallInfoManager.mLastReportedCallType == QnsConstants.CALL_TYPE_EMERGENCY) {
+ if (mLowRtpQuallityListener != null) {
+ log("notifyRtpLowQuality for emergency call to IMS ANE");
+ mLowRtpQuallityListener.notifyResult(reason);
+ } else {
+ log("notifyRtpLowQuality mLowRtpQuallityListener is null.");
+ }
+ }
}
}
@@ -395,6 +412,29 @@
QnsConstants.CALL_TYPE_EMERGENCY);
}
}
+ if (mCallTypeChangedEventListener != null) {
+ if ((state == PRECISE_CALL_STATE_ACTIVE
+ || state == PRECISE_CALL_STATE_DIALING
+ || state == PRECISE_CALL_STATE_ALERTING)
+ && !isDataNetworkConnected(ApnSetting.TYPE_EMERGENCY)
+ && isDataNetworkConnected(ApnSetting.TYPE_IMS)) {
+ log("Emergency call is progressing without emergency PDN");
+ if (mCallInfoManager.mLastReportedCallType
+ != QnsConstants.CALL_TYPE_EMERGENCY) {
+ mCallTypeChangedEventListener.notifyResult(
+ QnsConstants.CALL_TYPE_EMERGENCY);
+ mCallInfoManager.mLastReportedCallType =
+ QnsConstants.CALL_TYPE_EMERGENCY;
+ }
+ } else if (state == PRECISE_CALL_STATE_DISCONNECTED) {
+ log("Emergency call disconnected");
+ if (mCallInfoManager.mLastReportedCallType
+ == QnsConstants.CALL_TYPE_EMERGENCY) {
+ mCallTypeChangedEventListener.notifyResult(QnsConstants.CALL_TYPE_IDLE);
+ mCallInfoManager.mLastReportedCallType = QnsConstants.CALL_TYPE_IDLE;
+ }
+ }
+ }
return;
}
if (mCallTypeChangedEventListener != null) {
@@ -446,6 +486,17 @@
}
}
+ private boolean isDataNetworkConnected(int apnType) {
+ PreciseDataConnectionState preciseDataStatus =
+ QnsTelephonyListener.getInstance(mContext, mSlotIndex)
+ .getLastPreciseDataConnectionState(apnType);
+ if (preciseDataStatus == null) return false;
+ int state = preciseDataStatus.getState();
+ return (state == TelephonyManager.DATA_CONNECTED
+ || state == TelephonyManager.DATA_HANDOVER_IN_PROGRESS
+ || state == TelephonyManager.DATA_SUSPENDED);
+ }
+
@VisibleForTesting
protected void close() {
mCallTypeChangedEventListener = null;
diff --git a/src/com/android/qns/QnsCarrierConfigManager.java b/src/com/android/qns/QnsCarrierConfigManager.java
index e56d14c..fde1fbd 100644
--- a/src/com/android/qns/QnsCarrierConfigManager.java
+++ b/src/com/android/qns/QnsCarrierConfigManager.java
@@ -66,12 +66,6 @@
* management & listing related Access Network to pass to Telephony
*/
public class QnsCarrierConfigManager {
-
- /**
- * Keys supporting the configurations to support ANE in HO decision and Access Network
- * candidating
- */
-
/**
* Boolean indicating the WFC services in QNS Side is enabled, when airplane mode is On
*
diff --git a/tests/src/com/android/qns/AccessNetworkEvaluatorTest.java b/tests/src/com/android/qns/AccessNetworkEvaluatorTest.java
index 37c9c68..fe0abbc 100644
--- a/tests/src/com/android/qns/AccessNetworkEvaluatorTest.java
+++ b/tests/src/com/android/qns/AccessNetworkEvaluatorTest.java
@@ -336,6 +336,68 @@
}
@Test
+ public void testMoveTransportTypeAllowedEmergencyOverIms() {
+ when(configManager.isHandoverAllowedByPolicy(
+ ApnSetting.TYPE_IMS,
+ AccessNetworkConstants.AccessNetworkType.IWLAN,
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ QnsConstants.COVERAGE_HOME))
+ .thenReturn(true);
+ when(configManager.isHandoverAllowedByPolicy(
+ ApnSetting.TYPE_IMS,
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ AccessNetworkConstants.AccessNetworkType.IWLAN,
+ QnsConstants.COVERAGE_HOME))
+ .thenReturn(true);
+ when(configManager.isVolteRoamingSupported(anyInt())).thenReturn(true);
+ when(dataConnectionStatusTracker.isActiveState()).thenReturn(true);
+ when(dataConnectionStatusTracker.getLastTransportType())
+ .thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+ List<Integer> accessNetworks = new ArrayList<>();
+ accessNetworks.add(AccessNetworkConstants.AccessNetworkType.IWLAN);
+ QnsTelephonyListener.QnsTelephonyInfo info = qnsTelephonyListener.new QnsTelephonyInfo();
+ info.setCellularAvailable(true);
+ info.setCoverage(false);
+ info.setDataTech(ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+ info.setVoiceTech(ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
+ info.setDataRegState(ServiceState.STATE_IN_SERVICE);
+ QnsTelephonyListener.QnsTelephonyInfoIms infoIms =
+ qnsTelephonyListener.new QnsTelephonyInfoIms(info, true, true, false, false);
+ ane.onQnsTelephonyInfoChanged(infoIms);
+ ane.updateLastNotifiedQualifiedNetwork(accessNetworks);
+ ane.onSetCallType(QnsConstants.CALL_TYPE_EMERGENCY);
+ assertTrue(ane.needHandoverPolicyCheck());
+ assertFalse(ane.moveTransportTypeAllowed());
+
+ when(configManager.isHandoverAllowedByPolicy(
+ ApnSetting.TYPE_IMS,
+ AccessNetworkConstants.AccessNetworkType.IWLAN,
+ AccessNetworkConstants.AccessNetworkType.UTRAN,
+ QnsConstants.COVERAGE_HOME))
+ .thenReturn(false);
+ info = qnsTelephonyListener.new QnsTelephonyInfo();
+ info.setCellularAvailable(true);
+ info.setCoverage(false);
+ info.setDataTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
+ info.setVoiceTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
+ info.setDataRegState(ServiceState.STATE_IN_SERVICE);
+ infoIms = qnsTelephonyListener.new QnsTelephonyInfoIms(info, true, true, false, false);
+ ane.onQnsTelephonyInfoChanged(infoIms);
+ ane.updateLastNotifiedQualifiedNetwork(accessNetworks);
+ ane.onSetCallType(QnsConstants.CALL_TYPE_VOICE);
+ assertTrue(ane.needHandoverPolicyCheck());
+ assertFalse(ane.moveTransportTypeAllowed());
+ ane.updateLastNotifiedQualifiedNetwork(accessNetworks);
+ ane.onSetCallType(QnsConstants.CALL_TYPE_IDLE);
+ assertTrue(ane.needHandoverPolicyCheck());
+ assertTrue(ane.moveTransportTypeAllowed());
+ ane.updateLastNotifiedQualifiedNetwork(accessNetworks);
+ ane.onSetCallType(QnsConstants.CALL_TYPE_EMERGENCY);
+ assertTrue(ane.needHandoverPolicyCheck());
+ assertFalse(ane.moveTransportTypeAllowed());
+ }
+
+ @Test
public void testVopsCheckRequired() {
when(dataConnectionStatusTracker.getLastTransportType())
.thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
diff --git a/tests/src/com/android/qns/AlternativeEventListenerTest.java b/tests/src/com/android/qns/AlternativeEventListenerTest.java
index 744a2e7..e635eb8 100644
--- a/tests/src/com/android/qns/AlternativeEventListenerTest.java
+++ b/tests/src/com/android/qns/AlternativeEventListenerTest.java
@@ -19,12 +19,14 @@
import static org.junit.Assert.*;
import android.content.Context;
+import android.net.LinkProperties;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
import android.os.test.TestLooper;
import android.telephony.AccessNetworkConstants;
import android.telephony.PreciseCallState;
+import android.telephony.PreciseDataConnectionState;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
@@ -49,6 +51,7 @@
private Handler mHandler;
CountDownLatch mLatch;
int[] mThresholds;
+ QnsTelephonyListener mQtListener;
class AltEventProvider extends AlternativeEventProvider {
@@ -82,11 +85,13 @@
mHandler = new Handler(mTestLooper.getLooper());
mListener = AlternativeEventListener.getInstance(sMockContext, SLOT_INDEX);
mAltEventProvider = new AltEventProvider(sMockContext, SLOT_INDEX);
+ mQtListener = QnsTelephonyListener.getInstance(sMockContext, 0);
// mListener.setEventProvider(mAltEventProvider);
}
@After
public void tearDown() {
+ mQtListener.close();
mListener.close();
}
@@ -321,6 +326,112 @@
}
@Test
+ public void testEmergencyOverImsCallTypeChangedScenarios() {
+ mListener.registerCallTypeChangedListener(ApnSetting.TYPE_IMS, mHandler, 1, null);
+ PreciseDataConnectionState emergencyDataStatus =
+ new PreciseDataConnectionState.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_INVALID)
+ .setState(TelephonyManager.DATA_DISCONNECTED)
+ .setNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN)
+ .setApnSetting(
+ new ApnSetting.Builder()
+ .setApnTypeBitmask(ApnSetting.TYPE_EMERGENCY)
+ .setApnName("sos")
+ .setEntryName("sos")
+ .build())
+ .setLinkProperties(new LinkProperties())
+ .build();
+ PreciseDataConnectionState imsDataStatus =
+ new PreciseDataConnectionState.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+ .setState(TelephonyManager.DATA_CONNECTED)
+ .setNetworkType(AccessNetworkConstants.AccessNetworkType.IWLAN)
+ .setApnSetting(
+ new ApnSetting.Builder()
+ .setApnTypeBitmask(ApnSetting.TYPE_IMS)
+ .setApnName("ims")
+ .setEntryName("ims")
+ .build())
+ .build();
+ mQtListener.mTelephonyListener.onPreciseDataConnectionStateChanged(emergencyDataStatus);
+ mQtListener.mTelephonyListener.onPreciseDataConnectionStateChanged(imsDataStatus);
+ // Test1:
+ mAltEventProvider.notifyCallInfo(
+ 1, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_DIALING);
+
+ Message msg = mTestLooper.nextMessage();
+ assertNotNull(msg);
+ AsyncResult result = (AsyncResult) msg.obj;
+ assertNotNull(result.result);
+ assertEquals(QnsConstants.CALL_TYPE_EMERGENCY, (int) result.result);
+
+ // Test2:
+ mAltEventProvider.notifyCallInfo(
+ 1, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
+ msg = mTestLooper.nextMessage();
+
+ // Should not notify if call type is not changed
+ assertNull(msg);
+
+ // Test3:
+ imsDataStatus =
+ new PreciseDataConnectionState.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_INVALID)
+ .setState(TelephonyManager.DATA_DISCONNECTED)
+ .setNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN)
+ .setApnSetting(
+ new ApnSetting.Builder()
+ .setApnTypeBitmask(ApnSetting.TYPE_IMS)
+ .setApnName("ims")
+ .setEntryName("ims")
+ .build())
+ .build();
+ mQtListener.mTelephonyListener.onPreciseDataConnectionStateChanged(imsDataStatus);
+
+ mAltEventProvider.notifyCallInfo(
+ 1,
+ QnsConstants.CALL_TYPE_EMERGENCY,
+ PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED);
+ msg = mTestLooper.nextMessage();
+ assertNotNull(msg);
+ result = (AsyncResult) msg.obj;
+ assertNotNull(result.result);
+ assertEquals(QnsConstants.CALL_TYPE_IDLE, (int) result.result);
+
+ // Test4:
+ emergencyDataStatus =
+ new PreciseDataConnectionState.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+ .setState(TelephonyManager.DATA_CONNECTED)
+ .setNetworkType(AccessNetworkConstants.AccessNetworkType.IWLAN)
+ .setApnSetting(
+ new ApnSetting.Builder()
+ .setApnTypeBitmask(ApnSetting.TYPE_EMERGENCY)
+ .setApnName("sos")
+ .setEntryName("sos")
+ .build())
+ .build();
+ mQtListener.mTelephonyListener.onPreciseDataConnectionStateChanged(emergencyDataStatus);
+ imsDataStatus =
+ new PreciseDataConnectionState.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+ .setState(TelephonyManager.DATA_CONNECTED)
+ .setNetworkType(AccessNetworkConstants.AccessNetworkType.IWLAN)
+ .setApnSetting(
+ new ApnSetting.Builder()
+ .setApnTypeBitmask(ApnSetting.TYPE_IMS)
+ .setApnName("ims")
+ .setEntryName("ims")
+ .build())
+ .build();
+ mQtListener.mTelephonyListener.onPreciseDataConnectionStateChanged(imsDataStatus);
+ mAltEventProvider.notifyCallInfo(
+ 2, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
+ msg = mTestLooper.nextMessage();
+ assertNull(msg);
+ }
+
+ @Test
public void testOnSrvccStateChanged() {
mListener.registerCallTypeChangedListener(ApnSetting.TYPE_IMS, mHandler, 1, null);