Snap for 10103804 from 32df980cf4b3d7c0448a639c3f040bbc82074cc2 to mainline-tzdata5-release
Change-Id: Ifa0154b57fb9da651e8d8dca9884ca928596b73b
diff --git a/libs/TelephonyStatsLib/OWNERS b/libs/TelephonyStatsLib/OWNERS
new file mode 100644
index 0000000..7d5d12e
--- /dev/null
+++ b/libs/TelephonyStatsLib/OWNERS
@@ -0,0 +1,8 @@
+set noparent
+
+# for TelephonyStatsLib
+sewookseo@google.com
+sangyun@google.com
+seheele@google.com
+nagendranb@google.com
+mdungriyal@google.com
diff --git a/services/QualifiedNetworksService/Android.bp b/services/QualifiedNetworksService/Android.bp
index 1a5426f..80e6d14 100644
--- a/services/QualifiedNetworksService/Android.bp
+++ b/services/QualifiedNetworksService/Android.bp
@@ -17,6 +17,13 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
+genrule {
+ name: "statslog-qns-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module qns --javaPackage com.android.telephony.qns.stats --javaClass QnsStatsLog --worksource",
+ out: ["com/android/telephony/qns/stats/QnsStatsLog.java"],
+}
+
android_app {
name: "QualifiedNetworksService",
system_ext_specific: true,
@@ -25,11 +32,13 @@
srcs: [
"src/**/*.java",
"src/**/I*.aidl",
+ ":statslog-qns-java-gen",
],
static_libs: [
"androidx.appcompat_appcompat",
"androidx.browser_browser",
+ "TelephonyStatsLib",
],
libs: [
@@ -72,6 +81,7 @@
"src/**/*.java",
"src/**/I*.aidl",
"tests/**/*.java",
+ ":statslog-qns-java-gen",
],
libs: [
"android.test.runner",
@@ -90,8 +100,9 @@
"frameworks-base-testutils",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
- "truth-prebuilt",
- "testables",
+ "truth-prebuilt",
+ "testables",
+ "TelephonyStatsLib",
],
jni_libs: [
"libdexmakerjvmtiagent",
diff --git a/services/QualifiedNetworksService/AndroidManifest.xml b/services/QualifiedNetworksService/AndroidManifest.xml
index 5170124..5abdbf9 100644
--- a/services/QualifiedNetworksService/AndroidManifest.xml
+++ b/services/QualifiedNetworksService/AndroidManifest.xml
@@ -26,6 +26,8 @@
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+ <uses-permission android:name="android.permission.REGISTER_STATS_PULL_ATOM" />
+ <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<application
android:directBootAware="true"
android:defaultToDeviceProtectedStorage="true">
diff --git a/services/QualifiedNetworksService/privapp-permissions_com.android.telephony.qns.xml b/services/QualifiedNetworksService/privapp-permissions_com.android.telephony.qns.xml
index 223aa19..3f31bcf 100644
--- a/services/QualifiedNetworksService/privapp-permissions_com.android.telephony.qns.xml
+++ b/services/QualifiedNetworksService/privapp-permissions_com.android.telephony.qns.xml
@@ -20,5 +20,6 @@
<permission name="android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP"/>
<permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.REGISTER_STATS_PULL_ATOM" />
</privapp-permissions>
</permissions>
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/AccessNetworkEvaluator.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/AccessNetworkEvaluator.java
index d708f2d..f77da91 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/AccessNetworkEvaluator.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/AccessNetworkEvaluator.java
@@ -26,6 +26,7 @@
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ProvisioningManager;
import android.util.Log;
@@ -61,8 +62,13 @@
private static final int EVENT_IMS_REGISTRATION_STATE_CHANGED = EVENT_BASE + 10;
private static final int EVENT_WIFI_RTT_STATUS_CHANGED = EVENT_BASE + 11;
private static final int EVENT_SIP_DIALOG_SESSION_STATE_CHANGED = EVENT_BASE + 12;
+ private static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = EVENT_BASE + 13;
private static final int EVALUATE_SPECIFIC_REASON_NONE = 0;
private static final int EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE = 1;
+ private static final int EVALUATE_SPECIFIC_REASON_DATA_DISCONNECTED = 2;
+ private static final int EVALUATE_SPECIFIC_REASON_DATA_FAILED = 3;
+ private static final int EVALUATE_SPECIFIC_REASON_DATA_CONNECTED = 4;
+
protected final int mSlotIndex;
protected final Context mContext;
private final String mLogTag;
@@ -79,11 +85,13 @@
protected IwlanNetworkStatusTracker mIwlanNetworkStatusTracker;
protected DataConnectionStatusTracker mDataConnectionStatusTracker;
protected QnsEventDispatcher mQnsEventDispatcher;
- protected AlternativeEventListener mAltEventListener;
protected QnsCallStatusTracker mCallStatusTracker;
protected QnsProvisioningListener mQnsProvisioningListener;
protected QnsImsManager mQnsImsManager;
protected WifiBackhaulMonitor mWifiBackhaulMonitor;
+ protected QnsTelephonyListener mQnsTelephonyListener;
+ // for metric
+ protected QnsMetrics mQnsMetrics;
protected int mCellularAccessNetworkType = AccessNetworkType.UNKNOWN;
protected boolean mCellularAvailable = false;
@@ -113,6 +121,7 @@
private boolean mSipDialogSessionState = false;
private int mCachedTransportTypeForEmergencyInitialConnect =
AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+ private int mLastEvaluateSpecificReason = EVALUATE_SPECIFIC_REASON_NONE;
AccessNetworkEvaluator(QnsComponents qnsComponents, int netCapability, int slotIndex) {
mNetCapability = netCapability;
@@ -139,7 +148,6 @@
Executor executor = new QnsUtils.QnsExecutor(mHandler);
mConfigManager = mQnsComponents.getQnsCarrierConfigManager(mSlotIndex);
- mAltEventListener = mQnsComponents.getAlternativeEventListener(mSlotIndex);
mCallStatusTracker = mQnsComponents.getQnsCallStatusTracker(mSlotIndex);
mQnsProvisioningListener = mQnsComponents.getQnsProvisioningListener(mSlotIndex);
mIwlanNetworkStatusTracker = mQnsComponents.getIwlanNetworkStatusTracker();
@@ -151,6 +159,8 @@
mNetCapability);
mQnsImsManager = mQnsComponents.getQnsImsManager(mSlotIndex);
mWifiBackhaulMonitor = mQnsComponents.getWifiBackhaulMonitor(mSlotIndex);
+ mQnsTelephonyListener = mQnsComponents.getQnsTelephonyListener(mSlotIndex);
+ mQnsMetrics = mQnsComponents.getQnsMetrics();
// Pre-Conditions
mCellularNetworkStatusTracker = mQnsComponents.getCellularNetworkStatusTracker(mSlotIndex);
@@ -204,11 +214,12 @@
mIwlanNetworkStatusTracker = mQnsComponents.getIwlanNetworkStatusTracker();
mDataConnectionStatusTracker = dataConnectionStatusTracker;
mQnsEventDispatcher = mQnsComponents.getQnsEventDispatcher(mSlotIndex);
- mAltEventListener = mQnsComponents.getAlternativeEventListener(mSlotIndex);
mCallStatusTracker = mQnsComponents.getQnsCallStatusTracker(mSlotIndex);
mQnsProvisioningListener = mQnsComponents.getQnsProvisioningListener(mSlotIndex);
mQnsImsManager = mQnsComponents.getQnsImsManager(mSlotIndex);
mWifiBackhaulMonitor = mQnsComponents.getWifiBackhaulMonitor(mSlotIndex);
+ mQnsTelephonyListener = mQnsComponents.getQnsTelephonyListener(mSlotIndex);
+ mQnsMetrics = mQnsComponents.getQnsMetrics();
mHandlerThread =
new HandlerThread(AccessNetworkEvaluator.class.getSimpleName() + mNetCapability);
mHandlerThread.start();
@@ -244,6 +255,7 @@
isAllowed(AccessNetworkConstants.TRANSPORT_TYPE_WWAN))) {
mHandler.post(this::evaluate);
}
+ mLastEvaluateSpecificReason = EVALUATE_SPECIFIC_REASON_NONE;
}
void close() {
@@ -323,6 +335,9 @@
QualifiedNetworksInfo info = new QualifiedNetworksInfo(mNetCapability, accessNetworkTypes);
QnsAsyncResult ar = new QnsAsyncResult(null, info, null);
mQualifiedNetworksChangedRegistrants.notifyRegistrants(ar);
+
+ // metrics
+ sendMetricsForQualifiedNetworks(info);
}
private void initSettings() {
@@ -379,6 +394,10 @@
}
mQnsProvisioningListener.registerProvisioningItemInfoChanged(
mHandler, EVENT_PROVISIONING_INFO_CHANGED, null, true);
+ if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
+ mQnsTelephonyListener.registerImsCallDropDisconnectCauseListener(
+ mHandler, EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED, null);
+ }
List<Integer> events = new ArrayList<>();
events.add(QnsEventDispatcher.QNS_EVENT_WFC_ENABLED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_DISABLED);
@@ -415,6 +434,9 @@
mWifiBackhaulMonitor.unRegisterForRttStatusChange(mHandler);
}
}
+ if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
+ mQnsTelephonyListener.unregisterImsCallDropDisconnectCauseListener(mHandler);
+ }
mQnsProvisioningListener.unregisterProvisioningItemInfoChanged(mHandler);
mQnsEventDispatcher.unregisterEvent(mHandler);
mRestrictManager.unRegisterRestrictInfoChanged(mHandler);
@@ -518,7 +540,9 @@
protected void onIwlanNetworkStatusChanged(IwlanAvailabilityInfo info) {
if (info != null) {
- mIwlanAvailable = info.getIwlanAvailable();
+ if (mIwlanAvailable != info.getIwlanAvailable()) {
+ mIwlanAvailable = info.getIwlanAvailable();
+ }
mIsCrossWfc = info.isCrossWfc();
log("onIwlanNetworkStatusChanged IwlanAvailable:" + mIwlanAvailable);
if (info.getNotifyIwlanDisabled()) {
@@ -656,6 +680,10 @@
&& callType == QnsConstants.CALL_TYPE_EMERGENCY) {
if (!mDataConnectionStatusTracker.isActiveState()) return;
}
+
+ // metrics
+ sendMetricsForCallTypeChanged(mCallType, callType);
+
mCallType = callType;
mRestrictManager.setQnsCallType(mCallType);
log("onSetCallType CallType:" + mCallType);
@@ -675,7 +703,11 @@
log(
"onEmergencyPreferredTransportTypeChanged transport:"
+ QnsConstants.transportTypeToString(transport));
- if (mDataConnectionStatusTracker.isInactiveState()) {
+ if (mDataConnectionStatusTracker.isInactiveState()
+ || (mDataConnectionStatusTracker.isActiveState()
+ && mCallType == QnsConstants.CALL_TYPE_IDLE)) {
+ // If data network state is inactive OR active but call is not active yet,
+ // QNS will follow domain selection's decision.
enforceNotifyQualifiedNetworksWithTransportType(transport);
} else {
log(
@@ -704,32 +736,54 @@
DataConnectionStatusTracker.DataConnectionChangedInfo info) {
log("onDataConnectionStateChanged info:" + info);
boolean needEvaluate = false;
+ int evaluateSpecificReason = EVALUATE_SPECIFIC_REASON_NONE;
switch (info.getEvent()) {
case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED:
+ evaluateSpecificReason = EVALUATE_SPECIFIC_REASON_DATA_DISCONNECTED;
if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
// If FWK guided emergency's transport type during data connected state, notify
// the transport type when the data connection is disconnected.
notifyCachedTransportTypeForEmergency();
+ // When cellular is not available, CellularQualityMonitor will stop listening to
+ // TelephonyCallback. Thresholds for Emergency apn may not be reset as ANE for
+ // emergency only evaluates while data is connected. CellularQualityMonitor will
+ // not listen to TelephonyCallback again until the set of threshold values
+ // changed. Resetting thresholds for emergency after the emergency connection
+ // disconnects.
+ unregisterThresholdToQualityMonitor();
} else {
needEvaluate = true;
initLastNotifiedQualifiedNetwork();
}
break;
case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED:
+ evaluateSpecificReason = EVALUATE_SPECIFIC_REASON_DATA_CONNECTED;
mHandler.post(() -> onDataConnectionConnected(info.getTransportType()));
break;
case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_FAILED:
+ evaluateSpecificReason = EVALUATE_SPECIFIC_REASON_DATA_FAILED;
if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
// If FWK guided emergency's transport type during data connecting state, notify
// the transport type when the data connection is failed.
notifyCachedTransportTypeForEmergency();
+ // When cellular is not available, CellularQualityMonitor will stop listening to
+ // TelephonyCallback. Thresholds for Emergency apn may not be reset as ANE for
+ // emergency only evaluates while data is connected. CellularQualityMonitor will
+ // not listen to TelephonyCallback again until the set of threshold values
+ // changed. Resetting thresholds for emergency after the emergency connection
+ // disconnects.
+ unregisterThresholdToQualityMonitor();
} else {
needEvaluate = true;
}
break;
}
+
+ // metrics
+ sendMetricsForDataConnectionChanged(info);
+
if (needEvaluate) {
- evaluate();
+ evaluate(evaluateSpecificReason);
}
}
@@ -891,6 +945,26 @@
}
}
+ protected void onImsCallDisconnectCauseChanged(ImsReasonInfo imsReasonInfo) {
+ if (imsReasonInfo == null) {
+ return;
+ }
+ if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS
+ && imsReasonInfo.getCode() == ImsReasonInfo.CODE_MEDIA_NO_DATA) {
+ log(
+ "onImsCallDisconnectCauseChanged: iwlanAvailable="
+ + mIwlanAvailable
+ + " cellularAvailable="
+ + mCellularAvailable
+ + " imsReasonInfo="
+ + imsReasonInfo);
+ if (mIwlanAvailable && mCellularAvailable) {
+ // metrics
+ sendMetricsForImsCallDropStats();
+ }
+ }
+ }
+
protected void onCellularQualityChanged(Threshold[] ths) {
if (ths == null || ths.length == 0) {
log("onCellularQualityChanged: E threshold is null");
@@ -1168,11 +1242,13 @@
if (DBG) log("ANE is not initialized yet.");
return;
}
+ mLastEvaluateSpecificReason = specificReason;
log("evaluate reason:" + evaluateSpecificReasonToString(specificReason));
- if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_EIMS
- && mDataConnectionStatusTracker.isInactiveState()) {
- log("QNS only handles HO of EMERGENCY data connection");
- return;
+ if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
+ if (!mDataConnectionStatusTracker.isActiveState()) {
+ log("QNS only handles HO of EMERGENCY data connection");
+ return;
+ }
}
/* Check handover policy */
@@ -1350,7 +1426,7 @@
return true;
} else {
if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS
- && mCallType == QnsConstants.CALL_TYPE_IDLE) {
+ && mCallStatusTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS)) {
// Telephony will make new connection with preferred AccessNetwork
log("handover is not allowed. but need to move to target Transport.");
return true;
@@ -1871,6 +1947,12 @@
return "EVALUATE_SPECIFIC_REASON_NONE";
} else if (specificReason == EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE) {
return "EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE";
+ } else if (specificReason == EVALUATE_SPECIFIC_REASON_DATA_DISCONNECTED) {
+ return "EVALUATE_SPECIFIC_REASON_DATA_DISCONNECTED";
+ } else if (specificReason == EVALUATE_SPECIFIC_REASON_DATA_FAILED) {
+ return "EVALUATE_SPECIFIC_REASON_DATA_FAILED";
+ } else if (specificReason == EVALUATE_SPECIFIC_REASON_DATA_CONNECTED) {
+ return "EVALUATE_SPECIFIC_REASON_DATA_CONNECTED";
}
return "UNKNOWN";
}
@@ -1921,6 +2003,9 @@
case EVENT_SIP_DIALOG_SESSION_STATE_CHANGED:
onSipDialogSessionStateChanged((boolean) ar.mResult);
break;
+ case EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED:
+ onImsCallDisconnectCauseChanged((ImsReasonInfo) ar.mResult);
+ break;
case QnsEventDispatcher.QNS_EVENT_WFC_ENABLED:
onWfcEnabledChanged(true, false);
break;
@@ -2066,4 +2151,50 @@
boolean getSipDialogSessionState() {
return mSipDialogSessionState;
}
+
+ private void sendMetricsForQualifiedNetworks(QualifiedNetworksInfo info) {
+ if (!mCellularAvailable
+ || !mIwlanAvailable
+ || mCellularAccessNetworkType == AccessNetworkType.UNKNOWN
+ || mLastEvaluateSpecificReason == EVALUATE_SPECIFIC_REASON_DATA_DISCONNECTED) {
+ // b/268557926, decided to cut off if WWAN and WLAN are not in contention.
+ return;
+ }
+ mQnsMetrics.reportAtomForQualifiedNetworks(
+ info,
+ mSlotIndex,
+ mDataConnectionStatusTracker.getLastTransportType(),
+ mCoverage,
+ mSettingWfcEnabled,
+ mSettingWfcRoamingEnabled,
+ mSettingWfcMode,
+ mSettingWfcRoamingMode,
+ mCellularAccessNetworkType,
+ mIwlanAvailable,
+ mIsCrossWfc,
+ mRestrictManager,
+ mCellularQualityMonitor,
+ mWifiQualityMonitor,
+ mCallType);
+ }
+
+ private void sendMetricsForCallTypeChanged(int oldCallType, int newCallType) {
+ int transportTypeOfCall = mDataConnectionStatusTracker.getLastTransportType();
+ mQnsMetrics.reportAtomForCallTypeChanged(mNetCapability, mSlotIndex,
+ oldCallType, newCallType, mRestrictManager, transportTypeOfCall);
+ }
+
+ private void sendMetricsForDataConnectionChanged(
+ DataConnectionStatusTracker.DataConnectionChangedInfo info) {
+ mQnsMetrics.reportAtomForDataConnectionChanged(
+ mNetCapability, mSlotIndex, info, mConfigManager.getCarrierId());
+ }
+
+ private void sendMetricsForImsCallDropStats() {
+ int transportTypeOfCall = mDataConnectionStatusTracker.getLastTransportType();
+ mQnsMetrics.reportAtomForImsCallDropStats(mNetCapability, mSlotIndex, mRestrictManager,
+ mCellularQualityMonitor, mWifiQualityMonitor, transportTypeOfCall,
+ mCellularAccessNetworkType);
+ }
+
}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/AlternativeEventListener.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/AlternativeEventListener.java
deleted file mode 100644
index 36fdaa4..0000000
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/AlternativeEventListener.java
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * Copyright (C) 2021 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.telephony.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;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.NetworkCapabilities;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.telephony.Annotation;
-import android.telephony.PreciseDataConnectionState;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-class AlternativeEventListener {
- private static final int EVENT_SRVCC_STATE_CHANGED = 13001;
- private static final SparseArray<AlternativeEventListener> sAlternativeInterfaceManager =
- new SparseArray<>();
- private final String mLogTag;
- private Context mContext;
- private int mSlotIndex;
- private QnsTelephonyListener mQnsTelephonyListener;
- private QnsRegistrant mCallTypeChangedEventListener;
- private QnsRegistrant mEmergencyCallTypeChangedEventListener;
- private QnsRegistrant mEmergencyPreferredTransportTypeChanged;
- private QnsRegistrant mTryWfcConnectionState;
- private QnsRegistrant mLowRtpQuallityListener;
- private QnsRegistrant mEmcLowRtpQuallityListener;
- private AlternativeEventCb mEventCb;
- private AlternativeEventProvider mEventProvider;
- private Handler mHandler;
- private CallInfoManager mCallInfoManager = new CallInfoManager();
-
- class CallInfo {
- int mId;
- int mType;
- int mState;
-
- CallInfo(int id, int type, int state) {
- mId = id;
- mType = type;
- mState = state;
- }
- }
-
- /** Manager of CallInfo list. */
- private class CallInfoManager {
- private SparseArray<CallInfo> mCallInfos = new SparseArray<>();
- QnsCarrierConfigManager.RtpMetricsConfig mRtpMetricsConfig;
- int mEmergencyCallState = PRECISE_CALL_STATE_IDLE;
- int mLastReportedCallType = QnsConstants.CALL_TYPE_IDLE;
-
- CallInfoManager() {
- mRtpMetricsConfig = null;
- }
-
- void updateCallInfo(
- int id,
- @QnsConstants.QnsCallType int type,
- @Annotation.PreciseCallStates int state) {
- if (mRtpMetricsConfig != null && state == PRECISE_CALL_STATE_ACTIVE) {
- requestRtpThreshold(mRtpMetricsConfig);
- }
- if (type == QnsConstants.CALL_TYPE_EMERGENCY) {
- mEmergencyCallState = state;
- return;
- }
- if (type == QnsConstants.CALL_TYPE_VIDEO || type == QnsConstants.CALL_TYPE_VOICE) {
- CallInfo info = mCallInfos.get(id);
- if (info == null) {
- if (state == PRECISE_CALL_STATE_ACTIVE) {
- mCallInfos.put(id, new CallInfo(id, type, state));
- log("add callinfo with id " + id);
- }
- } else {
- if (info.mType != type) {
- log("CallId[" + info.mId + "] type changed " + info.mType + " > " + id);
- info.mType = type;
- }
- if (state == PRECISE_CALL_STATE_HOLDING) {
- log("CallId[" + info.mId + "] changed to HOLDING ");
- info.mState = state;
- } else if (state == PRECISE_CALL_STATE_ACTIVE) {
- log("CallId[" + info.mId + "] changed to ACTIVE ");
- info.mState = state;
- } else if (state == PRECISE_CALL_STATE_DISCONNECTED) {
- log("delete callInfo callId:" + id);
- mCallInfos.remove(id);
- }
- }
- }
- }
-
- boolean isCallIdle() {
- return mCallInfos.size() == 0;
- }
-
- CallInfo getActiveCallInfo() {
- for (int i = 0; i < mCallInfos.size(); i++) {
- int key = mCallInfos.keyAt(i);
- if (mCallInfos.get(key).mState == PRECISE_CALL_STATE_ACTIVE) {
- return mCallInfos.get(key);
- }
- }
- return null;
- }
-
- void clearCallInfo() {
- mCallInfos.clear();
- }
-
- boolean hasVideoCall() {
- for (int i = 0; i < mCallInfos.size(); i++) {
- int key = mCallInfos.keyAt(i);
- if (mCallInfos.get(key).mType == QnsConstants.CALL_TYPE_VIDEO) {
- return true;
- }
- }
- return false;
- }
-
- void requestRtpThreshold(QnsCarrierConfigManager.RtpMetricsConfig config) {
- if (config != null) {
- mRtpMetricsConfig =
- new QnsCarrierConfigManager.RtpMetricsConfig(
- config.mJitter,
- config.mPktLossRate,
- config.mPktLossTime,
- config.mNoRtpInterval);
- }
- CallInfo info = getActiveCallInfo();
- if (mEventProvider != null && info != null) {
- log("requestRtpThreshold callId:" + info.mId + " " + config.toString());
- mEventProvider.requestRtpThreshold(
- info.mId,
- mRtpMetricsConfig.mJitter,
- mRtpMetricsConfig.mPktLossRate,
- mRtpMetricsConfig.mPktLossTime,
- mRtpMetricsConfig.mNoRtpInterval);
- }
- }
- }
-
- class MessageHandler extends Handler {
- MessageHandler(Looper l) {
- super(l);
- }
-
- @Override
- public void handleMessage(Message message) {
- Log.d(mLogTag, "handleMessage msg=" + message.what);
- QnsAsyncResult ar = (QnsAsyncResult) message.obj;
- int state = (int) ar.mResult;
- switch (message.what) {
- case EVENT_SRVCC_STATE_CHANGED:
- onSrvccStateChanged(state);
- break;
- default:
- Log.d(mLogTag, "Unknown message received!");
- break;
- }
- }
- }
-
- /**
- * AlternativeEventListener constructor.
- */
- AlternativeEventListener(
- Context context, QnsTelephonyListener qnsTelephonyListener, int slotId) {
- mSlotIndex = slotId;
- mLogTag =
- QnsConstants.QNS_TAG
- + "_"
- + AlternativeEventListener.class.getSimpleName()
- + "_"
- + mSlotIndex;
- mContext = context;
- mQnsTelephonyListener = qnsTelephonyListener;
- mHandler = new AlternativeEventListener.MessageHandler(mContext.getMainLooper());
- mEventCb = new AlternativeEventCb();
- }
-
- /**
- * register emergency preferred transport type changed event.
- *
- * @param h Handler want to receive event.
- * @param what event Id to receive
- * @param userObj user object
- */
- void registerEmergencyPreferredTransportTypeChanged(
- @NonNull Handler h, int what, Object userObj) {
- mEmergencyPreferredTransportTypeChanged = new QnsRegistrant(h, what, userObj);
- }
-
- /** Unregister emergency preferred transport type changed event. */
- void unregisterEmergencyPreferredTransportTypeChanged() {
- mEmergencyPreferredTransportTypeChanged = null;
- }
-
- /**
- * register try WFC connection state change event.
- *
- * @param h Handler want to receive event
- * @param what event Id to receive
- * @param userObj user object
- */
- void registerTryWfcConnectionStateListener(@NonNull Handler h, int what, Object userObj) {
- mTryWfcConnectionState = new QnsRegistrant(h, what, userObj);
- }
-
- /**
- * Register low RTP quality event.
- *
- * @param netCapability Network Capability
- * @param h Handler want to receive event.
- * @param what event Id to receive
- * @param userObj user object
- */
- void registerLowRtpQualityEvent(
- int netCapability,
- @NonNull Handler h,
- int what,
- Object userObj,
- QnsCarrierConfigManager.RtpMetricsConfig config) {
- if (h != null) {
- QnsRegistrant r = new QnsRegistrant(h, what, userObj);
- if (netCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
- mLowRtpQuallityListener = r;
- } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
- mEmcLowRtpQuallityListener = r;
- }
- if (mEventProvider != null) {
- mCallInfoManager.requestRtpThreshold(config);
- }
- }
- }
-
- /**
- * Unregister low RTP quality event.
- *
- * @param netCapability Network Capability
- * @param h Handler want to receive event.
- */
- void unregisterLowRtpQualityEvent(int netCapability, @NonNull Handler h) {
- if (netCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
- mLowRtpQuallityListener = null;
- } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
- mEmcLowRtpQuallityListener = null;
- }
- mCallInfoManager.mRtpMetricsConfig = null;
- }
-
- /**
- * register call type changed event.
- *
- * @param netCapability Network Capability of caller
- * @param h Handler want to receive event.
- * @param what event Id to receive
- * @param userObj user object
- */
- void registerCallTypeChangedListener(
- int netCapability, @NonNull Handler h, int what, Object userObj) {
- if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS
- && netCapability != NetworkCapabilities.NET_CAPABILITY_EIMS) {
- log("registerCallTypeChangedListener : wrong netCapability");
- return;
- }
- if (h != null) {
- QnsRegistrant r = new QnsRegistrant(h, what, userObj);
- if (netCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
- mCallTypeChangedEventListener = r;
- mQnsTelephonyListener.registerSrvccStateListener(
- mHandler, EVENT_SRVCC_STATE_CHANGED, null);
- } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
- mEmergencyCallTypeChangedEventListener = r;
- }
- } else {
- log("registerCallTypeChangedListener : Handler is Null");
- }
- }
-
- /**
- * Unregister call type changed event.
- *
- * @param netCapability Network Capability of caller
- * @param h Handler want to receive event.
- */
- void unregisterCallTypeChangedListener(int netCapability, @NonNull Handler h) {
- if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS
- && netCapability != NetworkCapabilities.NET_CAPABILITY_EIMS) {
- log("unregisterCallTypeChangedListener : wrong netCapability");
- return;
- }
- if (h != null) {
- if (netCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
- mCallTypeChangedEventListener = null;
- mQnsTelephonyListener.unregisterSrvccStateChanged(mHandler);
- } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
- mEmergencyCallTypeChangedEventListener = null;
- }
- } else {
- log("unregisterCallTypeChangedListener : Handler is Null");
- }
- }
-
- /**
- * register EventProvider to EventListener
- *
- * @param provider extends of AlternativeEventProvider
- */
- void setEventProvider(AlternativeEventProvider provider) {
- log("setEventProvider provider " + provider);
- mEventProvider = provider;
- provider.registerCallBack(mEventCb);
- }
-
- @VisibleForTesting
- void onSrvccStateChanged(int srvccState) {
- if (srvccState == TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED) {
- mCallInfoManager.clearCallInfo();
- int callType = QnsConstants.CALL_TYPE_IDLE;
- mCallTypeChangedEventListener.notifyResult(callType);
- }
- }
-
- void clearNormalCallInfo() {
- mCallInfoManager.clearCallInfo();
- mCallInfoManager.mLastReportedCallType = QnsConstants.CALL_TYPE_IDLE;
- unregisterLowRtpQualityEvent(NetworkCapabilities.NET_CAPABILITY_IMS, null);
- }
-
- @VisibleForTesting
- void notifyRtpLowQuality(int callType, int reason) {
- if (callType == QnsConstants.CALL_TYPE_VOICE) {
- if (mLowRtpQuallityListener != null) {
- mLowRtpQuallityListener.notifyResult(reason);
- } else {
- log("notifyRtpLowQuality mLowRtpQuallityListener is null.");
- }
- } else if (callType == QnsConstants.CALL_TYPE_EMERGENCY) {
- if (mEmcLowRtpQuallityListener != null) {
- mEmcLowRtpQuallityListener.notifyResult(reason);
- } 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.");
- }
- }
- }
- }
-
- class AlternativeEventCb implements AlternativeEventProvider.EventCallback {
- @Override
- public void onCallInfoChanged(
- int id,
- @QnsConstants.QnsCallType int type,
- @Annotation.PreciseCallStates int state) {
- log("onCallInfoChanged callId" + id + " type" + type + " state" + state);
-
- mCallInfoManager.updateCallInfo(id, type, state);
- if (type == QnsConstants.CALL_TYPE_EMERGENCY) {
- if (mEmergencyCallTypeChangedEventListener != null) {
- if (state == PRECISE_CALL_STATE_DISCONNECTED) {
- mEmergencyCallTypeChangedEventListener.notifyResult(
- QnsConstants.CALL_TYPE_IDLE);
- } else if (state == PRECISE_CALL_STATE_ACTIVE) {
- mEmergencyCallTypeChangedEventListener.notifyResult(
- QnsConstants.CALL_TYPE_EMERGENCY);
- }
- }
- if (mCallTypeChangedEventListener != null) {
- if ((state == PRECISE_CALL_STATE_ACTIVE
- || state == PRECISE_CALL_STATE_DIALING
- || state == PRECISE_CALL_STATE_ALERTING)
- && !isDataNetworkConnected(NetworkCapabilities.NET_CAPABILITY_EIMS)
- && isDataNetworkConnected(NetworkCapabilities.NET_CAPABILITY_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) {
- int callType = QnsConstants.CALL_TYPE_IDLE;
- if (mCallInfoManager.isCallIdle()) {
- callType = QnsConstants.CALL_TYPE_IDLE;
- } else if (mCallInfoManager.hasVideoCall()) {
- callType = QnsConstants.CALL_TYPE_VIDEO;
- } else {
- callType = QnsConstants.CALL_TYPE_VOICE;
- }
- if (mCallTypeChangedEventListener != null
- && mCallInfoManager.mLastReportedCallType != callType) {
- mCallTypeChangedEventListener.notifyResult(callType);
- mCallInfoManager.mLastReportedCallType = callType;
- }
- }
- }
-
- @Override
- public void onVoiceRtpLowQuality(@QnsConstants.RtpLowQualityReason int reason) {
- if (mCallInfoManager.mEmergencyCallState == PRECISE_CALL_STATE_ACTIVE) {
- notifyRtpLowQuality(QnsConstants.CALL_TYPE_EMERGENCY, reason);
- } else if (!mCallInfoManager.isCallIdle() && !mCallInfoManager.hasVideoCall()) {
- notifyRtpLowQuality(QnsConstants.CALL_TYPE_VOICE, reason);
- }
- }
-
- @Override
- public void onEmergencyPreferenceChanged(int preferredTransportType) {
- if (mEmergencyPreferredTransportTypeChanged != null) {
- mEmergencyPreferredTransportTypeChanged.notifyResult(preferredTransportType);
- }
- }
-
- @Override
- public void onTryWfcConnectionStateChanged(boolean isEnabled) {
- mTryWfcConnectionState.notifyResult(isEnabled);
- }
- }
-
- protected boolean isIdleState() {
- return mCallInfoManager.isCallIdle();
- }
-
- protected void setEcnoSignalThreshold(@Nullable int[] threshold) {
- if (mEventProvider != null) {
- mEventProvider.setEcnoSignalThreshold(threshold);
- }
- }
-
- private boolean isDataNetworkConnected(int netCapability) {
- PreciseDataConnectionState preciseDataStatus =
- mQnsTelephonyListener.getLastPreciseDataConnectionState(netCapability);
-
- 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;
- mEmergencyCallTypeChangedEventListener = null;
- mEmergencyPreferredTransportTypeChanged = null;
- mTryWfcConnectionState = null;
- mLowRtpQuallityListener = null;
- mEmcLowRtpQuallityListener = null;
- sAlternativeInterfaceManager.remove(mSlotIndex);
- }
-
- protected void log(String s) {
- Log.d(mLogTag, s);
- }
-}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/AlternativeEventProvider.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/AlternativeEventProvider.java
deleted file mode 100644
index b2ef78d..0000000
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/AlternativeEventProvider.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2021 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.telephony.qns;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.telephony.AccessNetworkConstants;
-import android.telephony.Annotation;
-import android.util.Log;
-
-/** AlternativeEventProvider class */
-public abstract class AlternativeEventProvider {
- private EventCallback mEventCb;
- private final String mLogTag;
-
- public AlternativeEventProvider(AlternativeEventListener altEventListener, int slotId) {
- mLogTag =
- QnsConstants.QNS_TAG
- + "_"
- + AlternativeEventProvider.class.getSimpleName()
- + "_"
- + slotId;
- altEventListener.setEventProvider(this);
- }
-
- /**
- * Thins is to register RTP threshold.
- *
- * @param callId CallId
- * @param jitter RTP jitter value
- * @param packetLossRate RTP packet loss rate
- * @param packetLossTimeInMilliSec timer for RTP packet loss
- * @param noRtpTimeInMilliSec time for no incoming RTP
- */
- public abstract void requestRtpThreshold(
- int callId,
- int jitter,
- int packetLossRate,
- int packetLossTimeInMilliSec,
- int noRtpTimeInMilliSec);
-
- /**
- * This is to set signal strength threshold.
- *
- * @param threshold signal strength threshold values
- */
- public abstract void setEcnoSignalThreshold(@Nullable int[] threshold);
-
- /**
- * Event provider calls this to notify call info changed.
- *
- * @param id CallId
- * @param type CallType
- * @param state CallState
- */
- public void notifyCallInfo(int id, int type, int state) {
- if (mEventCb != null) {
- mEventCb.onCallInfoChanged(id, type, state);
- }
- }
-
- /**
- * Event provider calls this to notify RTP low quality
- *
- * @param reason RTP low quality reason.
- */
- public void notifyRtpLowQuality(@QnsConstants.RtpLowQualityReason int reason) {
- if (mEventCb != null) {
- mEventCb.onVoiceRtpLowQuality(reason);
- }
- }
-
- /**
- * Event provider needs to call this to notify Emergency preference change
- *
- * @param type Emergency transport type preference for initial data connection.
- */
- public void notifyEmergencyPreferredTransportType(
- @AccessNetworkConstants.TransportType int type) {
- if (mEventCb != null) {
- mEventCb.onEmergencyPreferenceChanged(type);
- }
- }
-
- /**
- * Event provider needs to call this to notify try WFC connection state change
- *
- * @param isEnabled try WFC connection
- */
- public void notifyTryWfcConnectionState(boolean isEnabled) {
- if (mEventCb != null) {
- mEventCb.onTryWfcConnectionStateChanged(isEnabled);
- }
- }
-
- /**
- * Listener need to register CallBack with implements of EventCallback.
- *
- * @param eventCb implements of EventCallback.
- */
- public void registerCallBack(@NonNull EventCallback eventCb) {
- log("registerCallBack" + eventCb);
- mEventCb = eventCb;
- }
-
- /** Event callback for call related item */
- public interface EventCallback {
- /**
- * call type event notification.
- *
- * @param id CallId
- * @param type CallType
- * @param state CallState
- */
- void onCallInfoChanged(
- int id,
- @QnsConstants.QnsCallType int type,
- @Annotation.PreciseCallStates int state);
-
- /**
- * RTP event notification.
- *
- * @param reason reason for RTP low quality
- */
- void onVoiceRtpLowQuality(@QnsConstants.RtpLowQualityReason int reason);
-
- /**
- * Notify Emergency Transport Type Preference for initial connect.
- *
- * @param transport Transport Type
- */
- void onEmergencyPreferenceChanged(@AccessNetworkConstants.TransportType int transport);
-
- /**
- * Try WFC connection state change notification.
- *
- * @param isEnabled flag value for WFC connection state change notification
- */
- void onTryWfcConnectionStateChanged(boolean isEnabled);
- }
-
- protected void log(String s) {
- Log.d(mLogTag, s);
- }
-}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/CellularQualityMonitor.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/CellularQualityMonitor.java
index c2b8d07..c9edc08 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/CellularQualityMonitor.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/CellularQualityMonitor.java
@@ -62,6 +62,7 @@
SignalThresholdInfo.MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED;
private final String mTag;
private TelephonyManager mTelephonyManager;
+ private QnsCarrierConfigManager mConfigManager;
private int mSubId;
private final int mSlotIndex;
private boolean mIsQnsListenerRegistered;
@@ -89,7 +90,10 @@
* @param listener QnsTelephonyListener instance
* @param slotIndex slot index
*/
- CellularQualityMonitor(Context context, QnsTelephonyListener listener, int slotIndex) {
+ CellularQualityMonitor(Context context,
+ QnsCarrierConfigManager configMgr,
+ QnsTelephonyListener listener,
+ int slotIndex) {
super(QualityMonitor.class.getSimpleName() + "-C-" + slotIndex);
mContext = context;
mSlotIndex = slotIndex;
@@ -110,6 +114,7 @@
} else {
Log.e(mTag, "Failed to get Telephony Service");
}
+ mConfigManager = configMgr;
mSignalStrengthListener = new CellularSignalStrengthListener(mContext.getMainExecutor());
mSignalStrengthListener.setSignalStrengthListener(this::onSignalStrengthsChanged);
}
@@ -273,6 +278,9 @@
if (backhaulTime > 0) {
builder.setHysteresisMs(backhaulTime);
}
+ int hysteresisDb = mConfigManager.getWwanHysteresisDbLevel(networkType,
+ measurementType);
+ builder.setHysteresisDb(hysteresisDb);
mSignalThresholdInfoList.add(builder.build());
Log.d(mTag, "Updated SignalThresholdInfo List: " + mSignalThresholdInfoList);
}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsCallStatusTracker.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsCallStatusTracker.java
index f1b6e37..cc1f194 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsCallStatusTracker.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsCallStatusTracker.java
@@ -16,6 +16,8 @@
package com.android.telephony.qns;
+import static com.android.telephony.qns.QnsConstants.INVALID_ID;
+
import android.annotation.NonNull;
import android.net.NetworkCapabilities;
import android.os.Handler;
@@ -50,6 +52,7 @@
private List<CallState> mCallStates = new ArrayList<>();
private QnsRegistrant mCallTypeChangedEventListener;
private QnsRegistrant mEmergencyCallTypeChangedEventListener;
+ private final QnsTimer mQnsTimer;
private int mLastNormalCallType = QnsConstants.CALL_TYPE_IDLE;
private int mLastEmergencyCallType = QnsConstants.CALL_TYPE_IDLE;
private boolean mEmergencyOverIms;
@@ -144,7 +147,6 @@
private static final int EVENT_PACKET_LOSS_TIMER_EXPIRED = 3402;
private static final int EVENT_HYSTERESIS_FOR_NORMAL_QUALITY = 3403;
private static final int EVENT_POLLING_CHECK_LOW_QUALITY = 3404;
- private static final int EVENT_LOW_QUALITY_HANDLER_MAX = 3405;
private static final int STATE_NORMAL_QUALITY = 0;
private static final int STATE_SUSPECT_LOW_QUALITY = 1;
@@ -156,6 +158,9 @@
private static final int LOW_QUALITY_REPORTED_TIME_INITIAL_VALUE = -1;
private int mState = STATE_NORMAL_QUALITY;
+ private int mPacketLossTimerId = INVALID_ID;
+ private int mHysteresisTimerId = INVALID_ID;
+ private int mPollingCheckTimerId = INVALID_ID;
private MediaQualityStatus mMediaQualityStatus;
private String mTag;
@@ -204,12 +209,14 @@
return;
} else {
// check normal quality is stable or not.
- this.sendEmptyMessageDelayed(EVENT_HYSTERESIS_FOR_NORMAL_QUALITY,
+ mHysteresisTimerId = mQnsTimer.registerTimer(
+ Message.obtain(this, EVENT_HYSTERESIS_FOR_NORMAL_QUALITY),
HYSTERESIS_TIME_NORMAL_QUALITY_MILLIS);
}
} else {
// Threshold breached.
- this.removeMessages(EVENT_HYSTERESIS_FOR_NORMAL_QUALITY);
+ mQnsTimer.unregisterTimer(mHysteresisTimerId);
+ mHysteresisTimerId = INVALID_ID;
switch (mState) {
case STATE_NORMAL_QUALITY:
case STATE_SUSPECT_LOW_QUALITY:
@@ -223,7 +230,8 @@
needNotify = true;
}
} else {
- removeMessages(EVENT_PACKET_LOSS_TIMER_EXPIRED);
+ mQnsTimer.unregisterTimer(mPacketLossTimerId);
+ mPacketLossTimerId = INVALID_ID;
enterLowQualityState(status);
needNotify = true;
}
@@ -250,28 +258,30 @@
void enterLowQualityState(MediaQualityStatus status) {
Log.d(mTag, "enterLowQualityState " + status);
mState = STATE_LOW_QUALITY;
- this.sendEmptyMessageDelayed(
- EVENT_POLLING_CHECK_LOW_QUALITY, LOW_QUALITY_CHECK_INTERVAL_MILLIS);
+ mPollingCheckTimerId = mQnsTimer.registerTimer(
+ Message.obtain(this, EVENT_POLLING_CHECK_LOW_QUALITY),
+ LOW_QUALITY_CHECK_INTERVAL_MILLIS);
}
void enterSuspectLowQualityState(int delayMillis) {
Log.d(mTag, "enterSuspectLowQualityState.");
- if (!this.hasMessages(EVENT_PACKET_LOSS_TIMER_EXPIRED)) {
- this.removeMessages(EVENT_PACKET_LOSS_TIMER_EXPIRED);
- }
+ mQnsTimer.unregisterTimer(mPacketLossTimerId);
Log.d(mTag, "Packet loss timer start. " + delayMillis);
Message msg = this.obtainMessage(
EVENT_PACKET_LOSS_TIMER_EXPIRED, mTransportType, 0);
- this.sendMessageDelayed(msg, delayMillis);
+ mPacketLossTimerId = mQnsTimer.registerTimer(msg, delayMillis);
mState = STATE_SUSPECT_LOW_QUALITY;
}
void exitLowQualityState() {
mState = STATE_NORMAL_QUALITY;
- for (int i = EVENT_PACKET_LOSS_TIMER_EXPIRED;
- i < EVENT_LOW_QUALITY_HANDLER_MAX; i++) {
- this.removeMessages(i);
- }
+ this.removeCallbacksAndMessages(null);
+ mQnsTimer.unregisterTimer(mPacketLossTimerId);
+ mQnsTimer.unregisterTimer(mHysteresisTimerId);
+ mQnsTimer.unregisterTimer(mPollingCheckTimerId);
+ mPacketLossTimerId = INVALID_ID;
+ mHysteresisTimerId = INVALID_ID;
+ mPollingCheckTimerId = INVALID_ID;
notifyLowMediaQuality(0);
}
@@ -283,9 +293,10 @@
int reason = thresholdBreached(mMediaQualityStatus);
if (reason > 0) {
notifyLowMediaQuality(thresholdBreached(mMediaQualityStatus));
- } else if (this.hasMessages(EVENT_HYSTERESIS_FOR_NORMAL_QUALITY)) {
+ } else if (mHysteresisTimerId != INVALID_ID) {
// hysteresis time to be normal state is running. let's check after that.
- this.sendEmptyMessageDelayed(EVENT_POLLING_CHECK_LOW_QUALITY,
+ mPollingCheckTimerId = mQnsTimer.registerTimer(
+ Message.obtain(this, EVENT_POLLING_CHECK_LOW_QUALITY),
HYSTERESIS_TIME_NORMAL_QUALITY_MILLIS);
} else {
Log.w(mTag, "Unexpected case.");
@@ -296,19 +307,22 @@
void updateForHandover(int transportType) {
// restart timers that they need to be restarted on new transport type.
if (mState == STATE_SUSPECT_LOW_QUALITY) {
- this.removeMessages(EVENT_PACKET_LOSS_TIMER_EXPIRED);
+ mQnsTimer.unregisterTimer(mPacketLossTimerId);
Message msg = this.obtainMessage(
EVENT_PACKET_LOSS_TIMER_EXPIRED, transportType, 0);
- this.sendMessageDelayed(msg, (mConfigManager.getRTPMetricsData()).mPktLossTime);
+ mPacketLossTimerId = mQnsTimer.registerTimer(msg,
+ (mConfigManager.getRTPMetricsData()).mPktLossTime);
}
- if (this.hasMessages(EVENT_HYSTERESIS_FOR_NORMAL_QUALITY)) {
- this.removeMessages(EVENT_HYSTERESIS_FOR_NORMAL_QUALITY);
- this.sendEmptyMessageDelayed(EVENT_HYSTERESIS_FOR_NORMAL_QUALITY,
+ if (mHysteresisTimerId != INVALID_ID) {
+ mQnsTimer.unregisterTimer(mHysteresisTimerId);
+ mHysteresisTimerId = mQnsTimer.registerTimer(
+ Message.obtain(this, EVENT_HYSTERESIS_FOR_NORMAL_QUALITY),
HYSTERESIS_TIME_NORMAL_QUALITY_MILLIS);
}
if (mState == STATE_LOW_QUALITY) {
- this.removeMessages(EVENT_POLLING_CHECK_LOW_QUALITY);
- this.sendEmptyMessageDelayed(EVENT_POLLING_CHECK_LOW_QUALITY,
+ mQnsTimer.unregisterTimer(mPollingCheckTimerId);
+ mPollingCheckTimerId = mQnsTimer.registerTimer(
+ Message.obtain(this, EVENT_POLLING_CHECK_LOW_QUALITY),
LOW_QUALITY_CHECK_AFTER_HO_MILLIS);
}
}
@@ -727,17 +741,19 @@
}
QnsCallStatusTracker(QnsTelephonyListener telephonyListener,
- QnsCarrierConfigManager configManager, int slotIndex) {
- this(telephonyListener, configManager, slotIndex, null);
+ QnsCarrierConfigManager configManager, QnsTimer qnsTimer, int slotIndex) {
+ this(telephonyListener, configManager, qnsTimer, slotIndex, null);
}
/** Only for test */
@VisibleForTesting
QnsCallStatusTracker(QnsTelephonyListener telephonyListener,
- QnsCarrierConfigManager configManager, int slotIndex, Looper looper) {
+ QnsCarrierConfigManager configManager, QnsTimer qnsTimer, int slotIndex,
+ Looper looper) {
mLogTag = QnsCallStatusTracker.class.getSimpleName() + "_" + slotIndex;
mTelephonyListener = telephonyListener;
mConfigManager = configManager;
+ mQnsTimer = qnsTimer;
mActiveCallTracker = new ActiveCallTracker(slotIndex, looper);
mTelephonyListener.addCallStatesChangedCallback(mCallStatesConsumer);
mTelephonyListener.addSrvccStateChangedCallback(mSrvccStateConsumer);
@@ -801,14 +817,18 @@
}
}
//2. Notify a new ongoing call type
- if (hasEmergencyCall() && mLastEmergencyCallType != QnsConstants.CALL_TYPE_EMERGENCY) {
- mLastEmergencyCallType = QnsConstants.CALL_TYPE_EMERGENCY;
- if (!isDataNetworkConnected(NetworkCapabilities.NET_CAPABILITY_EIMS)
- && isDataNetworkConnected(NetworkCapabilities.NET_CAPABILITY_IMS)) {
- notifyCallType(NetworkCapabilities.NET_CAPABILITY_IMS, mLastEmergencyCallType);
- mEmergencyOverIms = true;
- } else {
- notifyCallType(NetworkCapabilities.NET_CAPABILITY_EIMS, mLastEmergencyCallType);
+ if (hasEmergencyCall()) {
+ if (mLastEmergencyCallType != QnsConstants.CALL_TYPE_EMERGENCY) {
+ mLastEmergencyCallType = QnsConstants.CALL_TYPE_EMERGENCY;
+ if (!isDataNetworkConnected(NetworkCapabilities.NET_CAPABILITY_EIMS)
+ && isDataNetworkConnected(NetworkCapabilities.NET_CAPABILITY_IMS)) {
+ notifyCallType(NetworkCapabilities.NET_CAPABILITY_IMS,
+ mLastEmergencyCallType);
+ mEmergencyOverIms = true;
+ } else {
+ notifyCallType(NetworkCapabilities.NET_CAPABILITY_EIMS,
+ mLastEmergencyCallType);
+ }
}
} else if (hasVideoCall()) {
if (mLastNormalCallType != QnsConstants.CALL_TYPE_VIDEO) {
@@ -842,12 +862,28 @@
} else {
mActiveCallTracker.callStarted(callType, netCapability);
}
+ mQnsTimer.updateCallState(callType);
}
boolean isCallIdle() {
return mCallStates.size() == 0;
}
+ boolean isCallIdle(int netCapability) {
+ int callNum = mCallStates.size();
+ if (callNum == 0) {
+ return true;
+ }
+ if (netCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
+ return (mLastNormalCallType == QnsConstants.CALL_TYPE_IDLE)
+ && (mLastEmergencyCallType != QnsConstants.CALL_TYPE_IDLE
+ && !mEmergencyOverIms);
+ } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
+ return mLastEmergencyCallType == QnsConstants.CALL_TYPE_IDLE || mEmergencyOverIms;
+ }
+ return false;
+ }
+
boolean hasEmergencyCall() {
for (CallState cs : mCallStates) {
if (cs.getImsCallServiceType() == ImsCallProfile.SERVICE_TYPE_EMERGENCY
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsCarrierConfigManager.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsCarrierConfigManager.java
index 1f869d1..ac5b561 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsCarrierConfigManager.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsCarrierConfigManager.java
@@ -46,6 +46,7 @@
import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation.NetCapability;
import android.telephony.CarrierConfigManager;
+import android.telephony.SignalThresholdInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsMmTelManager;
@@ -667,6 +668,20 @@
*/
static final String KEY_SIP_DIALOG_SESSION_POLICY_INT = "qns.sip_dialog_session_policy_int";
+ /**
+ * List of Array items indicating hysteresis db levels based on access network and measurement
+ * type , whose value to be used at api
+ * {@link SignalThresholdInfo#Builder().setHysteresisDb(int)}
+ * The values are set as Format "<accessNetwork>:<meas_type>:<hysteresisDb>"
+ * Ex: "eutran:rsrp:2","ngran:ssrsrp:1"
+ *
+ * The default value or if value set is less than zero,
+ * for this key is {@link QnsConstants#KEY_DEFAULT_VALUE}
+ *
+ */
+ public static final String KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY =
+ "qns.cellular_signal_strength_hysteresis_db_string_array";
+
static HashMap<Integer, String> sAccessNetworkMap =
new HashMap<>() {
{
@@ -755,6 +770,7 @@
private String[] mImsAllowedRats;
private String[] mRoveInGuardTimerConditionThresholdGaps;
private String[] mFallbackOnInitialConnectionFailure;
+ private String[] mAccessNetworkMeasurementHysteresisDb;
@NonNull
private final List<FallbackRule> mFallbackWwanRuleWithImsUnregistered = new ArrayList<>();
@@ -1382,6 +1398,11 @@
KEY_QNS_ROVEIN_THRESHOLD_GAP_WITH_GUARD_TIMER_STRING_ARRAY);
mSipDialogSessionPolicy =
getConfig(bundleCarrier, bundleAsset, KEY_SIP_DIALOG_SESSION_POLICY_INT);
+ mAccessNetworkMeasurementHysteresisDb =
+ getConfig(
+ bundleCarrier,
+ bundleAsset,
+ KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY);
loadFallbackPolicyWithImsRegiFail(bundleCarrier, bundleAsset);
}
@@ -2063,22 +2084,46 @@
int getThresholdGapWithGuardTimer(
@AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType) {
- if (mRoveInGuardTimerConditionThresholdGaps == null) {
+ return getValueForMeasurementType(
+ accessNetwork, measType, mRoveInGuardTimerConditionThresholdGaps);
+
+ }
+
+ /**
+ * This method returns hysteresis Dbm level for ran and measurement type configured.
+ *
+ * @return : Based on Carrier Config Settings & operator requirement Default Value.
+ * Note: If configured value set is less than zero or not set,
+ * {@link QnsConstants#KEY_DEFAULT_VALUE}
+ */
+ public int getWwanHysteresisDbLevel(
+ @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType) {
+
+ int hysteresisDb = getValueForMeasurementType(
+ accessNetwork, measType, mAccessNetworkMeasurementHysteresisDb);
+ return hysteresisDb >= 0 ? hysteresisDb : QnsConstants.KEY_DEFAULT_VALUE;
+ }
+
+ private int getValueForMeasurementType(
+ @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType,
+ String [] measurementValues) {
+
+ if (measurementValues == null) {
return QnsConstants.KEY_DEFAULT_VALUE;
}
- if (!mRoveInGuardTimerConditionThresholdGaps[0].isEmpty()) {
- for (String check_offset : mRoveInGuardTimerConditionThresholdGaps) {
- String[] gap = check_offset.split(":");
- String access_network = sAccessNetworkMap.get(accessNetwork);
- String measurement_Type = sMeasTypeMap.get(measType);
- try {
- if (gap[0].equalsIgnoreCase(access_network)
- && gap[1].equalsIgnoreCase(measurement_Type)) {
- return Integer.parseInt(gap[2]);
- }
- } catch (Exception e) {
+ for (String check_offset : measurementValues) {
+ if (check_offset == null || check_offset.isEmpty()) continue;
+ String[] value = check_offset.split(":");
+ String access_network = sAccessNetworkMap.get(accessNetwork);
+ String measurement_Type = sMeasTypeMap.get(measType);
+ try {
+ if (value.length == 3 && value[0].equalsIgnoreCase(access_network)
+ && value[1].equalsIgnoreCase(measurement_Type)) {
+ return Integer.parseInt(value[2]);
}
+ } catch (Exception e) {
+ e.printStackTrace();
}
}
return QnsConstants.KEY_DEFAULT_VALUE;
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsComponents.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsComponents.java
index 1c9b898..0471ea8 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsComponents.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsComponents.java
@@ -22,6 +22,7 @@
import com.android.internal.annotations.VisibleForTesting;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -33,7 +34,6 @@
private final String mLogTag = QnsComponents.class.getSimpleName();
private final Context mContext;
- private final SparseArray<AlternativeEventListener> mAlternativeEventListeners;
private final SparseArray<CellularNetworkStatusTracker> mCellularNetworkStatusTrackers;
private final SparseArray<CellularQualityMonitor> mCellularQualityMonitors;
private final SparseArray<QnsImsManager> mQnsImsManagers;
@@ -45,12 +45,13 @@
private final SparseArray<WifiBackhaulMonitor> mWifiBackhaulMonitors;
private final List<Integer> mSlotIds;
private IwlanNetworkStatusTracker mIwlanNetworkStatusTracker;
+ private QnsTimer mQnsTimer;
private WifiQualityMonitor mWifiQualityMonitor;
+ private QnsMetrics mQnsMetrics;
/** Constructor to instantiate QnsComponents class. */
QnsComponents(Context context) {
mContext = context;
- mAlternativeEventListeners = new SparseArray<>();
mCellularNetworkStatusTrackers = new SparseArray<>();
mCellularQualityMonitors = new SparseArray<>();
mQnsImsManagers = new SparseArray<>();
@@ -68,15 +69,9 @@
mSlotIds.add(slotId);
mQnsTelephonyListeners.put(slotId, new QnsTelephonyListener(mContext, slotId));
mQnsImsManagers.put(slotId, new QnsImsManager(mContext, slotId));
- mAlternativeEventListeners.put(
- slotId,
- new AlternativeEventListener(mContext, mQnsTelephonyListeners.get(slotId), slotId));
mCellularNetworkStatusTrackers.put(
slotId,
new CellularNetworkStatusTracker(mQnsTelephonyListeners.get(slotId), slotId));
- mCellularQualityMonitors.put(
- slotId,
- new CellularQualityMonitor(mContext, mQnsTelephonyListeners.get(slotId), slotId));
mQnsProvisioningListeners.put(
slotId, new QnsProvisioningListener(mContext, mQnsImsManagers.get(slotId), slotId));
mQnsEventDispatchers.put(
@@ -89,20 +84,32 @@
mQnsCarrierConfigManagers.put(
slotId,
new QnsCarrierConfigManager(mContext, mQnsEventDispatchers.get(slotId), slotId));
+ mCellularQualityMonitors.put(
+ slotId,
+ new CellularQualityMonitor(mContext,
+ mQnsCarrierConfigManagers.get(slotId),
+ mQnsTelephonyListeners.get(slotId),
+ slotId));
+ if (mQnsTimer == null) {
+ mQnsTimer = new QnsTimer(mContext);
+ }
mQnsCallStatusTracker.put(
slotId,
- new QnsCallStatusTracker(mQnsTelephonyListeners.get(slotId),
- mQnsCarrierConfigManagers.get(slotId), slotId));
+ new QnsCallStatusTracker(
+ mQnsTelephonyListeners.get(slotId),
+ mQnsCarrierConfigManagers.get(slotId),
+ mQnsTimer,
+ slotId));
mWifiBackhaulMonitors.put(
slotId,
new WifiBackhaulMonitor(
mContext,
mQnsCarrierConfigManagers.get(slotId),
mQnsImsManagers.get(slotId),
+ mQnsTimer,
slotId));
-
if (mWifiQualityMonitor == null) {
- mWifiQualityMonitor = new WifiQualityMonitor(mContext);
+ mWifiQualityMonitor = new WifiQualityMonitor(mContext, mQnsTimer);
}
if (mIwlanNetworkStatusTracker == null) {
mIwlanNetworkStatusTracker = new IwlanNetworkStatusTracker(mContext);
@@ -113,6 +120,9 @@
mQnsImsManagers.get(slotId),
mQnsTelephonyListeners.get(slotId),
slotId);
+ if (mQnsMetrics == null) {
+ mQnsMetrics = new QnsMetrics(mContext);
+ }
Log.d(mLogTag, "QnsComponents created for slot " + slotId);
}
@@ -120,7 +130,6 @@
@VisibleForTesting
QnsComponents(
Context context,
- AlternativeEventListener alternativeEventListener,
CellularNetworkStatusTracker cellularNetworkStatusTracker,
CellularQualityMonitor cellularQualityMonitor,
IwlanNetworkStatusTracker iwlanNetworkStatusTracker,
@@ -130,14 +139,15 @@
QnsProvisioningListener qnsProvisioningListener,
QnsTelephonyListener qnsTelephonyListener,
QnsCallStatusTracker qnsCallStatusTracker,
+ QnsTimer qnsTimer,
WifiBackhaulMonitor wifiBackhaulMonitor,
WifiQualityMonitor wifiQualityMonitor,
+ QnsMetrics qnsMetrics,
int slotId) {
this(context);
mSlotIds.add(slotId);
mQnsTelephonyListeners.put(slotId, qnsTelephonyListener);
mQnsImsManagers.put(slotId, qnsImsManager);
- mAlternativeEventListeners.put(slotId, alternativeEventListener);
mCellularNetworkStatusTrackers.put(slotId, cellularNetworkStatusTracker);
mCellularQualityMonitors.put(slotId, cellularQualityMonitor);
mQnsCallStatusTracker.put(slotId, qnsCallStatusTracker);
@@ -148,6 +158,7 @@
mWifiBackhaulMonitors.put(slotId, wifiBackhaulMonitor);
mWifiQualityMonitor = wifiQualityMonitor;
+ mQnsTimer = qnsTimer;
mIwlanNetworkStatusTracker = iwlanNetworkStatusTracker;
mIwlanNetworkStatusTracker.initBySlotIndex(
qnsCarrierConfigManager,
@@ -155,11 +166,7 @@
qnsImsManager,
qnsTelephonyListener,
slotId);
- }
-
- /** Returns instance of AlternativeEventListener for given slotId. */
- AlternativeEventListener getAlternativeEventListener(int slotId) {
- return mAlternativeEventListeners.get(slotId);
+ mQnsMetrics = qnsMetrics;
}
/** Returns instance of CellularNetworkStatusTracker for given slotId. */
@@ -217,6 +224,16 @@
return mWifiQualityMonitor;
}
+ /** Returns instance of QnsTimer. */
+ QnsTimer getQnsTimer() {
+ return mQnsTimer;
+ }
+
+ /** Returns instance of WifiQualityMonitor. */
+ QnsMetrics getQnsMetrics() {
+ return mQnsMetrics;
+ }
+
/** Returns context. */
Context getContext() {
return mContext;
@@ -229,8 +246,10 @@
if (mSlotIds.size() == 1) {
mIwlanNetworkStatusTracker.close();
mWifiQualityMonitor.close();
+ mQnsMetrics.close();
mIwlanNetworkStatusTracker = null;
mWifiQualityMonitor = null;
+ mQnsMetrics = null;
}
WifiBackhaulMonitor wifiBackhaulMonitor = mWifiBackhaulMonitors.get(slotId);
@@ -243,6 +262,15 @@
mQnsCallStatusTracker.remove(slotId);
qnsCallStatusTracker.close();
}
+ if (mSlotIds.size() == 1) {
+ mQnsTimer.close();
+ mQnsTimer = null;
+ }
+ CellularQualityMonitor cellularQualityMonitor = mCellularQualityMonitors.get(slotId);
+ if (cellularQualityMonitor != null) {
+ mCellularQualityMonitors.remove(slotId);
+ cellularQualityMonitor.close();
+ }
QnsCarrierConfigManager qnsCarrierConfigManager = mQnsCarrierConfigManagers.get(slotId);
if (qnsCarrierConfigManager != null) {
mQnsCarrierConfigManagers.remove(slotId);
@@ -258,21 +286,11 @@
mQnsProvisioningListeners.remove(slotId);
qnsProvisioningListener.close();
}
- CellularQualityMonitor cellularQualityMonitor = mCellularQualityMonitors.get(slotId);
- if (cellularQualityMonitor != null) {
- mCellularQualityMonitors.remove(slotId);
- cellularQualityMonitor.close();
- }
CellularNetworkStatusTracker cellularTracker = mCellularNetworkStatusTrackers.get(slotId);
if (cellularTracker != null) {
mCellularNetworkStatusTrackers.remove(slotId);
cellularTracker.close();
}
- AlternativeEventListener alternativeEventListener = mAlternativeEventListeners.get(slotId);
- if (alternativeEventListener != null) {
- mAlternativeEventListeners.remove(slotId);
- alternativeEventListener.close();
- }
QnsImsManager qnsImsManager = mQnsImsManagers.get(slotId);
if (qnsImsManager != null) {
mQnsImsManagers.remove(slotId);
@@ -287,4 +305,16 @@
mSlotIds.remove(Integer.valueOf(slotId));
Log.d(mLogTag, "QnsComponents closed for slot " + slotId);
}
+
+ void dump(PrintWriter pw) {
+ if (mIwlanNetworkStatusTracker != null) {
+ mIwlanNetworkStatusTracker.dump(pw, " ");
+ }
+ if (mIwlanNetworkStatusTracker != null) {
+ mWifiQualityMonitor.dump(pw, " ");
+ }
+ if (mIwlanNetworkStatusTracker != null) {
+ mQnsTimer.dump(pw, " ");
+ }
+ }
}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsMetrics.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsMetrics.java
new file mode 100644
index 0000000..d936d0b
--- /dev/null
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsMetrics.java
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns;
+
+import android.content.Context;
+import android.net.NetworkCapabilities;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.SignalThresholdInfo;
+import android.telephony.qns.QnsProtoEnums;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.telephony.qns.DataConnectionStatusTracker.DataConnectionChangedInfo;
+import com.android.telephony.qns.QualifiedNetworksServiceImpl.QualifiedNetworksInfo;
+import com.android.telephony.qns.atoms.AtomsQnsFallbackRestrictionChangedInfo;
+import com.android.telephony.qns.atoms.AtomsQnsHandoverPingPongInfo;
+import com.android.telephony.qns.atoms.AtomsQnsHandoverTimeMillisInfo;
+import com.android.telephony.qns.atoms.AtomsQnsImsCallDropStats;
+import com.android.telephony.qns.atoms.AtomsQnsRatPreferenceMismatchInfo;
+import com.android.telephony.qns.atoms.AtomsQualifiedRatListChangedInfo;
+import com.android.telephony.statslib.StatsLib;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** QnsStats class */
+class QnsMetrics {
+
+ private StatsLib mStats;
+ private final String mLogTag;
+ private final Handler mHandler;
+ private final HandlerThread mHandlerThread;
+
+ // For HandoverTIme.
+ private final ConcurrentHashMap<Integer, HandoverTimeStateMachine> mHandoverTimeMap;
+ private final ConcurrentHashMap<Integer, PingPongTime> mPingPongTime;
+ private final ConcurrentHashMap<Integer, RatMismatchTime> mRatMismatchTime;
+ private final ConcurrentHashMap<Integer, RtpCallDrop> mRtpCallDrop;
+
+ /** Constructor */
+ QnsMetrics(Context context) {
+ mStats = new StatsLib(context);
+ mLogTag = QnsMetrics.class.getSimpleName();
+
+ mHandoverTimeMap = new ConcurrentHashMap<>();
+ mPingPongTime = new ConcurrentHashMap<>();
+ mRatMismatchTime = new ConcurrentHashMap<>();
+ mRtpCallDrop = new ConcurrentHashMap<>();
+
+ mHandlerThread = new HandlerThread(QnsMetrics.class.getSimpleName());
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
+
+ @VisibleForTesting
+ QnsMetrics(StatsLib statsLib) {
+ mStats = statsLib;
+ mLogTag = QnsMetrics.class.getSimpleName();
+
+ mHandoverTimeMap = new ConcurrentHashMap<>();
+ mPingPongTime = new ConcurrentHashMap<>();
+ mRatMismatchTime = new ConcurrentHashMap<>();
+ mRtpCallDrop = new ConcurrentHashMap<>();
+
+ mHandlerThread = new HandlerThread(QnsMetrics.class.getSimpleName());
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
+
+ @VisibleForTesting
+ Handler getHandler() {
+ return mHandler;
+ }
+
+ /** close */
+ public void close() {
+ mStats = null;
+ mHandlerThread.quitSafely();
+ }
+
+ /**
+ * Report atoms when the qualified access network is reported.
+ *
+ * @param info QualifiedNetworksInfo
+ * @param slotId slot index
+ * @param dataConnectionCurrentTransportType transportType currently stayed in.
+ * @param coverage coverage home or roam.
+ * @param settingWfcEnabled setting for wfc
+ * @param settingWfcRoamingEnabled roaming setting for wfc
+ * @param settingWfcMode setting for wfc mode
+ * @param settingWfcRoamingMode roaming setting for wfc mode
+ * @param cellularAccessNetworkType cellular rat
+ * @param iwlanAvailable iwlan available
+ * @param isCrossWfc cross sim wfc enabled
+ * @param restrictManager restriction manager
+ * @param cellularQualityMonitor cellular quality monitor
+ * @param wifiQualityMonitor wifi quality monitor
+ * @param callType call type
+ */
+ public void reportAtomForQualifiedNetworks(
+ QualifiedNetworksInfo info,
+ int slotId,
+ int dataConnectionCurrentTransportType,
+ int coverage,
+ boolean settingWfcEnabled,
+ boolean settingWfcRoamingEnabled,
+ int settingWfcMode,
+ int settingWfcRoamingMode,
+ int cellularAccessNetworkType,
+ boolean iwlanAvailable,
+ boolean isCrossWfc,
+ RestrictManager restrictManager,
+ QualityMonitor cellularQualityMonitor,
+ QualityMonitor wifiQualityMonitor,
+ int callType) {
+ mHandler.post(() -> procQualifiedNetworksForHandoverTime(info, slotId));
+ mHandler.post(() ->
+ procQualifiedRatListChanged(
+ info,
+ slotId,
+ dataConnectionCurrentTransportType,
+ coverage,
+ settingWfcEnabled,
+ settingWfcRoamingEnabled,
+ settingWfcMode,
+ settingWfcRoamingMode,
+ cellularAccessNetworkType,
+ iwlanAvailable,
+ isCrossWfc,
+ restrictManager,
+ cellularQualityMonitor,
+ wifiQualityMonitor,
+ callType));
+ }
+
+ /**
+ * Report atom when data connection is changed
+ *
+ * @param netCapability Network Capability
+ * @param slotId slot Index
+ * @param info DataConnectionChangedInfo
+ * @param carrierId carrier id.
+ */
+ public void reportAtomForDataConnectionChanged(
+ int netCapability, int slotId, DataConnectionChangedInfo info, int carrierId) {
+ mHandler.post(() -> procDataConnectionChangedForHandoverTime(netCapability, slotId, info));
+ mHandler.post(() -> procDataConnectionChangedForHandoverPingPong(
+ netCapability, slotId, info, carrierId));
+ mHandler.post(() -> procDataConnectionChangedForRatMismatch(
+ netCapability, slotId, info, carrierId));
+ }
+
+ /**
+ * Report atom when a restriction is set.
+ *
+ * @param netCapability Network Capability
+ * @param slotId slot Index
+ * @param wlanRestrictions list of restrictions on wlan
+ * @param wwanRestrictions list of restrictions on wwan
+ * @param carrierId carrier id.
+ */
+ public void reportAtomForRestrictions(
+ int netCapability,
+ int slotId,
+ List<Integer> wlanRestrictions,
+ List<Integer> wwanRestrictions,
+ int carrierId) {
+ mHandler.post(() -> procRestrictionsForFallback(
+ netCapability, slotId, wlanRestrictions, wwanRestrictions, carrierId));
+ }
+
+ /**
+ * Report atom when call type change
+ *
+ * @param netCapability Network Capability
+ * @param slotId slot Index
+ * @param oldCallType previous call type
+ * @param newCallType new call type
+ * @param restrictManager restriction manager
+ * @param transportTypeOfCall transport type in call
+ */
+ public void reportAtomForCallTypeChanged(
+ int netCapability,
+ int slotId,
+ int oldCallType,
+ int newCallType,
+ RestrictManager restrictManager,
+ int transportTypeOfCall) {
+ mHandler.post(() -> procCallTypeChangedForImsCallDrop(netCapability, slotId,
+ oldCallType, newCallType, restrictManager, transportTypeOfCall));
+ }
+
+ /**
+ * Report atom when ims call is dropped
+ *
+ * @param netCapability Network Capability
+ * @param slotId slot Index
+ * @param restrictManager restriction manager
+ * @param cellularQualityMonitor cellular quality monitor
+ * @param wifiQualityMonitor wifi quality monitor
+ * @param transportTypeOfCall transport type in call
+ * @param cellularAccessNetworkType cellular access network
+ */
+ public void reportAtomForImsCallDropStats(
+ int netCapability,
+ int slotId,
+ RestrictManager restrictManager,
+ QualityMonitor cellularQualityMonitor,
+ QualityMonitor wifiQualityMonitor,
+ int transportTypeOfCall,
+ int cellularAccessNetworkType) {
+ mHandler.post(() -> procCallDroppedForImsCallDrop(netCapability, slotId, restrictManager,
+ cellularQualityMonitor, wifiQualityMonitor, transportTypeOfCall,
+ cellularAccessNetworkType));
+ }
+
+ private void procQualifiedRatListChanged(
+ QualifiedNetworksInfo info,
+ int slotId,
+ int dataConnectedTransportType,
+ int coverage,
+ boolean settingWfcEnabled,
+ boolean settingWfcRoamingEnabled,
+ int settingWfcMode,
+ int settingWfcRoamingMode,
+ int cellularAccessNetworkType,
+ boolean iwlanAvailable,
+ boolean isCrossWfc,
+ RestrictManager restrictManager,
+ QualityMonitor cellularQualityMonitor,
+ QualityMonitor wifiQualityMonitor,
+ int callType) {
+ int netCapability = info.getNetCapability();
+ int firstQualifiedRat = getQualifiedAccessNetwork(info, 0);
+ int secondQualifiedRat = getQualifiedAccessNetwork(info, 1);
+ boolean wfcEnabled = getWfcEnabled(coverage, settingWfcEnabled, settingWfcRoamingEnabled);
+ int wfcMode = getWfcMode(coverage, settingWfcMode, settingWfcRoamingMode);
+ int iwlanNetworkType = getIwlanNetworkType(iwlanAvailable, isCrossWfc);
+ int restrictionsOnWwan = getRestrictionsBitmask(
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN, restrictManager);
+ int restrictionsOnWlan = getRestrictionsBitmask(
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN, restrictManager);
+ int signalStrength = getSignalStrength(cellularQualityMonitor, cellularAccessNetworkType);
+ int signalQuality = getSignalQuality(cellularQualityMonitor, cellularAccessNetworkType);
+ int signalNoise = getSignalNoise(cellularQualityMonitor, cellularAccessNetworkType);
+ int iwlanSignalStrength = getSignalStrength(wifiQualityMonitor, AccessNetworkType.IWLAN);
+ int updateReason = 0;
+ int imsCallQuality = 0;
+
+ writeQualifiedRatListChangedInfo(
+ netCapability,
+ slotId,
+ firstQualifiedRat,
+ secondQualifiedRat,
+ dataConnectedTransportType,
+ wfcEnabled,
+ wfcMode,
+ cellularAccessNetworkType,
+ iwlanNetworkType,
+ restrictionsOnWwan,
+ restrictionsOnWlan,
+ signalStrength,
+ signalQuality,
+ signalNoise,
+ iwlanSignalStrength,
+ updateReason,
+ callType,
+ imsCallQuality);
+ }
+
+
+ private void procQualifiedNetworksForHandoverTime(QualifiedNetworksInfo info, int slotId) {
+ if (info.getNetCapability() != NetworkCapabilities.NET_CAPABILITY_IMS) {
+ return;
+ }
+
+ HandoverTimeStateMachine handoverTimeStateMachine = mHandoverTimeMap.get(slotId);
+ if (handoverTimeStateMachine == null) {
+ handoverTimeStateMachine =
+ new HandoverTimeStateMachine(info.getNetCapability(), slotId, mHandler);
+ mHandoverTimeMap.put(slotId, handoverTimeStateMachine);
+ }
+
+ handoverTimeStateMachine.sendQualifiedRatChanged(info);
+ }
+
+ private void procDataConnectionChangedForHandoverTime(
+ int netCapability, int slotId, DataConnectionChangedInfo info) {
+ if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS) {
+ return;
+ }
+
+ HandoverTimeStateMachine handoverTimeStateMachine = mHandoverTimeMap.get(slotId);
+ if (handoverTimeStateMachine == null) {
+ handoverTimeStateMachine =
+ new HandoverTimeStateMachine(netCapability, slotId, mHandler);
+ mHandoverTimeMap.put(slotId, handoverTimeStateMachine);
+ }
+
+ handoverTimeStateMachine.sendDataStateChanged(info);
+ }
+
+ private void procDataConnectionChangedForHandoverPingPong(int netCapability, int slotId,
+ DataConnectionChangedInfo info, int carrierId) {
+ if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS) {
+ return;
+ }
+
+ PingPongTime pingPongTime = mPingPongTime.get(slotId);
+ if (pingPongTime == null) {
+ pingPongTime = new PingPongTime();
+ mPingPongTime.put(slotId, pingPongTime);
+ }
+
+ boolean bActiveState;
+ switch (info.getState()) {
+ case DataConnectionStatusTracker.STATE_INACTIVE:
+ case DataConnectionStatusTracker.STATE_CONNECTING:
+ bActiveState = false;
+ break;
+ case DataConnectionStatusTracker.STATE_CONNECTED:
+ case DataConnectionStatusTracker.STATE_HANDOVER:
+ default:
+ bActiveState = true;
+ break;
+ }
+ switch (info.getEvent()) {
+ case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED:
+ pingPongTime.mSuccessTime = QnsUtils.getSystemElapsedRealTime();
+ pingPongTime.mHandoverCount = 0;
+ break;
+ case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED:
+ pingPongTime.mStartTime = QnsUtils.getSystemElapsedRealTime();
+ break;
+ case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS:
+ pingPongTime.mHandoverCount++;
+ pingPongTime.mSuccessTime = QnsUtils.getSystemElapsedRealTime();
+ break;
+ }
+
+ if (pingPongTime.mStartTime != 0L && pingPongTime.mSuccessTime != 0L) {
+ long pingPongTimeLimit = AtomsQnsHandoverPingPongInfo.PING_PONG_TIME_IN_MILLIS;
+ long elapsed =
+ (pingPongTime.mSuccessTime > pingPongTime.mStartTime)
+ ? (pingPongTime.mSuccessTime - pingPongTime.mStartTime)
+ : (pingPongTime.mStartTime - pingPongTime.mSuccessTime);
+ if (pingPongTime.mHandoverCount > 0) {
+ log("HandoverPingPong elapsed:" + elapsed
+ + " ping-pong count:" + (pingPongTime.mHandoverCount / 2));
+ }
+ if (elapsed > pingPongTimeLimit || !bActiveState) {
+ if (pingPongTime.mHandoverCount > 1) {
+ int pingpongCount = pingPongTime.mHandoverCount / 2;
+ writeQnsHandoverPingPong(slotId, pingpongCount, carrierId);
+ }
+ pingPongTime.mHandoverCount = 0;
+ pingPongTime.mStartTime = 0L;
+ pingPongTime.mSuccessTime = 0L;
+ procDataConnectionChangedForHandoverPingPong(
+ netCapability, slotId, info, carrierId);
+ }
+ }
+ if (!bActiveState) {
+ pingPongTime.mHandoverCount = 0;
+ pingPongTime.mStartTime = 0L;
+ pingPongTime.mSuccessTime = 0L;
+ }
+ }
+
+ private void procRestrictionsForFallback(int netCapability, int slotId,
+ List<Integer> wlanRestrictions, List<Integer> wwanRestrictions, int carrierId) {
+ if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS
+ || wlanRestrictions == null
+ || wwanRestrictions == null) {
+ return;
+ }
+
+ boolean bRestrictionOnWlanByRtpThresholdBreached =
+ wlanRestrictions.contains(RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY);
+ boolean bRestrictionOnWwanByRtpThresholdBreached =
+ wwanRestrictions.contains(RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY);
+ boolean bRestrictionOnWlanByImsRegistrationFailed =
+ wlanRestrictions.contains(
+ RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL);
+ boolean bRestrictionOnWlanByWifiBackhaulProblem =
+ wlanRestrictions.contains(
+ RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL);
+
+ // all false will not write atom because this atom is used for count metric.
+ if (bRestrictionOnWlanByRtpThresholdBreached
+ || bRestrictionOnWwanByRtpThresholdBreached
+ || bRestrictionOnWlanByImsRegistrationFailed
+ || bRestrictionOnWlanByWifiBackhaulProblem) {
+ writeQnsFallbackRestrictionChangedInfo(
+ bRestrictionOnWlanByRtpThresholdBreached,
+ bRestrictionOnWwanByRtpThresholdBreached,
+ bRestrictionOnWlanByImsRegistrationFailed,
+ bRestrictionOnWlanByWifiBackhaulProblem,
+ carrierId,
+ slotId);
+ }
+ }
+
+ private void procDataConnectionChangedForRatMismatch(
+ int netCapability, int slotId, DataConnectionChangedInfo info, int carrierId) {
+
+ RatMismatchTime mismatchTime = mRatMismatchTime.get(slotId);
+ if (mismatchTime == null) {
+ mismatchTime = new RatMismatchTime();
+ mRatMismatchTime.put(slotId, mismatchTime);
+ }
+
+ switch (info.getEvent()) {
+ case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED:
+ if (mismatchTime.mCount == 0) {
+ mismatchTime.mStartTime = QnsUtils.getSystemElapsedRealTime();
+ }
+ break;
+ case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED:
+ mismatchTime.mCount++;
+ break;
+ default:
+ if (mismatchTime.mCount > 0) {
+ long duration = QnsUtils.getSystemElapsedRealTime() - mismatchTime.mStartTime;
+ int count = mismatchTime.mCount;
+
+ writeQnsRatPreferenceMismatchInfo(
+ netCapability, count, (int) duration, carrierId, slotId);
+ mismatchTime.mCount = 0;
+ mismatchTime.mStartTime = 0L;
+ }
+ break;
+ }
+ }
+
+ private void writeQualifiedRatListChangedInfo(
+ int netCapability,
+ int slotId,
+ int firstQualifiedRat,
+ int secondQualifiedRat,
+ int currentTransportType,
+ boolean wfcEnabled,
+ int wfcMode,
+ int cellularNetworkType,
+ int iwlanNetworkType,
+ int restrictionsOnWwan,
+ int restrictionsOnWlan,
+ int signalStrength,
+ int signalQuality,
+ int signalNoise,
+ int iwlanSignalStrength,
+ int updateReason,
+ int imsCallType,
+ int imsCallQuality) {
+ AtomsQualifiedRatListChangedInfo atoms =
+ new AtomsQualifiedRatListChangedInfo(
+ netCapability,
+ firstQualifiedRat,
+ secondQualifiedRat,
+ currentTransportType,
+ wfcEnabled,
+ wfcMode,
+ cellularNetworkType,
+ iwlanNetworkType,
+ restrictionsOnWwan,
+ restrictionsOnWlan,
+ signalStrength,
+ signalQuality,
+ signalNoise,
+ iwlanSignalStrength,
+ updateReason,
+ imsCallType,
+ imsCallQuality,
+ slotId);
+ mStats.write(atoms);
+ }
+
+
+ private void writeQnsHandoverTimeMillisInfo(long handoverTime, int slotIndex) {
+ AtomsQnsHandoverTimeMillisInfo atoms =
+ new AtomsQnsHandoverTimeMillisInfo((int) handoverTime, slotIndex);
+ mStats.append(atoms);
+ }
+
+ private void writeQnsHandoverPingPong(int slotId, int pingPongCount, int carrierId) {
+ AtomsQnsHandoverPingPongInfo atoms =
+ new AtomsQnsHandoverPingPongInfo(pingPongCount, carrierId, slotId);
+ mStats.append(atoms);
+ }
+
+ private void writeQnsFallbackRestrictionChangedInfo(
+ boolean bRestrictionOnWlanByRtpThresholdBreached,
+ boolean bRestrictionOnWwanByRtpThresholdBreached,
+ boolean bRestrictionOnWlanByImsRegistrationFailed,
+ boolean bRestrictionOnWlanByWifiBackhaulProblem,
+ int carrierId,
+ int slotId) {
+ AtomsQnsFallbackRestrictionChangedInfo atom =
+ new AtomsQnsFallbackRestrictionChangedInfo(
+ bRestrictionOnWlanByRtpThresholdBreached,
+ bRestrictionOnWwanByRtpThresholdBreached,
+ bRestrictionOnWlanByImsRegistrationFailed,
+ bRestrictionOnWlanByWifiBackhaulProblem,
+ carrierId,
+ slotId);
+ mStats.write(atom);
+ }
+
+ private void writeQnsRatPreferenceMismatchInfo(int netCapability, int handoverFailCount,
+ int durationMismatch, int carrierId, int slotId) {
+ AtomsQnsRatPreferenceMismatchInfo atoms = new AtomsQnsRatPreferenceMismatchInfo(
+ netCapability, handoverFailCount, durationMismatch, carrierId, slotId);
+ mStats.append(atoms);
+ }
+
+ class HandoverTimeStateMachine extends StateMachine {
+
+ private static final int EVENT_DATA_STATE_CHANGED = 0;
+ private static final int EVENT_QUALIFIED_RAT_CHANGED = 1;
+
+ private final IdleState mIdleState;
+ private final ConnectedState mConnectedState;
+ private final HandoverRequestedState mHandoverRequestedState;
+ private final HandoverInProgressState mHandoverInProgressState;
+
+ private final int mNetCapability;
+ private final int mSlotId;
+ int mDataTransportType;
+ long mHandoverRequestedTime;
+
+ HandoverTimeStateMachine(int netCapability, int slotId, Handler handler) {
+ super(mLogTag + "_" + HandoverTimeStateMachine.class.getSimpleName() + "_" + slotId
+ + "_" + QnsUtils.getNameOfNetCapability(netCapability), handler);
+
+ mIdleState = new IdleState();
+ mConnectedState = new ConnectedState();
+ mHandoverRequestedState = new HandoverRequestedState();
+ mHandoverInProgressState = new HandoverInProgressState();
+
+ mNetCapability = netCapability;
+ mSlotId = slotId;
+ mDataTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+ mHandoverRequestedTime = 0L;
+
+ addState(mIdleState);
+ addState(mConnectedState);
+ addState(mHandoverRequestedState);
+ addState(mHandoverInProgressState);
+ setInitialState(mIdleState);
+ start();
+ }
+
+ public void sendDataStateChanged(DataConnectionChangedInfo info) {
+ sendMessage(EVENT_DATA_STATE_CHANGED, info);
+ }
+
+ public void sendQualifiedRatChanged(QualifiedNetworksInfo info) {
+ sendMessage(EVENT_QUALIFIED_RAT_CHANGED, info);
+ }
+
+ private final class IdleState extends State {
+ @Override
+ public void enter() {
+ log("IdleState");
+ mDataTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+ mHandoverRequestedTime = 0L;
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ log("IdleState processMessage=" + msg.what);
+ switch (msg.what) {
+ case EVENT_DATA_STATE_CHANGED:
+ DataConnectionChangedInfo dataInfo = (DataConnectionChangedInfo) msg.obj;
+ switch (dataInfo.getState()) {
+ case DataConnectionStatusTracker.STATE_CONNECTED:
+ mDataTransportType = dataInfo.getTransportType();
+ transitionTo(mConnectedState);
+ return HANDLED;
+ case DataConnectionStatusTracker.STATE_HANDOVER:
+ mDataTransportType = dataInfo.getTransportType();
+ transitionTo(mConnectedState);
+ break;
+ }
+ break;
+ case EVENT_QUALIFIED_RAT_CHANGED:
+ break;
+ }
+ return super.processMessage(msg);
+ }
+
+ @Override
+ public void exit() {
+ super.exit();
+ }
+ }
+
+ private final class ConnectedState extends State {
+ @Override
+ public void enter() {
+ log("ConnectedState");
+ mHandoverRequestedTime = 0L;
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ log("ConnectedState processMessage=" + msg.what);
+ switch (msg.what) {
+ case EVENT_DATA_STATE_CHANGED:
+ DataConnectionChangedInfo dataInfo = (DataConnectionChangedInfo) msg.obj;
+ switch (dataInfo.getState()) {
+ case DataConnectionStatusTracker.STATE_INACTIVE:
+ case DataConnectionStatusTracker.STATE_CONNECTING:
+ transitionTo(mIdleState);
+ break;
+ case DataConnectionStatusTracker.STATE_CONNECTED:
+ case DataConnectionStatusTracker.STATE_HANDOVER:
+ mDataTransportType = dataInfo.getTransportType();
+ return HANDLED;
+ }
+ break;
+ case EVENT_QUALIFIED_RAT_CHANGED:
+ QualifiedNetworksInfo qualifiedInfo = (QualifiedNetworksInfo) msg.obj;
+ // handover trigger
+ if (mNetCapability == qualifiedInfo.getNetCapability()
+ && qualifiedInfo.getAccessNetworkTypes().stream().anyMatch(
+ accessNetwork -> QnsUtils.getTransportTypeFromAccessNetwork(
+ accessNetwork) != mDataTransportType)) {
+ mHandoverRequestedTime = QnsUtils.getSystemElapsedRealTime();
+ transitionTo(mHandoverRequestedState);
+ return HANDLED;
+ }
+ break;
+ }
+
+ return super.processMessage(msg);
+ }
+
+ @Override
+ public void exit() {
+ super.exit();
+ }
+ }
+
+ private final class HandoverRequestedState extends State {
+ @Override
+ public void enter() {
+ log("HandoverRequestedState");
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ log("HandoverRequestedState processMessage=" + msg.what);
+ switch (msg.what) {
+ case EVENT_DATA_STATE_CHANGED:
+ DataConnectionChangedInfo dataInfo = (DataConnectionChangedInfo) msg.obj;
+ switch (dataInfo.getState()) {
+ case DataConnectionStatusTracker.STATE_INACTIVE:
+ case DataConnectionStatusTracker.STATE_CONNECTING:
+ transitionTo(mIdleState);
+ break;
+ case DataConnectionStatusTracker.STATE_CONNECTED:
+ if (dataInfo.getTransportType() != mDataTransportType) {
+ // back to connected state, already reached to target transport.
+ mDataTransportType = dataInfo.getTransportType();
+ transitionTo(mConnectedState);
+ }
+ break;
+ case DataConnectionStatusTracker.STATE_HANDOVER:
+ if (dataInfo.getTransportType() != mDataTransportType) {
+ // back to connected state, already reached to target transport.
+ mDataTransportType = dataInfo.getTransportType();
+ transitionTo(mConnectedState);
+ }
+ transitionTo(mHandoverInProgressState);
+ break;
+ }
+ break;
+ case EVENT_QUALIFIED_RAT_CHANGED:
+ QualifiedNetworksInfo qualifiedInfo = (QualifiedNetworksInfo) msg.obj;
+ if (mNetCapability != qualifiedInfo.getNetCapability()) {
+ break;
+ }
+ if (qualifiedInfo.getAccessNetworkTypes().stream().noneMatch(
+ accessNetwork -> QnsUtils.getTransportTypeFromAccessNetwork(
+ accessNetwork) != mDataTransportType)) {
+ // back to connected state. no handover target transport.
+ transitionTo(mConnectedState);
+ return HANDLED;
+ }
+ break;
+ }
+ return super.processMessage(msg);
+ }
+
+ @Override
+ public void exit() {
+ super.exit();
+ }
+ }
+
+ private final class HandoverInProgressState extends State {
+ @Override
+ public void enter() {
+ log("HandoverInProgressState");
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ log("HandoverInProgressState processMessage=" + msg.what);
+ switch (msg.what) {
+ case EVENT_DATA_STATE_CHANGED:
+ DataConnectionChangedInfo dataInfo = (DataConnectionChangedInfo) msg.obj;
+ switch (dataInfo.getState()) {
+ case DataConnectionStatusTracker.STATE_INACTIVE:
+ case DataConnectionStatusTracker.STATE_CONNECTING:
+ transitionTo(mIdleState);
+ break;
+ case DataConnectionStatusTracker.STATE_CONNECTED:
+ if (dataInfo.getTransportType() != mDataTransportType) {
+ if (mHandoverRequestedTime == 0L) {
+ break;
+ }
+ // handover done.
+ long handoverTime = QnsUtils.getSystemElapsedRealTime()
+ - mHandoverRequestedTime;
+ writeQnsHandoverTimeMillisInfo(handoverTime, mSlotId);
+ mDataTransportType = dataInfo.getTransportType();
+ mHandoverRequestedTime = 0L;
+ transitionTo(mConnectedState);
+ } else {
+ // handover didn't have done yet.
+ transitionTo(mHandoverRequestedState);
+ }
+ break;
+ case DataConnectionStatusTracker.STATE_HANDOVER:
+ if (dataInfo.getTransportType() != mDataTransportType) {
+ // back to connected state, already reached to target transport.
+ mDataTransportType = dataInfo.getTransportType();
+ transitionTo(mConnectedState);
+ }
+ break;
+ }
+ break;
+ case EVENT_QUALIFIED_RAT_CHANGED:
+ QualifiedNetworksInfo qualifiedInfo = (QualifiedNetworksInfo) msg.obj;
+ if (mNetCapability == qualifiedInfo.getNetCapability()
+ && qualifiedInfo.getAccessNetworkTypes().stream().noneMatch(
+ accessNetwork -> QnsUtils.getTransportTypeFromAccessNetwork(
+ accessNetwork) != mDataTransportType)) {
+ // back to connected state. no handover request
+ transitionTo(mConnectedState);
+ return HANDLED;
+ }
+ break;
+ }
+ return super.processMessage(msg);
+ }
+
+ @Override
+ public void exit() {
+ super.exit();
+ }
+ }
+ }
+
+ private static class PingPongTime {
+ int mHandoverCount = 0;
+ long mStartTime = 0L;
+ long mSuccessTime = 0L;
+ }
+
+ private static class RatMismatchTime {
+ int mCount = 0;
+ long mStartTime = 0L;
+ }
+
+ private static class RtpCallDrop {
+ boolean mRtpThresholdBreached;
+ int mRestrictionsOnOtherTransportType;
+ }
+
+
+ private void procCallTypeChangedForImsCallDrop(
+ int netCapability,
+ int slotId,
+ int oldCallType,
+ int newCallType,
+ RestrictManager restrictManager,
+ int transportTypeOfCall) {
+ if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS) {
+ return;
+ }
+
+ RtpCallDrop rtpCallDrop = mRtpCallDrop.get(slotId);
+ if (rtpCallDrop == null) {
+ rtpCallDrop = new RtpCallDrop();
+ mRtpCallDrop.put(slotId, rtpCallDrop);
+ }
+
+ // call ended
+ if (newCallType == QnsConstants.CALL_TYPE_IDLE
+ && oldCallType != QnsConstants.CALL_TYPE_IDLE) {
+ rtpCallDrop.mRtpThresholdBreached =
+ restrictManager.hasRestrictionType(
+ transportTypeOfCall, RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY);
+ int otherTransportType =
+ transportTypeOfCall == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
+ ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN
+ : AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
+ rtpCallDrop.mRestrictionsOnOtherTransportType =
+ getRestrictionsBitmask(otherTransportType, restrictManager);
+ } else {
+ rtpCallDrop.mRtpThresholdBreached = false;
+ rtpCallDrop.mRestrictionsOnOtherTransportType = 0;
+ }
+ }
+
+ private void procCallDroppedForImsCallDrop(
+ int netCapability,
+ int slotId,
+ RestrictManager restrictManager,
+ QualityMonitor cellularQualityMonitor,
+ QualityMonitor wifiQualityMonitor,
+ int transportTypeOfCall,
+ int cellularAccessNetworkType) {
+ if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS) {
+ return;
+ }
+
+ RtpCallDrop rtpCallDrop = mRtpCallDrop.get(slotId);
+ if (rtpCallDrop == null) {
+ rtpCallDrop = new RtpCallDrop();
+ mRtpCallDrop.put(slotId, rtpCallDrop);
+ }
+
+ if (!rtpCallDrop.mRtpThresholdBreached
+ || rtpCallDrop.mRestrictionsOnOtherTransportType == 0) {
+ rtpCallDrop.mRtpThresholdBreached = restrictManager.hasRestrictionType(
+ transportTypeOfCall, RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY);
+ int otherTransportType =
+ transportTypeOfCall == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
+ ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN
+ : AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
+ rtpCallDrop.mRestrictionsOnOtherTransportType =
+ getRestrictionsBitmask(otherTransportType, restrictManager);
+ }
+
+ int signalStrength = getSignalStrength(cellularQualityMonitor, cellularAccessNetworkType);
+ int signalQuality = getSignalQuality(cellularQualityMonitor, cellularAccessNetworkType);
+ int signalNoise = getSignalNoise(cellularQualityMonitor, cellularAccessNetworkType);
+ int iwlanSignalStrength = getSignalStrength(wifiQualityMonitor, AccessNetworkType.IWLAN);
+
+ writeQnsImsCallDropStats(
+ transportTypeOfCall,
+ rtpCallDrop.mRtpThresholdBreached,
+ rtpCallDrop.mRestrictionsOnOtherTransportType,
+ signalStrength,
+ signalQuality,
+ signalNoise,
+ iwlanSignalStrength,
+ cellularAccessNetworkType,
+ slotId);
+ }
+
+ private void writeQnsImsCallDropStats(
+ int transportTypeCallDropped,
+ boolean rtpThresholdBreached,
+ int restrictionsOnOtherTransportType,
+ int signalStrength,
+ int signalQuality,
+ int signalNoise,
+ int iwlanSignalStrength,
+ int cellularNetworkType,
+ int slotId) {
+ AtomsQnsImsCallDropStats atoms =
+ new AtomsQnsImsCallDropStats(
+ transportTypeCallDropped,
+ rtpThresholdBreached,
+ restrictionsOnOtherTransportType,
+ signalStrength,
+ signalQuality,
+ signalNoise,
+ iwlanSignalStrength,
+ slotId,
+ cellularNetworkType);
+ mStats.write(atoms);
+ }
+
+ private int getQualifiedAccessNetwork(QualifiedNetworksInfo info, int index) {
+ List<Integer> types = info.getAccessNetworkTypes();
+ if (types == null || index >= types.size()) {
+ return QnsProtoEnums.EMPTY;
+ }
+ return types.get(index);
+ }
+
+ private boolean getWfcEnabled(int coverage, boolean wfcEnabled, boolean wfcRoamingEnabled) {
+ return coverage == QnsConstants.COVERAGE_HOME ? wfcEnabled : wfcRoamingEnabled;
+ }
+
+ private int getWfcMode(int coverage, int wfcMode, int wfcRoamingMode) {
+ return coverage == QnsConstants.COVERAGE_HOME ? wfcMode : wfcRoamingMode;
+ }
+
+ private int getIwlanNetworkType(boolean iwlanAvailable, boolean isCrossWfc) {
+ if (!iwlanAvailable) {
+ return QnsProtoEnums.IWLAN_NETWORK_TYPE_NONE;
+ } else if (isCrossWfc) {
+ return QnsProtoEnums.IWLAN_NETWORK_TYPE_CST;
+ }
+ return QnsProtoEnums.IWLAN_NETWORK_TYPE_WIFI;
+ }
+
+ static final HashMap<Integer, Integer> sAtomRestrictionsMap;
+
+ static {
+ sAtomRestrictionsMap = new HashMap<>();
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_GUARDING, QnsProtoEnums.RESTRICT_TYPE_GUARDING);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_THROTTLING, QnsProtoEnums.RESTRICT_TYPE_THROTTLING);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_HO_NOT_ALLOWED,
+ QnsProtoEnums.RESTRICT_TYPE_HO_NOT_ALLOWED);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_NON_PREFERRED_TRANSPORT,
+ QnsProtoEnums.RESTRICT_TYPE_NON_PREFERRED_TRANSPORT);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY,
+ QnsProtoEnums.RESTRICT_TYPE_RTP_LOW_QUALITY);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL,
+ QnsProtoEnums.RESTRICT_TYPE_RESTRICT_IWLAN_IN_CALL);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL,
+ QnsProtoEnums.RESTRICT_TYPE_RESTRICT_IWLAN_CS_CALL);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL,
+ QnsProtoEnums.RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL,
+ QnsProtoEnums.RESTRICT_TYPE_FALLBACK_ON_DATA_CONNECTION_FAIL);
+ sAtomRestrictionsMap.put(
+ RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL,
+ QnsProtoEnums.RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL);
+ }
+
+ private int getRestrictionsBitmask(int transportType, RestrictManager restrictManager) {
+ int restrictions = QnsProtoEnums.RESTRICT_TYPE_NONE;
+ for (int restrictionType : sAtomRestrictionsMap.keySet()) {
+ if (restrictManager.hasRestrictionType(transportType, restrictionType)) {
+ restrictions |= sAtomRestrictionsMap.get(restrictionType);
+ }
+ }
+ return restrictions;
+ }
+
+ private int getSignalStrength(QualityMonitor qm, int accessNetworkType) {
+ switch (accessNetworkType) {
+ case AccessNetworkType.GERAN:
+ case AccessNetworkType.IWLAN:
+ return qm.getCurrentQuality(
+ accessNetworkType, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI);
+ case AccessNetworkType.UTRAN:
+ return qm.getCurrentQuality(
+ accessNetworkType, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP);
+ case AccessNetworkType.EUTRAN:
+ return qm.getCurrentQuality(
+ accessNetworkType, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP);
+ case AccessNetworkType.NGRAN:
+ return qm.getCurrentQuality(
+ accessNetworkType, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP);
+ }
+ return 0;
+ }
+
+ private int getSignalQuality(QualityMonitor qm, int accessNetworkType) {
+ switch (accessNetworkType) {
+ case AccessNetworkType.EUTRAN:
+ return qm.getCurrentQuality(
+ accessNetworkType, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ);
+ case AccessNetworkType.NGRAN:
+ return qm.getCurrentQuality(
+ accessNetworkType, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ);
+ }
+ return 0;
+ }
+
+ private int getSignalNoise(QualityMonitor qm, int accessNetworkType) {
+ switch (accessNetworkType) {
+ case AccessNetworkType.EUTRAN:
+ return qm.getCurrentQuality(
+ accessNetworkType, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR);
+ case AccessNetworkType.NGRAN:
+ return qm.getCurrentQuality(
+ accessNetworkType, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR);
+ }
+ return 0;
+ }
+
+ protected void log(String s) {
+ Log.d(mLogTag, s);
+ }
+}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsTelephonyListener.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsTelephonyListener.java
index 32883d4..9e59736 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsTelephonyListener.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsTelephonyListener.java
@@ -37,6 +37,7 @@
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.VopsSupportInfo;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
import android.util.Log;
@@ -69,6 +70,7 @@
QnsRegistrantList mSrvccStateListener = new QnsRegistrantList();
QnsRegistrantList mSubscriptionIdListener = new QnsRegistrantList();
QnsRegistrantList mIwlanServiceStateListener = new QnsRegistrantList();
+ QnsRegistrantList mImsCallDropDisconnectCauseListener = new QnsRegistrantList();
List<Consumer<List<CallState>>> mCallStatesConsumerList = new ArrayList<>();
List<Consumer<Integer>> mSrvccStateConsumerList = new ArrayList<>();
List<Consumer<MediaQualityStatus>> mMediaQualityConsumerList = new ArrayList<>();
@@ -327,6 +329,21 @@
}
/**
+ * Register an event for ImsCallDropDisconnectCause changed.
+ *
+ * @param h the Handler to get event.
+ * @param what the event.
+ * @param userObj user object.
+ */
+ void registerImsCallDropDisconnectCauseListener(Handler h, int what, Object userObj) {
+ log("registerImsCallDropDisconnectCauseListener");
+ if (h != null) {
+ QnsRegistrant r = new QnsRegistrant(h, what, userObj);
+ mImsCallDropDisconnectCauseListener.add(r);
+ }
+ }
+
+ /**
* Unregister an event for QnsTelephonyInfo changed.
*
* @param netCapability Network Capability to be notified.
@@ -406,6 +423,18 @@
}
}
+ /**
+ * Unregister an event for ImsCallDropDisconnectCause state changed.
+ *
+ * @param h the handler to get event.
+ */
+ void unregisterImsCallDropDisconnectCauseListener(Handler h) {
+ log("unregisterImsCallDropDisconnectCauseListener");
+ if (h != null) {
+ mImsCallDropDisconnectCauseListener.remove(h);
+ }
+ }
+
private void createTelephonyListener() {
if (mTelephonyListener == null) {
mTelephonyListener = new TelephonyListener(mContext.getMainExecutor());
@@ -429,6 +458,10 @@
(int srvccState) -> {
onSrvccStateChanged(srvccState);
});
+ mTelephonyListener.setImsCallDisconnectCauseListener(
+ (ImsReasonInfo imsReasonInfo) -> {
+ onImsCallDisconnectCauseChanged(imsReasonInfo);
+ });
}
}
@@ -721,6 +754,10 @@
mSubscriptionIdListener.notifyResult(subId);
}
+ protected void onImsCallDisconnectCauseChanged(ImsReasonInfo imsReasonInfo) {
+ mImsCallDropDisconnectCauseListener.notifyResult(imsReasonInfo);
+ }
+
protected void log(String s) {
Log.d(mLogTag, s);
}
@@ -769,6 +806,11 @@
void onCallStatesChanged(List<CallState> callStateList);
}
+ protected interface OnImsCallDisconnectCauseListener {
+ /** Notify the call disconnected cause changed. */
+ void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo);
+ }
+
protected static class Archiving<V> {
protected HashMap<String, V> mArchiving = new HashMap<>();
@@ -1037,7 +1079,8 @@
TelephonyCallback.CallStateListener,
TelephonyCallback.SrvccStateListener,
TelephonyCallback.CallAttributesListener,
- TelephonyCallback.MediaQualityStatusChangedListener {
+ TelephonyCallback.MediaQualityStatusChangedListener,
+ TelephonyCallback.ImsCallDisconnectCauseListener {
private final Executor mExecutor;
private OnServiceStateListener mServiceStateListener;
private OnPreciseDataConnectionStateListener mPreciseDataConnectionStateListener;
@@ -1046,6 +1089,7 @@
private OnSrvccStateChangedCallback mSrvccStateCallback;
private OnSrvccStateChangedCallback mSrvccStateListener;
private OnCallStatesChangedCallback mCallStatesCallback;
+ private OnImsCallDisconnectCauseListener mImsCallDisconnectCauseListener;
private TelephonyManager mTelephonyManager;
TelephonyListener(Executor executor) {
@@ -1080,6 +1124,11 @@
void setCallStatesCallback(OnCallStatesChangedCallback listener) {
mCallStatesCallback = listener;
}
+
+ void setImsCallDisconnectCauseListener(OnImsCallDisconnectCauseListener listener) {
+ mImsCallDisconnectCauseListener = listener;
+ }
+
/**
* Register a TelephonyCallback for this listener.
*
@@ -1168,6 +1217,13 @@
consumer.accept(status);
}
}
+
+ @Override
+ public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) {
+ if (mImsCallDisconnectCauseListener != null) {
+ mImsCallDisconnectCauseListener.onImsCallDisconnectCauseChanged(imsReasonInfo);
+ }
+ }
}
void addCallStatesChangedCallback(Consumer<List<CallState>> consumer) {
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsTimer.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsTimer.java
new file mode 100644
index 0000000..7630054
--- /dev/null
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/QnsTimer.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2023 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.telephony.qns;
+
+import static com.android.telephony.qns.QnsConstants.CALL_TYPE_IDLE;
+import static com.android.telephony.qns.QnsConstants.INVALID_ID;
+import static com.android.telephony.qns.QnsUtils.getSystemElapsedRealTime;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.PowerManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.PriorityQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/** This class handles the delayed events triggered in QNS. */
+class QnsTimer {
+
+ private static final String TAG = QnsTimer.class.getSimpleName();
+ private static final int EVENT_QNS_TIMER_EXPIRED = 1;
+
+ private static final int MIN_ALARM_CALL_ACTIVE_DELAY_MS = 0;
+ private static final int MIN_ALARM_SCREEN_OFF_DELAY_MS = 10000;
+ private static final int MIN_ALARM_DEVICE_LIGHT_IDLE_DELAY_MS = 30000;
+ private static final int MIN_ALARM_DEVICE_IDLE_DELAY_MS = 60000;
+ static final String ACTION_ALARM_TIMER_EXPIRED =
+ "com.android.telephony.qns.action.ALARM_TIMER_EXPIRED";
+
+ private static final AtomicInteger sTimerId = new AtomicInteger();
+ private final Context mContext;
+ private final AlarmManager mAlarmManager;
+ private final PowerManager mPowerManager;
+ private final HandlerThread mHandlerThread;
+ private final BroadcastReceiver mBroadcastReceiver;
+ private final PriorityQueue<TimerInfo> mTimerInfos;
+ private PendingIntent mPendingIntent;
+ private long mMinAlarmTimeMs = MIN_ALARM_SCREEN_OFF_DELAY_MS;
+ private int mCurrentAlarmTimerId = INVALID_ID;
+ private int mCurrentHandlerTimerId = INVALID_ID;
+ private boolean mIsAlarmRequired;
+ @VisibleForTesting Handler mHandler;
+ private long mLastAlarmTriggerAtMs = Long.MAX_VALUE;
+ private int mCallType = CALL_TYPE_IDLE;
+
+ QnsTimer(Context context) {
+ mContext = context;
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ mBroadcastReceiver = new AlarmReceiver();
+ mTimerInfos =
+ new PriorityQueue<>(Comparator.comparingLong(TimerInfo::getExpireAtElapsedMillis));
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new QnsTimerHandler();
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ACTION_ALARM_TIMER_EXPIRED);
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+ intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+ intentFilter.addAction(PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED);
+ intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ mContext.registerReceiver(mBroadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED);
+ }
+
+ /**
+ * This method uses AlarmManager to execute the delayed event passed as param.
+ *
+ * @param msg message to process.
+ * @param delayMs timer value for the delay.
+ * @return unique timer id associated with the registered timer.
+ */
+ int registerTimer(Message msg, long delayMs) {
+ int timerId = sTimerId.getAndIncrement();
+ TimerInfo timerInfo = new TimerInfo(timerId);
+ timerInfo.setMessage(msg);
+ timerInfo.setExpireAtElapsedMillis(getSystemElapsedRealTime() + delayMs);
+ logd("register timer for timerId=" + timerId + ", with delay=" + delayMs);
+ mHandler.post(
+ () -> {
+ mTimerInfos.add(timerInfo);
+ updateToShortestDelay(mIsAlarmRequired, false /* forceUpdate */);
+ });
+ return timerId;
+ }
+
+ /**
+ * This method unregisters the timer associated to given timerId.
+ *
+ * @param timerId timer id associated with the running timer.
+ */
+ void unregisterTimer(int timerId) {
+ if (timerId == INVALID_ID) {
+ return;
+ }
+ logd("unregisterTimer for timerId=" + timerId);
+ mHandler.post(
+ () -> {
+ logd("Cancel timerId=" + timerId);
+ TimerInfo timerInfo = new TimerInfo(timerId);
+ if (mTimerInfos.remove(timerInfo) && timerId == mCurrentAlarmTimerId) {
+ updateToShortestDelay(mIsAlarmRequired, false /* forceUpdate */);
+ }
+ });
+ }
+
+ /**
+ * It updates the call state in QnsTimer. If the call is active the minimum timer value for an
+ * alarm is updated to 0ms. Otherwise the value will be based on device state (Idle, Light Idle
+ * or Screen off).
+ *
+ * @param type Call type {@code @QnsConstants.QnsCallType}
+ */
+ void updateCallState(@QnsConstants.QnsCallType int type) {
+ if (mCallType == CALL_TYPE_IDLE && type != CALL_TYPE_IDLE) {
+ mHandler.post(
+ () -> {
+ mMinAlarmTimeMs = MIN_ALARM_CALL_ACTIVE_DELAY_MS;
+ if (mIsAlarmRequired) {
+ updateToShortestDelay(true, true /* forceUpdate */);
+ }
+ });
+ }
+ mCallType = type;
+ if (mCallType == CALL_TYPE_IDLE && mIsAlarmRequired) {
+ if (mPowerManager.isDeviceIdleMode()) {
+ mMinAlarmTimeMs = MIN_ALARM_DEVICE_IDLE_DELAY_MS;
+ } else if (mPowerManager.isDeviceLightIdleMode()) {
+ mMinAlarmTimeMs = MIN_ALARM_DEVICE_LIGHT_IDLE_DELAY_MS;
+ } else {
+ mMinAlarmTimeMs = MIN_ALARM_SCREEN_OFF_DELAY_MS; // SCREEN_OFF case
+ }
+ }
+ }
+
+ /**
+ * This method performs the following actions: 1. checks if the shortest timer is set for
+ * handler or alarm. If not it overrides the earlier set timer with the shortest one. 2. checks
+ * for timers in the list those have passed the current elapsed time; and notifies them to
+ * respective handlers.
+ *
+ * @param isAlarmRequired flag indicates if timer is need to setup with Alarm.
+ * @param forceUpdate flag indicates to update the delay time for handler and/or alarm
+ * forcefully.
+ */
+ private void updateToShortestDelay(boolean isAlarmRequired, boolean forceUpdate) {
+ TimerInfo timerInfo = mTimerInfos.peek();
+ long elapsedTime = getSystemElapsedRealTime();
+ while (timerInfo != null && timerInfo.getExpireAtElapsedMillis() <= elapsedTime) {
+ logd("Notify timerInfo=" + timerInfo);
+ timerInfo.getMessage().sendToTarget();
+ mTimerInfos.poll();
+ timerInfo = mTimerInfos.peek();
+ }
+ if (timerInfo == null) {
+ logd("No timers are pending to run");
+ clearAllTimers();
+ return;
+ }
+ long delay = timerInfo.getExpireAtElapsedMillis() - elapsedTime;
+ // Delayed Handler will always set for shortest delay.
+ if (timerInfo.getTimerId() != mCurrentHandlerTimerId || forceUpdate) {
+ mHandler.removeMessages(EVENT_QNS_TIMER_EXPIRED);
+ mHandler.sendEmptyMessageDelayed(EVENT_QNS_TIMER_EXPIRED, delay);
+ mCurrentHandlerTimerId = timerInfo.getTimerId();
+ }
+
+ // Alarm will always set for shortest from Math.max(delay, mMinAlarmTimeMs)
+ if (timerInfo.getTimerId() != mCurrentAlarmTimerId || forceUpdate) {
+ if (isAlarmRequired) {
+ delay = Math.max(delay, mMinAlarmTimeMs);
+ // check if smaller timer alarm is already running for active timer info.
+ if (mTimerInfos.contains(new TimerInfo(mCurrentAlarmTimerId))
+ && mLastAlarmTriggerAtMs - elapsedTime < delay
+ && mPendingIntent != null) {
+ logd(
+ "Skip update since minimum Alarm Timer already running for timerId="
+ + mCurrentAlarmTimerId);
+ return;
+ }
+ logd("Setup alarm for delay " + delay);
+ mLastAlarmTriggerAtMs = elapsedTime + delay;
+ setupAlarmFor(mLastAlarmTriggerAtMs);
+ } else if (mPendingIntent != null) {
+ mAlarmManager.cancel(mPendingIntent);
+ mPendingIntent = null;
+ }
+ mCurrentAlarmTimerId = timerInfo.getTimerId();
+ logd("Update timer to timer id=" + mCurrentAlarmTimerId);
+ }
+ }
+
+ private void clearAllTimers() {
+ mHandler.removeMessages(EVENT_QNS_TIMER_EXPIRED);
+ if (mPendingIntent != null) {
+ logd("Cancel Alarm");
+ mAlarmManager.cancel(mPendingIntent);
+ }
+ mPendingIntent = null;
+ }
+
+ private void setupAlarmFor(long triggerAtMillis) {
+ mPendingIntent =
+ PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ new Intent(ACTION_ALARM_TIMER_EXPIRED),
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ mAlarmManager.setExactAndAllowWhileIdle(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, mPendingIntent);
+ }
+
+ private class AlarmReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ logd("onReceive action=" + action);
+ switch (action) {
+ case ACTION_ALARM_TIMER_EXPIRED:
+ mHandler.sendEmptyMessage(EVENT_QNS_TIMER_EXPIRED);
+ break;
+ case Intent.ACTION_SCREEN_OFF:
+ mHandler.post(
+ () -> {
+ mMinAlarmTimeMs =
+ (mCallType == CALL_TYPE_IDLE)
+ ? MIN_ALARM_SCREEN_OFF_DELAY_MS
+ : MIN_ALARM_CALL_ACTIVE_DELAY_MS;
+ if (!mIsAlarmRequired) {
+ mIsAlarmRequired = true;
+ updateToShortestDelay(true, true /* forceUpdate */);
+ }
+ });
+ break;
+ case Intent.ACTION_SCREEN_ON:
+ mHandler.post(
+ () -> {
+ if (mIsAlarmRequired) {
+ mIsAlarmRequired = false;
+ updateToShortestDelay(false, true /* forceUpdate */);
+ }
+ });
+ break;
+ case PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED:
+ mHandler.post(
+ () -> {
+ if (mPowerManager.isDeviceLightIdleMode()) {
+ mMinAlarmTimeMs =
+ (mCallType == CALL_TYPE_IDLE)
+ ? MIN_ALARM_DEVICE_LIGHT_IDLE_DELAY_MS
+ : MIN_ALARM_CALL_ACTIVE_DELAY_MS;
+ if (!mIsAlarmRequired) {
+ mIsAlarmRequired = true;
+ updateToShortestDelay(true, true /* forceUpdate */);
+ }
+ } else {
+ mMinAlarmTimeMs =
+ (mCallType == CALL_TYPE_IDLE)
+ ? MIN_ALARM_SCREEN_OFF_DELAY_MS
+ : MIN_ALARM_CALL_ACTIVE_DELAY_MS;
+ }
+ });
+ break;
+ case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
+ mHandler.post(
+ () -> {
+ if (mPowerManager.isDeviceIdleMode()) {
+ mMinAlarmTimeMs =
+ (mCallType == CALL_TYPE_IDLE)
+ ? MIN_ALARM_DEVICE_IDLE_DELAY_MS
+ : MIN_ALARM_CALL_ACTIVE_DELAY_MS;
+ if (!mIsAlarmRequired) {
+ mIsAlarmRequired = true;
+ updateToShortestDelay(true, true /* forceUpdate */);
+ }
+ } else {
+ mMinAlarmTimeMs =
+ (mCallType == CALL_TYPE_IDLE)
+ ? MIN_ALARM_SCREEN_OFF_DELAY_MS
+ : MIN_ALARM_CALL_ACTIVE_DELAY_MS;
+ }
+ });
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private class QnsTimerHandler extends Handler {
+ QnsTimerHandler() {
+ super(mHandlerThread.getLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ logd("handleMessage msg.what=" + msg.what);
+ switch (msg.what) {
+ case EVENT_QNS_TIMER_EXPIRED:
+ logd("Timer expired");
+ updateToShortestDelay(mIsAlarmRequired, false /* forceUpdate */);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ static class TimerInfo {
+ private final int mTimerId;
+ private long mExpireAtElapsedMillis;
+ private Message mMsg;
+
+ TimerInfo(int timerId) {
+ mTimerId = timerId;
+ }
+
+ public int getTimerId() {
+ return mTimerId;
+ }
+
+ public Message getMessage() {
+ return mMsg;
+ }
+
+ public void setMessage(Message msg) {
+ mMsg = msg;
+ }
+
+ public long getExpireAtElapsedMillis() {
+ return mExpireAtElapsedMillis;
+ }
+
+ public void setExpireAtElapsedMillis(long expireAtElapsedMillis) {
+ mExpireAtElapsedMillis = expireAtElapsedMillis;
+ }
+
+ /** Timers are equals if they share the same timer id. */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof TimerInfo)) return false;
+ TimerInfo timerInfo = (TimerInfo) o;
+ return mTimerId == timerInfo.mTimerId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTimerId);
+ }
+
+ @Override
+ public String toString() {
+ return "TimerInfo{"
+ + "mTimerId="
+ + mTimerId
+ + ", mExpireAtElapsedMillis="
+ + mExpireAtElapsedMillis
+ + ", mMsg="
+ + mMsg
+ + '}';
+ }
+ }
+
+ @VisibleForTesting
+ PriorityQueue<TimerInfo> getTimersInfo() {
+ return mTimerInfos;
+ }
+
+ void close() {
+ logd("Closing QnsTimer");
+ mHandlerThread.quitSafely();
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ mTimerInfos.clear();
+ clearAllTimers();
+ }
+
+ private void logd(String s) {
+ Log.d(TAG, s);
+ }
+
+ /**
+ * Dumps the state of {@link QnsTimer}
+ *
+ * @param pw {@link PrintWriter} to write the state of the object.
+ * @param prefix String to append at start of dumped log.
+ */
+ void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + "------------------------------");
+ pw.println(prefix + "QnsTimer:");
+ pw.println(
+ prefix
+ + "mIsAlarmRequired="
+ + mIsAlarmRequired
+ + ", mCurrentAlarmTimerId="
+ + mCurrentAlarmTimerId
+ + ", mCurrentHandlerTimerId="
+ + mCurrentHandlerTimerId
+ + ", latest timerId="
+ + sTimerId.get()
+ + ", Current elapsed time="
+ + getSystemElapsedRealTime());
+ pw.println(prefix + "mTimerInfos=" + mTimerInfos);
+ pw.println(prefix + "mPendingIntent=" + mPendingIntent);
+ }
+}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/QualifiedNetworksServiceImpl.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/QualifiedNetworksServiceImpl.java
index 9ac37b1..679098e 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/QualifiedNetworksServiceImpl.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/QualifiedNetworksServiceImpl.java
@@ -358,14 +358,7 @@
NetworkAvailabilityProviderImpl provider = providerMap.getValue();
provider.dump(pw, " ");
}
- IwlanNetworkStatusTracker iwlanNst = mQnsComponents.getIwlanNetworkStatusTracker();
- if (iwlanNst != null) {
- iwlanNst.dump(pw, " ");
- }
- WifiQualityMonitor wQM = mQnsComponents.getWifiQualityMonitor();
- if (wQM != null) {
- wQM.dump(pw, " ");
- }
+ mQnsComponents.dump(pw);
pw.println("==============================");
}
}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/RestrictManager.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/RestrictManager.java
index 9ae8a1d..21eaf7c 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/RestrictManager.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/RestrictManager.java
@@ -18,6 +18,7 @@
import static com.android.telephony.qns.DataConnectionStatusTracker.STATE_CONNECTED;
import static com.android.telephony.qns.DataConnectionStatusTracker.STATE_HANDOVER;
+import static com.android.telephony.qns.QnsConstants.INVALID_ID;
import android.annotation.IntDef;
import android.net.NetworkCapabilities;
@@ -161,7 +162,9 @@
private QnsCallStatusTracker mQnsCallStatusTracker;
private QnsCallStatusTracker.ActiveCallTracker mActiveCallTracker;
private QnsImsManager mQnsImsManager;
+ private QnsTimer mQnsTimer;
private WifiBackhaulMonitor mWifiBackhaulMonitor;
+ private QnsMetrics mQnsMetrics;
private int mNetCapability;
private int mSlotId;
private int mTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
@@ -173,6 +176,7 @@
private int mFallbackCounterOnDataConnectionFail;
private boolean mIsRttStatusCheckRegistered = false;
private int mLastDataConnectionTransportType;
+ private int mFallbackTimerId = -1;
private boolean mIsTimerRunningOnDataConnectionFail = false;
private Pair<Integer, Long> mDeferredThrottlingEvent = null;
@@ -182,6 +186,7 @@
@Annotation.CallState private int mCallState;
private Map<Integer, RestrictInfo> mRestrictInfos = new ConcurrentHashMap<>();
+ private Map<Restriction, Integer> mRestrictionTimers = new ConcurrentHashMap<>();
private class RestrictManagerHandler extends Handler {
RestrictManagerHandler(Looper l) {
@@ -238,6 +243,9 @@
.getRestrictionMap()
.get(restriction.mRestrictType)) {
releaseRestriction(transportType, restriction.mRestrictType);
+ mQnsTimer.unregisterTimer(mRestrictionTimers
+ .getOrDefault(restriction, INVALID_ID));
+ mRestrictionTimers.remove(restriction);
}
break;
@@ -247,6 +255,7 @@
"Initial Data Connection fail timer expired"
+ mIsTimerRunningOnDataConnectionFail);
+ mQnsTimer.unregisterTimer(mFallbackTimerId);
if (mIsTimerRunningOnDataConnectionFail) {
int currTransportType = message.arg1;
fallbackToOtherTransportOnDataConnectionFail(currTransportType);
@@ -451,11 +460,13 @@
mTelephonyListener = qnsComponents.getQnsTelephonyListener(mSlotId);
mQnsEventDispatcher = qnsComponents.getQnsEventDispatcher(mSlotId);
mQnsCarrierConfigManager = qnsComponents.getQnsCarrierConfigManager(mSlotId);
+ mQnsTimer = qnsComponents.getQnsTimer();
mHandler = new RestrictManagerHandler(loop);
mNetCapability = netCapability;
mDataConnectionStatusTracker = dcst;
mQnsCallStatusTracker = qnsComponents.getQnsCallStatusTracker(mSlotId);
mActiveCallTracker = qnsComponents.getQnsCallStatusTracker(mSlotId).getActiveCallTracker();
+ mQnsMetrics = qnsComponents.getQnsMetrics();
mDataConnectionStatusTracker.registerDataConnectionStatusChanged(
mHandler, EVENT_DATA_CONNECTION_CHANGED);
if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
@@ -518,6 +529,7 @@
if (mNetCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
mQnsImsManager.unregisterImsRegistrationStatusChanged(mHandler);
}
+ mRestrictionTimers.clear();
}
private void onWfcModeChanged(int prefMode, @QnsConstants.CellularCoverage int coverage) {
@@ -776,9 +788,7 @@
mIsTimerRunningOnDataConnectionFail = false;
mRetryCounterOnDataConnectionFail = 0;
- if (mHandler.hasMessages(EVENT_INITIAL_DATA_CONNECTION_FAIL_RETRY_TIMER_EXPIRED)) {
- mHandler.removeMessages(EVENT_INITIAL_DATA_CONNECTION_FAIL_RETRY_TIMER_EXPIRED);
- }
+ mQnsTimer.unregisterTimer(mFallbackTimerId);
}
private void processDataConnectionDisconnected() {
@@ -916,7 +926,7 @@
transportType,
0,
null);
- mHandler.sendMessageDelayed(msg, (long) fallbackRetryTimer);
+ mFallbackTimerId = mQnsTimer.registerTimer(msg, fallbackRetryTimer);
mIsTimerRunningOnDataConnectionFail = true;
}
}
@@ -1291,6 +1301,7 @@
removeReleaseRestrictionMessage(restriction);
}
restrictionMap.remove(restriction.mRestrictType);
+ mRestrictionTimers.remove(restriction);
needNotify = true;
}
if (needNotify && !skipNotify) {
@@ -1327,7 +1338,8 @@
Message msg =
mHandler.obtainMessage(EVENT_RELEASE_RESTRICTION, transportType, 0, restriction);
long delayInMillis = restriction.mReleaseTime - SystemClock.elapsedRealtime();
- mHandler.sendMessageDelayed(msg, delayInMillis);
+ int timerId = mQnsTimer.registerTimer(msg, delayInMillis);
+ mRestrictionTimers.put(restriction, timerId);
Log.d(
mLogTag,
restrictTypeToString(restriction.mRestrictType)
@@ -1341,7 +1353,8 @@
Log.e(mLogTag, "removeReleaseRestrictionMessage restriction is null");
return;
}
- mHandler.removeMessages(EVENT_RELEASE_RESTRICTION, restriction);
+ mQnsTimer.unregisterTimer(mRestrictionTimers.getOrDefault(restriction, INVALID_ID));
+ mRestrictionTimers.remove(restriction);
}
void registerRestrictInfoChanged(Handler h, int what) {
@@ -1440,6 +1453,9 @@
Log.d(mLogTag, "notifyRestrictInfoChanged");
if (mRestrictInfoRegistrant != null) {
mRestrictInfoRegistrant.notifyResult(mRestrictInfos);
+
+ // metrics
+ sendRestrictionsForMetrics();
} else {
Log.d(mLogTag, "notifyRestrictInfoChanged. no Registrant.");
}
@@ -1684,4 +1700,24 @@
+ QnsConstants.callStateToString(mCallState));
pw.println(prefix + "mRestrictInfos=" + mRestrictInfos);
}
+
+ private void sendRestrictionsForMetrics() {
+ if (mNetCapability != NetworkCapabilities.NET_CAPABILITY_IMS) {
+ return;
+ }
+ ArrayList<Integer> wlanRestrictions =
+ new ArrayList<>(
+ mRestrictInfos
+ .get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+ .getRestrictionMap()
+ .keySet());
+ ArrayList<Integer> wwanRestrictions =
+ new ArrayList<>(
+ mRestrictInfos
+ .get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+ .getRestrictionMap()
+ .keySet());
+ mQnsMetrics.reportAtomForRestrictions(mNetCapability, mSlotId,
+ wlanRestrictions, wwanRestrictions, mQnsCarrierConfigManager.getCarrierId());
+ }
}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/WifiBackhaulMonitor.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/WifiBackhaulMonitor.java
index be3c22c..6bef150 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/WifiBackhaulMonitor.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/WifiBackhaulMonitor.java
@@ -16,6 +16,8 @@
package com.android.telephony.qns;
+import static com.android.telephony.qns.QnsConstants.INVALID_ID;
+
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
@@ -28,6 +30,8 @@
import android.telephony.AccessNetworkConstants;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -56,6 +60,7 @@
private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final QnsCarrierConfigManager mConfigManager;
+ private final QnsTimer mQnsTimer;
private boolean mRttResult = false;
ArrayList<InetAddress> mValidIpList = new ArrayList<>();
@@ -65,6 +70,7 @@
private boolean mIsIwlanConnected = false;
private boolean mIsRttRunning = false;
private String mInterfaceName = null;
+ private int mRttTimerId = INVALID_ID;
private class BackhaulHandler extends Handler {
BackhaulHandler() {
@@ -118,6 +124,7 @@
Context context,
QnsCarrierConfigManager configManager,
QnsImsManager imsManager,
+ QnsTimer qnstimer,
int slotIndex) {
mSlotIndex = slotIndex;
mTag = WifiBackhaulMonitor.class.getSimpleName() + "[" + mSlotIndex + "]";
@@ -125,6 +132,7 @@
mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
mConfigManager = configManager;
mQnsImsManager = imsManager;
+ mQnsTimer = qnstimer;
mNetworkCallback = new WiFiStatusCallback();
mRegistrantList = new QnsRegistrantList();
mHandlerThread = new HandlerThread(mTag);
@@ -174,8 +182,9 @@
/** Triggers the request to check RTT. */
void requestRttCheck() {
if (!mIsRttRunning) {
- if (mHandler.hasMessages(EVENT_START_RTT_CHECK)) {
- mHandler.removeMessages(EVENT_START_RTT_CHECK);
+ if (mRttTimerId != INVALID_ID) {
+ mQnsTimer.unregisterTimer(mRttTimerId);
+ mRttTimerId = INVALID_ID;
}
mHandler.sendEmptyMessage(EVENT_START_RTT_CHECK);
} else {
@@ -232,13 +241,17 @@
}
private void startRttSchedule(int delay) {
- mHandler.sendEmptyMessageDelayed(EVENT_START_RTT_CHECK, delay);
+ log("start RTT schedule for " + delay);
+ mRttTimerId = mQnsTimer.registerTimer(Message.obtain(mHandler, EVENT_START_RTT_CHECK),
+ delay);
mIsRttScheduled = true;
}
private void stopRttSchedule() {
if (mIsRttScheduled) {
- mHandler.removeMessages(EVENT_START_RTT_CHECK);
+ log("stop RTT schedule");
+ mQnsTimer.unregisterTimer(mRttTimerId);
+ mRttTimerId = INVALID_ID;
mIsRttScheduled = false;
}
}
@@ -350,6 +363,11 @@
mIsRttScheduled = false;
}
+ @VisibleForTesting
+ int getRttTimerId() {
+ return mRttTimerId;
+ }
+
private void log(String s) {
Log.d(mTag, s);
}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/WifiQualityMonitor.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/WifiQualityMonitor.java
index bf758a9..0c5ea2a 100644
--- a/services/QualifiedNetworksService/src/com/android/telephony/qns/WifiQualityMonitor.java
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/WifiQualityMonitor.java
@@ -53,6 +53,8 @@
private final ConnectivityManager mConnectivityManager;
private final WiFiThresholdCallback mWiFiThresholdCallback;
private final NetworkRequest.Builder mBuilder;
+ private final QnsTimer mQnsTimer;
+ private final List<Integer> mTimerIds;
private int mWifiRssi;
@VisibleForTesting Handler mHandler;
@@ -60,6 +62,7 @@
private static final int BACKHAUL_TIMER_DEFAULT = 3000;
static final int INVALID_RSSI = -127;
private boolean mIsRegistered = false;
+ private boolean mIsBackhaulRunning;
private class WiFiThresholdCallback extends ConnectivityManager.NetworkCallback {
/** Callback Received based on meeting Wifi RSSI Threshold Registered or Wifi Lost */
@@ -94,11 +97,7 @@
synchronized void validateWqmStatus(int wifiRssi) {
if (isWifiRssiValid(wifiRssi)) {
Log.d(mTag, "Registered Threshold @ Wqm Status check =" + mRegisteredThreshold);
- if (!mHandler.hasMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED)) {
- mHandler.obtainMessage(EVENT_WIFI_RSSI_CHANGED, wifiRssi, 0).sendToTarget();
- } else {
- Log.d(mTag, "BackhaulCheck in Progress , skip validation");
- }
+ mHandler.obtainMessage(EVENT_WIFI_RSSI_CHANGED, wifiRssi, 0).sendToTarget();
} else {
Log.d(mTag, "Cancel backhaul if running for invalid SS received");
clearBackHaulTimer();
@@ -117,21 +116,24 @@
}
private void clearBackHaulTimer() {
- if (mHandler.hasMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED)) {
- Log.d(mTag, "Stop all active backhaul timers");
- mHandler.removeMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED);
- mWaitingThresholds.clear();
+ Log.d(mTag, "Stop all active backhaul timers");
+ for (int timerId : mTimerIds) {
+ mQnsTimer.unregisterTimer(timerId);
}
+ mTimerIds.clear();
+ mWaitingThresholds.clear();
}
/**
* Create WifiQualityMonitor object for accessing WifiManager, ConnectivityManager to monitor
* RSSI, build parameters for registering threshold & callback listening.
*/
- WifiQualityMonitor(Context context) {
+ WifiQualityMonitor(Context context, QnsTimer qnsTimer) {
super(QualityMonitor.class.getSimpleName() + "-I");
mTag = WifiQualityMonitor.class.getSimpleName() + "-I";
mContext = context;
+ mQnsTimer = qnsTimer;
+ mTimerIds = new ArrayList<>();
HandlerThread handlerThread = new HandlerThread(mTag);
handlerThread.start();
mHandler = new WiFiEventsHandler(handlerThread.getLooper());
@@ -239,9 +241,7 @@
}
private void validateForWifiBackhaul(int wifiRssi) {
- if (mHandler.hasMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED)) {
- mHandler.removeMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED);
- }
+ mIsBackhaulRunning = false;
for (Map.Entry<String, List<Threshold>> entry : mThresholdsList.entrySet()) {
if (mWaitingThresholds.getOrDefault(entry.getKey(), false)) {
continue;
@@ -262,9 +262,13 @@
}
if (backhaul > 0) {
mWaitingThresholds.put(key, true);
- if (!mHandler.hasMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED)) {
- Log.d(mTag, "Starting backhaul timer = " + backhaul);
- mHandler.sendEmptyMessageDelayed(EVENT_WIFI_NOTIFY_TIMER_EXPIRED, backhaul);
+ Log.d(mTag, "Starting backhaul timer = " + backhaul);
+ if (!mIsBackhaulRunning) {
+ mTimerIds.add(
+ mQnsTimer.registerTimer(
+ Message.obtain(mHandler, EVENT_WIFI_NOTIFY_TIMER_EXPIRED),
+ backhaul));
+ mIsBackhaulRunning = true;
}
} else {
Log.d(mTag, "Notify for RSSI Threshold Registered w/o Backhaul = " + backhaul);
@@ -302,7 +306,6 @@
unregisterCallback();
if (mThresholdsList.isEmpty()) {
clearBackHaulTimer();
- mWaitingThresholds.clear();
}
} else {
Log.d(mTag, "Listening to threshold = " + mRegisteredThreshold);
@@ -378,8 +381,8 @@
prefix
+ ", mIsRegistered="
+ mIsRegistered
- + ", backhaulstatus ="
- + mHandler.hasMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED));
+ + ", mIsBackhaulRunning="
+ + mIsBackhaulRunning);
pw.println(
prefix
+ "mWifiRssi="
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsFallbackRestrictionChangedInfo.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsFallbackRestrictionChangedInfo.java
new file mode 100644
index 0000000..05a2fdf
--- /dev/null
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsFallbackRestrictionChangedInfo.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import android.util.StatsEvent;
+
+import com.android.telephony.qns.stats.QnsStatsLog;
+import com.android.telephony.statslib.AtomsPushed;
+
+import java.util.Objects;
+
+/** AtomsQnsFallbackRestrictionChangedInfo class */
+public class AtomsQnsFallbackRestrictionChangedInfo extends AtomsPushed {
+
+ /** atom #1 : Restriction on WLAN caused by RTP threshold breached */
+ private boolean mRestrictionOnWlanByRtpThresholdBreached;
+
+ /** atom #2 : Restriction on WWAN caused by RTP threshold breached */
+ private boolean mRestrictionOnWwanByRtpThresholdBreached;
+
+ /** atom #3 : Restriction on WLAN caused by IMS registration fail */
+ private boolean mRestrictionOnWlanByImsRegistrationFailed;
+
+ /** atom #4 : Restriction on WLAN caused by Wi-Fi backhaul problem. */
+ private boolean mRestrictionOnWlanByWifiBackhaulProblem;
+
+ /** atom #5 : Carrier Id */
+ private int mCarrierId;
+
+ /** atom #6 : Slot Index */
+ private int mSlotIndex;
+
+ /** Constructor of AtomsQnsFallbackRestrictionChangedInfo */
+ public AtomsQnsFallbackRestrictionChangedInfo() {}
+
+ /**
+ * Constructor of AtomsQnsFallbackRestrictionChangedInfo
+ *
+ * @param restrictionOnWlanByRtpThresholdBreached Restriction on wlan caused by RTP threshold
+ * breached
+ * @param restrictionOnWwanByRtpThresholdBreached Restriction on wwan caused by RTP threshold
+ * breached
+ * @param restrictionOnWlanByImsRegistrationFailed Restriction on wlan caused by IMS
+ * registration fail
+ * @param restrictionOnWlanByWifiBackhaulProblem Restriction on wlan caused by Wifi backhaul
+ * problem.
+ * @param carrierId Carrier Id
+ * @param slotIndex Index of sim slot
+ */
+ public AtomsQnsFallbackRestrictionChangedInfo(
+ boolean restrictionOnWlanByRtpThresholdBreached,
+ boolean restrictionOnWwanByRtpThresholdBreached,
+ boolean restrictionOnWlanByImsRegistrationFailed,
+ boolean restrictionOnWlanByWifiBackhaulProblem,
+ int carrierId,
+ int slotIndex) {
+ mRestrictionOnWlanByRtpThresholdBreached = restrictionOnWlanByRtpThresholdBreached;
+ mRestrictionOnWwanByRtpThresholdBreached = restrictionOnWwanByRtpThresholdBreached;
+ mRestrictionOnWlanByImsRegistrationFailed = restrictionOnWlanByImsRegistrationFailed;
+ mRestrictionOnWlanByWifiBackhaulProblem = restrictionOnWlanByWifiBackhaulProblem;
+ mCarrierId = carrierId;
+ mSlotIndex = slotIndex;
+ }
+
+ /**
+ * Copy Constructor of AtomsQnsFallbackRestrictionChangedInfo
+ *
+ * @param info The info param to copy from.
+ */
+ public AtomsQnsFallbackRestrictionChangedInfo(AtomsQnsFallbackRestrictionChangedInfo info) {
+ mRestrictionOnWlanByRtpThresholdBreached = info.mRestrictionOnWlanByRtpThresholdBreached;
+ mRestrictionOnWwanByRtpThresholdBreached = info.mRestrictionOnWwanByRtpThresholdBreached;
+ mRestrictionOnWlanByImsRegistrationFailed = info.mRestrictionOnWlanByImsRegistrationFailed;
+ mRestrictionOnWlanByWifiBackhaulProblem = info.mRestrictionOnWlanByWifiBackhaulProblem;
+ mCarrierId = info.mCarrierId;
+ mSlotIndex = info.mSlotIndex;
+ }
+
+ /**
+ * Write the atom information to be recorded to the builder according to the type in order.
+ *
+ * @param builder Builder class for StatsEvent Builder object.
+ */
+ @Override
+ public void build(StatsEvent.Builder builder) {
+ builder.writeBoolean(mRestrictionOnWlanByRtpThresholdBreached); // atom #1
+ builder.writeBoolean(mRestrictionOnWwanByRtpThresholdBreached); // atom #2
+ builder.writeBoolean(mRestrictionOnWlanByImsRegistrationFailed); // atom #3
+ builder.writeBoolean(mRestrictionOnWlanByWifiBackhaulProblem); // atom #4
+ builder.writeInt(mCarrierId); // atom #5
+ builder.writeInt(mSlotIndex); // atom #6
+ }
+
+ /** Return atom id defined in proto. */
+ @Override
+ public int getStatsId() {
+ return QnsStatsLog.QNS_FALLBACK_RESTRICTION_CHANGED;
+ }
+
+ /** Return copy of the AtomsQnsFallbackRestrictionChangedInfo */
+ @Override
+ public AtomsPushed copy() {
+ return new AtomsQnsFallbackRestrictionChangedInfo(this);
+ }
+
+ public boolean getRestrictionOnWlanByRtpThresholdBreached() {
+ return mRestrictionOnWlanByRtpThresholdBreached;
+ }
+
+ public void setRestrictionOnWlanByRtpThresholdBreached(
+ boolean restrictionOnWlanByRtpThresholdBreached) {
+ mRestrictionOnWlanByRtpThresholdBreached = restrictionOnWlanByRtpThresholdBreached;
+ }
+
+ public boolean getRestrictionOnWwanByRtpThresholdBreached() {
+ return mRestrictionOnWwanByRtpThresholdBreached;
+ }
+
+ public void setRestrictionOnWwanByRtpThresholdBreached(
+ boolean restrictionOnWwanByRtpThresholdBreached) {
+ mRestrictionOnWwanByRtpThresholdBreached = restrictionOnWwanByRtpThresholdBreached;
+ }
+
+ public boolean getRestrictionOnWlanByImsRegistrationFailed() {
+ return mRestrictionOnWlanByImsRegistrationFailed;
+ }
+
+ public void setRestrictionOnWlanByImsRegistrationFailed(
+ boolean restrictionOnWlanByImsRegistrationFailed) {
+ mRestrictionOnWlanByImsRegistrationFailed = restrictionOnWlanByImsRegistrationFailed;
+ }
+
+ public boolean getRestrictionOnWlanByWifiBackhaulProblem() {
+ return mRestrictionOnWlanByWifiBackhaulProblem;
+ }
+
+ public void setRestrictionOnWlanByWifiBackhaulProblem(
+ boolean restrictionOnWlanByWifiBackhaulProblem) {
+ mRestrictionOnWlanByWifiBackhaulProblem = restrictionOnWlanByWifiBackhaulProblem;
+ }
+
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+
+ public void setCarrierId(int carrierId) {
+ mCarrierId = carrierId;
+ }
+
+ public int getSlotIndex() {
+ return mSlotIndex;
+ }
+
+ public void setSlotIndex(int slotIndex) {
+ mSlotIndex = slotIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "AtomsQnsFallbackRestrictionChangedInfo{"
+ + "mRestrictionWlanRtpThresholdBreached="
+ + mRestrictionOnWlanByRtpThresholdBreached
+ + ", mRestrictionWwanRtpThresholdBreached="
+ + mRestrictionOnWwanByRtpThresholdBreached
+ + ", mRestrictionWwanImsRegiFail="
+ + mRestrictionOnWlanByImsRegistrationFailed
+ + ", mRestrictionWwanWifiBackhaulProblem="
+ + mRestrictionOnWlanByWifiBackhaulProblem
+ + ", mCarrierId="
+ + mCarrierId
+ + ", mSlotIndex="
+ + mSlotIndex
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AtomsQnsFallbackRestrictionChangedInfo)) return false;
+ AtomsQnsFallbackRestrictionChangedInfo that = (AtomsQnsFallbackRestrictionChangedInfo) o;
+ return mRestrictionOnWlanByRtpThresholdBreached
+ == that.mRestrictionOnWlanByRtpThresholdBreached
+ && mRestrictionOnWwanByRtpThresholdBreached
+ == that.mRestrictionOnWwanByRtpThresholdBreached
+ && mRestrictionOnWlanByImsRegistrationFailed
+ == that.mRestrictionOnWlanByImsRegistrationFailed
+ && mRestrictionOnWlanByWifiBackhaulProblem
+ == that.mRestrictionOnWlanByWifiBackhaulProblem
+ && mCarrierId == that.mCarrierId
+ && mSlotIndex == that.mSlotIndex;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mRestrictionOnWlanByRtpThresholdBreached,
+ mRestrictionOnWwanByRtpThresholdBreached,
+ mRestrictionOnWlanByImsRegistrationFailed,
+ mRestrictionOnWlanByWifiBackhaulProblem,
+ mCarrierId,
+ mSlotIndex);
+ }
+}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsHandoverPingPongInfo.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsHandoverPingPongInfo.java
new file mode 100644
index 0000000..a714e58
--- /dev/null
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsHandoverPingPongInfo.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import android.util.StatsEvent;
+
+import com.android.telephony.qns.stats.QnsStatsLog;
+import com.android.telephony.statslib.AtomsPulled;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/** AtomsQnsHandoverPingPongInfo class */
+public class AtomsQnsHandoverPingPongInfo extends AtomsPulled implements Serializable {
+
+ private static final long serialVersionUID = 815898959L; // 0x30A1A14F
+
+ /** atom #1 : Count of handover ping-pong */
+ private int mCountHandoverPingPong;
+
+ /** atom #2 : Carrier Id */
+ private int mCarrierId;
+
+ /** atom #3 : Slot Index */
+ private int mSlotIndex;
+
+ /** Constructor of AtomsQnsHandoverPingPongInfo */
+ public AtomsQnsHandoverPingPongInfo() {}
+
+ /**
+ * Constructor of AtomsQnsHandoverPingPongInfo
+ *
+ * @param countHandoverPingPong count of Handover Ping-Pong
+ * @param carrierId Carrier Id
+ * @param slotIndex Index of sim slot
+ */
+ public AtomsQnsHandoverPingPongInfo(int countHandoverPingPong, int carrierId, int slotIndex) {
+ mCountHandoverPingPong = countHandoverPingPong;
+ mCarrierId = carrierId;
+ mSlotIndex = slotIndex;
+ }
+
+ /**
+ * Copy Constructor of AtomsQnsHandoverPingPongInfo
+ *
+ * @param info The info param to copy from.
+ */
+ public AtomsQnsHandoverPingPongInfo(AtomsQnsHandoverPingPongInfo info) {
+ mCountHandoverPingPong = info.mCountHandoverPingPong;
+ mCarrierId = info.mCarrierId;
+ mSlotIndex = info.mSlotIndex;
+ }
+
+ /**
+ * Write the atom information to be recorded to the builder according to the type in order.
+ *
+ * @param builder Builder class for StatsEvent Builder object.
+ */
+ @Override
+ public void build(StatsEvent.Builder builder) {
+ builder.writeInt(mCountHandoverPingPong); // atom #1
+ builder.writeInt(mCarrierId); // atom #2
+ builder.writeInt(mSlotIndex); // atom #3
+ }
+
+ /** Return atom id defined in proto. */
+ @Override
+ public int getStatsId() {
+ return QnsStatsLog.QNS_HANDOVER_PINGPONG;
+ }
+
+ /** Return copy of the AtomsQnsHandoverPingPongInfo */
+ @Override
+ public AtomsPulled copy() {
+ return new AtomsQnsHandoverPingPongInfo(this);
+ }
+
+ @Override
+ public String getDimension() {
+ return mCarrierId + "_" + mSlotIndex;
+ }
+
+ @Override
+ public void accumulate(AtomsPulled info) {
+ if (!(info instanceof AtomsQnsHandoverPingPongInfo)) {
+ return;
+ }
+ AtomsQnsHandoverPingPongInfo atomsQnsHandoverPingPongInfo =
+ (AtomsQnsHandoverPingPongInfo) info;
+ this.mCountHandoverPingPong += atomsQnsHandoverPingPongInfo.getCountHandoverPingPong();
+ }
+
+ public int getCountHandoverPingPong() {
+ return mCountHandoverPingPong;
+ }
+
+ public void setCountHandoverPingPong(int countHandoverPingPong) {
+ mCountHandoverPingPong = countHandoverPingPong;
+ }
+
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+
+ public void setCarrierId(int carrierId) {
+ mCarrierId = carrierId;
+ }
+
+ public int getSlotIndex() {
+ return mSlotIndex;
+ }
+
+ public void setSlotIndex(int slotIndex) {
+ mSlotIndex = slotIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "AtomsQnsHandoverPingPongInfo{"
+ + "mCountHandoverPingPong="
+ + mCountHandoverPingPong
+ + ", mCarrierId="
+ + mCarrierId
+ + ", mSlotIndex="
+ + mSlotIndex
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AtomsQnsHandoverPingPongInfo)) return false;
+ AtomsQnsHandoverPingPongInfo that = (AtomsQnsHandoverPingPongInfo) o;
+ return mCountHandoverPingPong == that.mCountHandoverPingPong
+ && mCarrierId == that.mCarrierId
+ && mSlotIndex == that.mSlotIndex;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCountHandoverPingPong, mCarrierId, mSlotIndex);
+ }
+
+ public static long PING_PONG_TIME_IN_MILLIS = 5000L;
+}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsHandoverTimeMillisInfo.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsHandoverTimeMillisInfo.java
new file mode 100644
index 0000000..e6924ac
--- /dev/null
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsHandoverTimeMillisInfo.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import android.util.StatsEvent;
+
+import com.android.telephony.qns.stats.QnsStatsLog;
+import com.android.telephony.statslib.AtomsPulled;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/** AtomsQnsHandoverTimeMillisInfo class */
+public class AtomsQnsHandoverTimeMillisInfo extends AtomsPulled implements Serializable {
+
+ private static final long serialVersionUID = 1379441656L; // 0x52389BF8
+
+ /** atom #1 : Time in milliseconds from QNS RAT update to successful HO completion */
+ private int mTimeForHoSuccess;
+
+ /** atom #2 : Slot Index */
+ private int mSlotIndex;
+
+ /** Constructor of AtomsQnsHandoverTimeMillisInfo */
+ public AtomsQnsHandoverTimeMillisInfo() {}
+
+ /**
+ * Constructor of AtomsQnsHandoverTimeMillisInfo
+ *
+ * @param timeForHoSuccess Time in milliseconds from QNS RAT update to successful HO completion
+ * @param slotIndex Index of sim slot
+ */
+ public AtomsQnsHandoverTimeMillisInfo(int timeForHoSuccess, int slotIndex) {
+ mTimeForHoSuccess = timeForHoSuccess;
+ mSlotIndex = slotIndex;
+ }
+
+ /**
+ * Copy Constructor of AtomsQnsHandoverTimeMillisInfo
+ *
+ * @param info The info param to copy from.
+ */
+ public AtomsQnsHandoverTimeMillisInfo(AtomsQnsHandoverTimeMillisInfo info) {
+ mTimeForHoSuccess = info.mTimeForHoSuccess;
+ mSlotIndex = info.mSlotIndex;
+ }
+
+ /**
+ * Write the atom information to be recorded to the builder according to the type in order.
+ *
+ * @param builder Builder class for StatsEvent Builder object.
+ */
+ @Override
+ public void build(StatsEvent.Builder builder) {
+ builder.writeInt(mTimeForHoSuccess); // atom #1
+ builder.writeInt(mSlotIndex); // atom #2
+ }
+
+ /** Return atom id defined in proto. */
+ @Override
+ public int getStatsId() {
+ return QnsStatsLog.QNS_HANDOVER_TIME_MILLIS;
+ }
+
+ /** Return copy of the AtomsQnsHandoverTimeMillisInfo */
+ @Override
+ public AtomsPulled copy() {
+ return new AtomsQnsHandoverTimeMillisInfo(this);
+ }
+
+ @Override
+ public String getDimension() {
+ return Integer.toString(mSlotIndex);
+ }
+
+ @Override
+ public void accumulate(AtomsPulled info) {
+ if (!(info instanceof AtomsQnsRatPreferenceMismatchInfo)) {
+ return;
+ }
+ AtomsQnsHandoverTimeMillisInfo atomsQnsHandoverTimeMillisInfo =
+ (AtomsQnsHandoverTimeMillisInfo) info;
+ this.mTimeForHoSuccess += atomsQnsHandoverTimeMillisInfo.getTimeForHoSuccess();
+ }
+
+ public int getTimeForHoSuccess() {
+ return mTimeForHoSuccess;
+ }
+
+ public void setTimeForHoSuccess(int timeForHoSuccess) {
+ mTimeForHoSuccess = timeForHoSuccess;
+ }
+
+ public int getSlotIndex() {
+ return mSlotIndex;
+ }
+
+ public void setSlotIndex(int slotIndex) {
+ mSlotIndex = slotIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "AtomsQnsHandoverTimeMillisInfo{" + "mTimeForHoSuccess=" + mTimeForHoSuccess + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AtomsQnsHandoverTimeMillisInfo)) return false;
+ AtomsQnsHandoverTimeMillisInfo that = (AtomsQnsHandoverTimeMillisInfo) o;
+ return mTimeForHoSuccess == that.mTimeForHoSuccess && mSlotIndex == that.mSlotIndex;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTimeForHoSuccess, mSlotIndex);
+ }
+}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsImsCallDropStats.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsImsCallDropStats.java
new file mode 100644
index 0000000..991bce4
--- /dev/null
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsImsCallDropStats.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import android.util.StatsEvent;
+
+import com.android.telephony.qns.stats.QnsStatsLog;
+import com.android.telephony.statslib.AtomsPushed;
+
+import java.util.Objects;
+
+/** AtomsQnsImsCallDropStats class */
+public class AtomsQnsImsCallDropStats extends AtomsPushed {
+
+ /** atom #1 : Transport type in where IMS call drop occurred. */
+ private int mTransportTypeCallDropped;
+
+ /** atom #2 : RTP threshold breached event occurred. */
+ private boolean mRtpThresholdBreached;
+
+ /** atom #3 : Bit mask of restrictions on another transport type */
+ private int mRestrictionsOnOtherTransportType;
+
+ /** atom #4 : Cellular network signal strength {e.g. SSRSRP in NR, RSRP in LTE} */
+ private int mSignalStrength;
+
+ /** atom #5 : Cellular network signal quality {e.g. SSRSRQ in NR, RSRQ in LTE} */
+ private int mSignalQuality;
+
+ /** atom #6 : Cellular network signal noise ratio {e.g. SSSINR in NR, RSSNR in LTE} */
+ private int mSignalNoise;
+
+ /** atom #7 : Iwlan network signal strength (Wi-Fi RSSI) */
+ private int mIwlanSignalStrength;
+
+ /** atom #8 : Slot Index */
+ private int mSlotIndex;
+
+ /** atom #9 : cellular access network type. */
+ private int mCellularNetworkType;
+
+ /** Constructor of AtomsQnsImsCallDropStats */
+ public AtomsQnsImsCallDropStats() {}
+
+ /**
+ * Write the atom information to be recorded to the builder according to the type in order.
+ *
+ * @param builder Builder class for StatsEvent Builder object.
+ */
+ @Override
+ public void build(StatsEvent.Builder builder) {
+ builder.writeInt(mTransportTypeCallDropped); // atom #1
+ builder.writeBoolean(mRtpThresholdBreached); // atom #2
+ builder.writeInt(mRestrictionsOnOtherTransportType); // atom #3
+ builder.writeInt(mSignalStrength); // atom #4
+ builder.writeInt(mSignalQuality); // atom #5
+ builder.writeInt(mSignalNoise); // atom #6
+ builder.writeInt(mIwlanSignalStrength); // atom #7
+ builder.writeInt(mSlotIndex); // atom #8
+ builder.writeInt(mCellularNetworkType); // atom #9
+ }
+
+ /** Return atom id defined in proto. */
+ @Override
+ public int getStatsId() {
+ return QnsStatsLog.QNS_IMS_CALL_DROP_STATS;
+ }
+
+ /** Return copy of the AtomsQnsImsCallDropStats */
+ @Override
+ public AtomsPushed copy() {
+ return new AtomsQnsImsCallDropStats(this);
+ }
+
+ /**
+ * Constructor of AtomsQnsImsCallDropStats
+ *
+ * @param transportTypeCallDropped Transport type in where IMS call drop occurred.
+ * @param rtpThresholdBreached RTP threshold breached event occurred.
+ * @param restrictionsOnOtherTransportType Bit mask of restrictions on another transport type.
+ * @param signalStrength Cellular network signal strength.
+ * @param signalQuality Cellular network signal quality.
+ * @param signalNoise Cellular network signal noise ratio.
+ * @param iwlanSignalStrength Wi-Fi network signal strength.
+ * @param slotIndex Index of sim slot.
+ * @param cellularNetworkType cellular access network type.
+ */
+ public AtomsQnsImsCallDropStats(
+ int transportTypeCallDropped,
+ boolean rtpThresholdBreached,
+ int restrictionsOnOtherTransportType,
+ int signalStrength,
+ int signalQuality,
+ int signalNoise,
+ int iwlanSignalStrength,
+ int slotIndex,
+ int cellularNetworkType) {
+ mTransportTypeCallDropped = transportTypeCallDropped;
+ mRtpThresholdBreached = rtpThresholdBreached;
+ mRestrictionsOnOtherTransportType = restrictionsOnOtherTransportType;
+ mSignalStrength = signalStrength;
+ mSignalQuality = signalQuality;
+ mSignalNoise = signalNoise;
+ mIwlanSignalStrength = iwlanSignalStrength;
+ mSlotIndex = slotIndex;
+ mCellularNetworkType = cellularNetworkType;
+ }
+
+ /**
+ * Copy Constructor of AtomsQnsImsCallDropStats
+ *
+ * @param info The info param to copy from.
+ */
+ public AtomsQnsImsCallDropStats(AtomsQnsImsCallDropStats info) {
+ mTransportTypeCallDropped = info.mTransportTypeCallDropped;
+ mRtpThresholdBreached = info.mRtpThresholdBreached;
+ mRestrictionsOnOtherTransportType = info.mRestrictionsOnOtherTransportType;
+ mSignalStrength = info.mSignalStrength;
+ mSignalQuality = info.mSignalQuality;
+ mSignalNoise = info.mSignalNoise;
+ mIwlanSignalStrength = info.mIwlanSignalStrength;
+ mSlotIndex = info.mSlotIndex;
+ mCellularNetworkType = info.mCellularNetworkType;
+ }
+
+ public int getTransportTypeCallDropped() {
+ return mTransportTypeCallDropped;
+ }
+
+ public void setTransportTypeCallDropped(int transportTypeCallDropped) {
+ mTransportTypeCallDropped = transportTypeCallDropped;
+ }
+
+ public boolean getRtpThresholdBreached() {
+ return mRtpThresholdBreached;
+ }
+
+ public void setRtpThresholdBreached(boolean rtpThresholdBreached) {
+ mRtpThresholdBreached = rtpThresholdBreached;
+ }
+
+ public int getRestrictionsOnOtherTransportType() {
+ return mRestrictionsOnOtherTransportType;
+ }
+
+ public void setRestrictionsOnOtherTransportType(int restrictionsOnOtherTransportType) {
+ mRestrictionsOnOtherTransportType = restrictionsOnOtherTransportType;
+ }
+
+ public int getSignalStrength() {
+ return mSignalStrength;
+ }
+
+ public void setSignalStrength(int signalStrength) {
+ mSignalStrength = signalStrength;
+ }
+
+ public int getSignalQuality() {
+ return mSignalQuality;
+ }
+
+ public void setSignalQuality(int signalQuality) {
+ mSignalQuality = signalQuality;
+ }
+
+ public int getSignalNoise() {
+ return mSignalNoise;
+ }
+
+ public void setSignalNoise(int signalNoise) {
+ mSignalNoise = signalNoise;
+ }
+
+ public int getIwlanSignalStrength() {
+ return mIwlanSignalStrength;
+ }
+
+ public void setIwlanSignalStrength(int iwlanSignalStrength) {
+ mIwlanSignalStrength = iwlanSignalStrength;
+ }
+
+ public int getSlotIndex() {
+ return mSlotIndex;
+ }
+
+ public void setSlotIndex(int slotIndex) {
+ mSlotIndex = slotIndex;
+ }
+
+ public int getCellularNetworkType() {
+ return mCellularNetworkType;
+ }
+
+ public void setCellularNetworkType(int cellularNetworkType) {
+ mCellularNetworkType = cellularNetworkType;
+ }
+
+ @Override
+ public String toString() {
+ return "AtomsQnsImsCallDropStats{"
+ + "mTransportTypeCallDropped="
+ + mTransportTypeCallDropped
+ + ", mRtpThresholdBreached="
+ + mRtpThresholdBreached
+ + ", mRestrictionsOnOtherTransportType="
+ + mRestrictionsOnOtherTransportType
+ + ", mSignalStrength="
+ + mSignalStrength
+ + ", mSignalQuality="
+ + mSignalQuality
+ + ", mSignalNoise="
+ + mSignalNoise
+ + ", mIwlanSignalStrength="
+ + mIwlanSignalStrength
+ + ", mSlotIndex="
+ + mSlotIndex
+ + ", mCellularNetworkType="
+ + mCellularNetworkType
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AtomsQnsImsCallDropStats)) return false;
+ AtomsQnsImsCallDropStats that = (AtomsQnsImsCallDropStats) o;
+ return mTransportTypeCallDropped == that.mTransportTypeCallDropped
+ && mRtpThresholdBreached == that.mRtpThresholdBreached
+ && mRestrictionsOnOtherTransportType == that.mRestrictionsOnOtherTransportType
+ && mSignalStrength == that.mSignalStrength
+ && mSignalQuality == that.mSignalQuality
+ && mSignalNoise == that.mSignalNoise
+ && mIwlanSignalStrength == that.mIwlanSignalStrength
+ && mSlotIndex == that.mSlotIndex
+ && mCellularNetworkType == that.mCellularNetworkType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mTransportTypeCallDropped,
+ mRtpThresholdBreached,
+ mRestrictionsOnOtherTransportType,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mSlotIndex,
+ mCellularNetworkType);
+ }
+}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsRatPreferenceMismatchInfo.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsRatPreferenceMismatchInfo.java
new file mode 100644
index 0000000..150f6a1
--- /dev/null
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQnsRatPreferenceMismatchInfo.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import android.util.StatsEvent;
+
+import com.android.telephony.qns.stats.QnsStatsLog;
+import com.android.telephony.statslib.AtomsPulled;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/** AtomsQnsRatPreferenceMismatchInfo class */
+public class AtomsQnsRatPreferenceMismatchInfo extends AtomsPulled implements Serializable {
+
+ private static final long serialVersionUID = 1913485192L; // 0x720D7788
+
+ /** atom #1 : Net capability of this information. */
+ private int mNetCapability;
+
+ /** atom #2 : Count of handover failed. */
+ private int mHandoverFailCount;
+
+ /** atom #3 : Duration of this mismatch. */
+ private int mDurationOfMismatch;
+
+ /** atom #4 : Carrier Id */
+ private int mCarrierId;
+
+ /** atom #5 : Slot Index */
+ private int mSlotIndex;
+
+ /** Constructor of AtomsQnsRatPreferenceMismatchInfo */
+ public AtomsQnsRatPreferenceMismatchInfo() {}
+
+ /**
+ * Constructor of AtomsQnsRatPreferenceMismatchInfo
+ *
+ * @param netCapability Net capability of this information.
+ * @param handoverFailCount Count of handover failed.
+ * @param durationOfMismatch Duration of this mismatch.
+ * @param carrierId Carrier Id
+ * @param slotIndex Index of sim slot
+ */
+ public AtomsQnsRatPreferenceMismatchInfo(
+ int netCapability,
+ int handoverFailCount,
+ int durationOfMismatch,
+ int carrierId,
+ int slotIndex) {
+ mNetCapability = netCapability;
+ mHandoverFailCount = handoverFailCount;
+ mDurationOfMismatch = durationOfMismatch;
+ mCarrierId = carrierId;
+ mSlotIndex = slotIndex;
+ }
+
+ /**
+ * Copy Constructor of AtomsQnsRatPreferenceMismatchInfo
+ *
+ * @param info The info param to copy from.
+ */
+ public AtomsQnsRatPreferenceMismatchInfo(AtomsQnsRatPreferenceMismatchInfo info) {
+ mNetCapability = info.mNetCapability;
+ mHandoverFailCount = info.mHandoverFailCount;
+ mDurationOfMismatch = info.mDurationOfMismatch;
+ mCarrierId = info.mCarrierId;
+ mSlotIndex = info.mSlotIndex;
+ }
+
+ /**
+ * Write the atom information to be recorded to the builder according to the type in order.
+ *
+ * @param builder Builder class for StatsEvent Builder object.
+ */
+ @Override
+ public void build(StatsEvent.Builder builder) {
+ builder.writeInt(mNetCapability); // atom #1
+ builder.writeInt(mHandoverFailCount); // atom #2
+ builder.writeInt(mDurationOfMismatch); // atom #3
+ builder.writeInt(mCarrierId); // atom #4
+ builder.writeInt(mSlotIndex); // atom #5
+ }
+
+ /** Return atom id defined in proto. */
+ @Override
+ public int getStatsId() {
+ return QnsStatsLog.QNS_RAT_PREFERENCE_MISMATCH_INFO;
+ }
+
+ /** Return copy of the AtomsQnsRatPreferenceMismatchInfo */
+ @Override
+ public AtomsPulled copy() {
+ return new AtomsQnsRatPreferenceMismatchInfo(this);
+ }
+
+ @Override
+ public String getDimension() {
+ return mNetCapability + "_" + mCarrierId + "_" + mSlotIndex;
+ }
+
+ @Override
+ public void accumulate(AtomsPulled info) {
+ if (!(info instanceof AtomsQnsRatPreferenceMismatchInfo)) {
+ return;
+ }
+ AtomsQnsRatPreferenceMismatchInfo atomsQnsRatPreferenceMismatchInfo =
+ (AtomsQnsRatPreferenceMismatchInfo) info;
+ this.mDurationOfMismatch += atomsQnsRatPreferenceMismatchInfo.getDurationOfMismatch();
+ this.mHandoverFailCount += atomsQnsRatPreferenceMismatchInfo.getHandoverFailCount();
+ }
+
+ public int getNetCapability() {
+ return mNetCapability;
+ }
+
+ public void setNetCapability(int netCapability) {
+ mNetCapability = netCapability;
+ }
+
+ public int getHandoverFailCount() {
+ return mHandoverFailCount;
+ }
+
+ public void setHandoverFailCount(int handoverFailCount) {
+ mHandoverFailCount = handoverFailCount;
+ }
+
+ public int getDurationOfMismatch() {
+ return mDurationOfMismatch;
+ }
+
+ public void setDurationOfMismatch(int durationOfMismatch) {
+ mDurationOfMismatch = durationOfMismatch;
+ }
+
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+
+ public void setCarrierId(int carrierId) {
+ mCarrierId = carrierId;
+ }
+
+ public int getSlotIndex() {
+ return mSlotIndex;
+ }
+
+ public void setSlotIndex(int slotIndex) {
+ mSlotIndex = slotIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "AtomsQnsRatPreferenceMismatchInfo{"
+ + "mNetCapability="
+ + mNetCapability
+ + ", mHandoverFailCount="
+ + mHandoverFailCount
+ + ", mDurationOfMismatch="
+ + mDurationOfMismatch
+ + ", mCarrierId="
+ + mCarrierId
+ + ", mSlotIndex="
+ + mSlotIndex
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AtomsQnsRatPreferenceMismatchInfo)) return false;
+ AtomsQnsRatPreferenceMismatchInfo that = (AtomsQnsRatPreferenceMismatchInfo) o;
+ return mNetCapability == that.mNetCapability
+ && mHandoverFailCount == that.mHandoverFailCount
+ && mDurationOfMismatch == that.mDurationOfMismatch
+ && mCarrierId == that.mCarrierId
+ && mSlotIndex == that.mSlotIndex;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mNetCapability, mHandoverFailCount, mDurationOfMismatch, mCarrierId, mSlotIndex);
+ }
+}
diff --git a/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQualifiedRatListChangedInfo.java b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQualifiedRatListChangedInfo.java
new file mode 100644
index 0000000..ea3ec6b
--- /dev/null
+++ b/services/QualifiedNetworksService/src/com/android/telephony/qns/atoms/AtomsQualifiedRatListChangedInfo.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import android.util.StatsEvent;
+
+import com.android.telephony.qns.stats.QnsStatsLog;
+import com.android.telephony.statslib.AtomsPushed;
+
+import java.util.Objects;
+
+/** AtomsQualifiedRatListChangedInfo class */
+public class AtomsQualifiedRatListChangedInfo extends AtomsPushed {
+
+ /** atom #1 : NetCapability of this Qualified RAT update */
+ private int mNetCapability;
+ /** atom #2 : The most preferred qualified RAT */
+ private int mFirstQualifiedRat;
+ /** atom #3 : Second preferred qualified RAT */
+ private int mSecondQualifiedRat;
+ /** atom #4 : Current actual transport type of Data session for this NetCapability */
+ private int mCurrentTransportType;
+ /** atom #5 : Indicates whether WFC is enabled */
+ private boolean mWfcEnabled;
+ /** atom #6 : Indicates the user's WFC mode */
+ private int mWfcMode;
+ /** atom #7 : Current Cellular AccessNetwork Type */
+ private int mCellularNetworkType;
+ /** atom #8 : Available IWLAN AccessNetwork */
+ private int mIwlanNetworkType;
+ /** atom #9 : Bit mask of restrictions on WWAN */
+ private int mRestrictionsOnWwan;
+ /** atom #10 : Bit mask of restrictions on WLAN */
+ private int mRestrictionsOnWlan;
+ /** atom #11 : Cellular network signal strength {e.g. SSRSRP in NR, RSRP in LTE} */
+ private int mSignalStrength;
+ /** atom #12 : Cellular network signal quality {e.g. SSRSRQ in NR, RSRQ in LTE} */
+ private int mSignalQuality;
+ /** atom #13 : Cellular network signal noise ratio {e.g. SSSINR in NR, RSSNR in LTE} */
+ private int mSignalNoise;
+ /** atom #14 : Iwlan network signal strength (Wi-Fi RSSI) */
+ private int mIwlanSignalStrength;
+ /** atom #15 : Reason for preferred RAT update */
+ private int mUpdateReason;
+ /** atom #16: IMS Call Type */
+ private int mImsCallType;
+ /** atom #17 : IMS Call Quality */
+ private int mImsCallQuality;
+ /** atom #18 : Slot Index */
+ private int mSlotIndex;
+
+ /** Constructor of AtomsQualifiedRatListChangedInfo */
+ public AtomsQualifiedRatListChangedInfo() {}
+
+ /**
+ * Constructor of AtomsQualifiedRatListChangedInfo
+ *
+ * @param netCapability NetCapability of this Qualified RAT update
+ * @param firstQualifiedRat The most preferred qualified RAT
+ * @param secondQualifiedRat Second preferred qualified RAT
+ * @param currentTransportType Current actual transport type of Data session for this
+ * NetCapability
+ * @param wfcEnabled Indicates whether WFC is enabled
+ * @param wfcMode Indicates the user's WFC mode
+ * @param cellularNetworkType Current Cellular AccessNetwork Type
+ * @param iwlanNetworkType Available IWLAN AccessNetwork
+ * @param restrictionsOnWwan Bit mask of restrictions on WWAN
+ * @param restrictionsOnWlan Bit mask of restrictions on WLAN
+ * @param signalStrength Cellular network signal strength {e.g. SSRSRP in NR, RSRP in LTE, RSCP
+ * in UMTS}
+ * @param signalQuality Cellular network signal quality {e.g. SSRSRQ in NR, RSRQ in LTE}
+ * @param signalNoise Cellular network signal noise ratio {e.g. SSSINR in NR, RSSNR in LTE}
+ * @param iwlanSignalStrength Iwlan network signal strength (Wi-Fi RSSI)
+ * @param updateReason Reason for preferred RAT update
+ * @param imsCallType Ims Call Type {e.g. IDLE, VOICE, VIDEO, E-CALL}
+ * @param imsCallQuality Ims Call Quality
+ * @param slotIndex Index of sim slot
+ */
+ public AtomsQualifiedRatListChangedInfo(
+ int netCapability,
+ int firstQualifiedRat,
+ int secondQualifiedRat,
+ int currentTransportType,
+ boolean wfcEnabled,
+ int wfcMode,
+ int cellularNetworkType,
+ int iwlanNetworkType,
+ int restrictionsOnWwan,
+ int restrictionsOnWlan,
+ int signalStrength,
+ int signalQuality,
+ int signalNoise,
+ int iwlanSignalStrength,
+ int updateReason,
+ int imsCallType,
+ int imsCallQuality,
+ int slotIndex) {
+ mNetCapability = netCapability;
+ mFirstQualifiedRat = firstQualifiedRat;
+ mSecondQualifiedRat = secondQualifiedRat;
+ mCurrentTransportType = currentTransportType;
+ mWfcEnabled = wfcEnabled;
+ mWfcMode = wfcMode;
+ mCellularNetworkType = cellularNetworkType;
+ mIwlanNetworkType = iwlanNetworkType;
+ mRestrictionsOnWwan = restrictionsOnWwan;
+ mRestrictionsOnWlan = restrictionsOnWlan;
+ mSignalStrength = signalStrength;
+ mSignalQuality = signalQuality;
+ mSignalNoise = signalNoise;
+ mIwlanSignalStrength = iwlanSignalStrength;
+ mUpdateReason = updateReason;
+ mImsCallType = imsCallType;
+ mImsCallQuality = imsCallQuality;
+ mSlotIndex = slotIndex;
+ }
+
+ /**
+ * Copy Constructor of AtomsQualifiedRatListChangedInfo
+ *
+ * @param info The info param to copy from.
+ */
+ public AtomsQualifiedRatListChangedInfo(AtomsQualifiedRatListChangedInfo info) {
+ mNetCapability = info.mNetCapability;
+ mFirstQualifiedRat = info.mFirstQualifiedRat;
+ mSecondQualifiedRat = info.mSecondQualifiedRat;
+ mCurrentTransportType = info.mCurrentTransportType;
+ mWfcEnabled = info.mWfcEnabled;
+ mWfcMode = info.mWfcMode;
+ mCellularNetworkType = info.mCellularNetworkType;
+ mIwlanNetworkType = info.mIwlanNetworkType;
+ mRestrictionsOnWwan = info.mRestrictionsOnWwan;
+ mRestrictionsOnWlan = info.mRestrictionsOnWlan;
+ mSignalStrength = info.mSignalStrength;
+ mSignalQuality = info.mSignalQuality;
+ mSignalNoise = info.mSignalNoise;
+ mIwlanSignalStrength = info.mIwlanSignalStrength;
+ mUpdateReason = info.mUpdateReason;
+ mImsCallType = info.mImsCallType;
+ mImsCallQuality = info.mImsCallQuality;
+ mSlotIndex = info.mSlotIndex;
+ }
+
+ /**
+ * Write the atom information to be recorded to the builder according to the type in order.
+ *
+ * @param builder Builder class for StatsEvent Builder object.
+ */
+ @Override
+ public void build(StatsEvent.Builder builder) {
+ builder.writeInt(mNetCapability); // atom #1
+ builder.writeInt(mFirstQualifiedRat); // atom #2
+ builder.writeInt(mSecondQualifiedRat); // atom #3
+ builder.writeInt(mCurrentTransportType); // atom #4
+ builder.writeBoolean(mWfcEnabled); // atom #5
+ builder.writeInt(mWfcMode); // atom #6
+ builder.writeInt(mCellularNetworkType); // atom #7
+ builder.writeInt(mIwlanNetworkType); // atom #8
+ builder.writeInt(mRestrictionsOnWwan); // atom #9
+ builder.writeInt(mRestrictionsOnWlan); // atom #10
+ builder.writeInt(mSignalStrength); // atom #11
+ builder.writeInt(mSignalQuality); // atom #12
+ builder.writeInt(mSignalNoise); // atom #13
+ builder.writeInt(mIwlanSignalStrength); // atom #14
+ builder.writeInt(mUpdateReason); // atom #15
+ builder.writeInt(mImsCallType); // atom #16
+ builder.writeInt(mImsCallQuality); // atom #17
+ builder.writeInt(mSlotIndex); // atom #18
+ }
+
+ /** Return atom id defined in proto. */
+ @Override
+ public int getStatsId() {
+ return QnsStatsLog.QUALIFIED_RAT_LIST_CHANGED;
+ }
+
+ /** Return copy of the AtomsQualifiedRatListChangedInfo */
+ @Override
+ public AtomsPushed copy() {
+ return new AtomsQualifiedRatListChangedInfo(this);
+ }
+
+ public int getNetCapability() {
+ return mNetCapability;
+ }
+
+ public void setNetCapability(int netCapability) {
+ mNetCapability = netCapability;
+ }
+
+ public int getFirstQualifiedRat() {
+ return mFirstQualifiedRat;
+ }
+
+ public void setFirstQualifiedRat(int firstQualifiedRat) {
+ mFirstQualifiedRat = firstQualifiedRat;
+ }
+
+ public int getSecondQualifiedRat() {
+ return mSecondQualifiedRat;
+ }
+
+ public void setSecondQualifiedRat(int secondQualifiedRat) {
+ mSecondQualifiedRat = secondQualifiedRat;
+ }
+
+ public int getCurrentTransportType() {
+ return mCurrentTransportType;
+ }
+
+ public void setCurrentTransportType(int currentTransportType) {
+ mCurrentTransportType = currentTransportType;
+ }
+
+ public boolean getWfcEnabled() {
+ return mWfcEnabled;
+ }
+
+ public void setWfcEnabled(boolean wfcEnabled) {
+ mWfcEnabled = wfcEnabled;
+ }
+
+ public int getWfcMode() {
+ return mWfcMode;
+ }
+
+ public void setWfcMode(int wfcMode) {
+ mWfcMode = wfcMode;
+ }
+
+ public int getCellularNetworkType() {
+ return mCellularNetworkType;
+ }
+
+ public void setCellularNetworkType(int cellularNetworkType) {
+ mCellularNetworkType = cellularNetworkType;
+ }
+
+ public int getIwlanNetworkType() {
+ return mIwlanNetworkType;
+ }
+
+ public void setIwlanNetworkType(int iwlanNetworkType) {
+ mIwlanNetworkType = iwlanNetworkType;
+ }
+
+ public int getRestrictionsOnWwan() {
+ return mRestrictionsOnWwan;
+ }
+
+ public void setRestrictionsOnWwan(int restrictionsOnWwan) {
+ mRestrictionsOnWwan = restrictionsOnWwan;
+ }
+
+ public int getRestrictionsOnWlan() {
+ return mRestrictionsOnWlan;
+ }
+
+ public void setRestrictionsOnWlan(int restrictionsOnWlan) {
+ mRestrictionsOnWlan = restrictionsOnWlan;
+ }
+
+ public int getSignalStrength() {
+ return mSignalStrength;
+ }
+
+ public void setSignalStrength(int signalStrength) {
+ mSignalStrength = signalStrength;
+ }
+
+ public int getSignalQuality() {
+ return mSignalQuality;
+ }
+
+ public void setSignalQuality(int signalQuality) {
+ mSignalQuality = signalQuality;
+ }
+
+ public int getSignalNoise() {
+ return mSignalNoise;
+ }
+
+ public void setSignalNoise(int signalNoise) {
+ mSignalNoise = signalNoise;
+ }
+
+ public int getIwlanSignalStrength() {
+ return mIwlanSignalStrength;
+ }
+
+ public void setIwlanSignalStrength(int iwlanSignalStrength) {
+ mIwlanSignalStrength = iwlanSignalStrength;
+ }
+
+ public int getUpdateReason() {
+ return mUpdateReason;
+ }
+
+ public void setUpdateReason(int updateReason) {
+ mUpdateReason = updateReason;
+ }
+
+ public int getImsCallType() {
+ return mImsCallType;
+ }
+
+ public void setImsCallType(int imsCallType) {
+ mImsCallType = imsCallType;
+ }
+
+ public int getImsCallQuality() {
+ return mImsCallQuality;
+ }
+
+ public void setImsCallQuality(int imsCallQuality) {
+ mImsCallQuality = imsCallQuality;
+ }
+
+ public int getSlotIndex() {
+ return mSlotIndex;
+ }
+
+ public void setSlotIndex(int slotIndex) {
+ mSlotIndex = slotIndex;
+ }
+
+ @Override
+ public String toString() {
+ return "AtomsQualifiedRatListChangedInfo{"
+ + "mNetCapability="
+ + mNetCapability
+ + ", mFirstQualifiedRat="
+ + mFirstQualifiedRat
+ + ", mSecondQualifiedRat="
+ + mSecondQualifiedRat
+ + ", mCurrentTransportType="
+ + mCurrentTransportType
+ + ", mWfcEnabled="
+ + mWfcEnabled
+ + ", mWfcMode="
+ + mWfcMode
+ + ", mCellularNetworkType="
+ + mCellularNetworkType
+ + ", mIwlanNetworkType="
+ + mIwlanNetworkType
+ + ", mRestrictionsOnWwan="
+ + mRestrictionsOnWwan
+ + ", mRestrictionsOnWlan="
+ + mRestrictionsOnWlan
+ + ", mSignalStrength="
+ + mSignalStrength
+ + ", mSignalQuality="
+ + mSignalQuality
+ + ", mSignalNoise="
+ + mSignalNoise
+ + ", mIwlanSignalStrength="
+ + mIwlanSignalStrength
+ + ", mUpdateReason="
+ + mUpdateReason
+ + ", mImsCallType="
+ + mImsCallType
+ + ", mImsCallQuality="
+ + mImsCallQuality
+ + ", mSlotIndex="
+ + mSlotIndex
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof AtomsQualifiedRatListChangedInfo)) return false;
+ AtomsQualifiedRatListChangedInfo that = (AtomsQualifiedRatListChangedInfo) o;
+ return mNetCapability == that.mNetCapability
+ && mFirstQualifiedRat == that.mFirstQualifiedRat
+ && mSecondQualifiedRat == that.mSecondQualifiedRat
+ && mCurrentTransportType == that.mCurrentTransportType
+ && mWfcEnabled == that.mWfcEnabled
+ && mWfcMode == that.mWfcMode
+ && mCellularNetworkType == that.mCellularNetworkType
+ && mIwlanNetworkType == that.mIwlanNetworkType
+ && mRestrictionsOnWwan == that.mRestrictionsOnWwan
+ && mRestrictionsOnWlan == that.mRestrictionsOnWlan
+ && mSignalStrength == that.mSignalStrength
+ && mSignalQuality == that.mSignalQuality
+ && mSignalNoise == that.mSignalNoise
+ && mIwlanSignalStrength == that.mIwlanSignalStrength
+ && mUpdateReason == that.mUpdateReason
+ && mImsCallType == that.mImsCallType
+ && mImsCallQuality == that.mImsCallQuality
+ && mSlotIndex == that.mSlotIndex;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mNetCapability,
+ mFirstQualifiedRat,
+ mSecondQualifiedRat,
+ mCurrentTransportType,
+ mWfcEnabled,
+ mWfcMode,
+ mCellularNetworkType,
+ mIwlanNetworkType,
+ mRestrictionsOnWwan,
+ mRestrictionsOnWlan,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mUpdateReason,
+ mImsCallType,
+ mImsCallQuality,
+ mSlotIndex);
+ }
+}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/AccessNetworkEvaluatorTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/AccessNetworkEvaluatorTest.java
index 8d3883e..9c59fd7 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/AccessNetworkEvaluatorTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/AccessNetworkEvaluatorTest.java
@@ -29,6 +29,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.isNotNull;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
@@ -47,6 +48,7 @@
import android.telephony.SignalThresholdInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ProvisioningManager;
import com.android.telephony.qns.AccessNetworkSelectionPolicy.PreCondition;
@@ -63,6 +65,7 @@
import org.mockito.stubbing.Answer;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
@@ -71,6 +74,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
@RunWith(JUnit4.class)
public class AccessNetworkEvaluatorTest extends QnsTest {
@@ -86,6 +90,7 @@
private static final int EVENT_WFC_ACTIVATION_WITH_IWLAN_CONNECTION_REQUIRED = EVENT_BASE + 9;
private static final int EVENT_IMS_REGISTRATION_STATE_CHANGED = EVENT_BASE + 10;
private static final int EVENT_SIP_DIALOG_SESSION_STATE_CHANGED = EVENT_BASE + 12;
+ private static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = EVENT_BASE + 13;
@Mock private RestrictManager mRestrictManager;
@Mock private DataConnectionStatusTracker mDataConnectionStatusTracker;
@@ -164,6 +169,8 @@
when(mMockQnsTelephonyListener.getLastQnsTelephonyInfo())
.thenReturn(mMockQnsTelephonyListener.new QnsTelephonyInfo());
+ when(mMockQnsTelephonyListener.getLastQnsTelephonyInfo())
+ .thenReturn(mMockQnsTelephonyListener.new QnsTelephonyInfo());
}
@After
@@ -282,6 +289,8 @@
when(mDataConnectionStatusTracker.isActiveState()).thenReturn(true);
when(mDataConnectionStatusTracker.getLastTransportType())
.thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+ when(mMockQnsCallStatusTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS))
+ .thenReturn(true);
List<Integer> accessNetworks = new ArrayList<>();
accessNetworks.add(AccessNetworkConstants.AccessNetworkType.IWLAN);
QnsTelephonyListener.QnsTelephonyInfo info =
@@ -342,6 +351,8 @@
when(mDataConnectionStatusTracker.isActiveState()).thenReturn(true);
when(mDataConnectionStatusTracker.getLastTransportType())
.thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+ when(mMockQnsCallStatusTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS))
+ .thenReturn(true);
List<Integer> accessNetworks = new ArrayList<>();
accessNetworks.add(AccessNetworkConstants.AccessNetworkType.IWLAN);
QnsTelephonyListener.QnsTelephonyInfo info =
@@ -375,14 +386,20 @@
mAne.onQnsTelephonyInfoChanged(infoIms);
mAne.updateLastNotifiedQualifiedNetwork(accessNetworks);
mAne.onSetCallType(QnsConstants.CALL_TYPE_VOICE);
+ when(mMockQnsCallStatusTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS))
+ .thenReturn(false);
assertTrue(mAne.needHandoverPolicyCheck());
assertFalse(mAne.moveTransportTypeAllowed());
mAne.updateLastNotifiedQualifiedNetwork(accessNetworks);
mAne.onSetCallType(QnsConstants.CALL_TYPE_IDLE);
+ when(mMockQnsCallStatusTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS))
+ .thenReturn(true);
assertTrue(mAne.needHandoverPolicyCheck());
assertTrue(mAne.moveTransportTypeAllowed());
mAne.updateLastNotifiedQualifiedNetwork(accessNetworks);
mAne.onSetCallType(QnsConstants.CALL_TYPE_EMERGENCY);
+ when(mMockQnsCallStatusTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS))
+ .thenReturn(false);
assertTrue(mAne.needHandoverPolicyCheck());
assertFalse(mAne.moveTransportTypeAllowed());
}
@@ -1734,4 +1751,87 @@
assertEquals(
QnsConstants.CALL_TYPE_VIDEO, matchedAnsp.get(0).getPreCondition().getCallType());
}
+
+ @Test
+ public void testDataConnectionDisconnectedOnSos_ResettingThresholds() {
+ AccessNetworkEvaluator aneSos =
+ new AccessNetworkEvaluator(
+ mQnsComponents[mSlotIndex],
+ NetworkCapabilities.NET_CAPABILITY_EIMS,
+ mRestrictManager,
+ mDataConnectionStatusTracker,
+ mSlotIndex);
+ aneSos.registerForQualifiedNetworksChanged(mHandler, QUALIFIED_NETWORKS_CHANGED);
+ waitForLastHandlerAction(aneSos.mHandler);
+
+ aneSos.onDataConnectionStateChanged(
+ new DataConnectionStatusTracker.DataConnectionChangedInfo(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED,
+ DataConnectionStatusTracker.STATE_INACTIVE,
+ AccessNetworkConstants.TRANSPORT_TYPE_INVALID));
+ waitForLastHandlerAction(aneSos.mHandler);
+
+ aneSos.onDataConnectionStateChanged(
+ new DataConnectionStatusTracker.DataConnectionChangedInfo(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_FAILED,
+ DataConnectionStatusTracker.STATE_INACTIVE,
+ AccessNetworkConstants.TRANSPORT_TYPE_INVALID));
+ waitForLastHandlerAction(aneSos.mHandler);
+
+ verify(mMockWifiQm, times(2)).updateThresholdsForNetCapability(
+ NetworkCapabilities.NET_CAPABILITY_EIMS, mSlotIndex, null);
+ }
+
+ @Test
+ public void testOnImsCallDisconnectCauseChanged() {
+ // ANE takes time to build ANSP.
+ waitForLastHandlerAction(mAne.mHandler);
+ when(mRestrictManager.isRestricted(anyInt())).thenReturn(false);
+ when(mRestrictManager.isAllowedOnSingleTransport(anyInt())).thenReturn(true);
+ when(mDataConnectionStatusTracker.getLastTransportType())
+ .thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ // make iwlan and cellular available
+ IwlanNetworkStatusTracker.IwlanAvailabilityInfo iwlanInfo =
+ mMockIwlanNetworkStatusTracker.new IwlanAvailabilityInfo(true, false);
+ mAne.onIwlanNetworkStatusChanged(iwlanInfo);
+ QnsTelephonyListener.QnsTelephonyInfo cellInfo =
+ mMockQnsTelephonyListener.new QnsTelephonyInfo();
+ cellInfo.setCellularAvailable(true);
+ cellInfo.setCoverage(true);
+ cellInfo.setDataNetworkType(TelephonyManager.NETWORK_TYPE_LTE);
+ cellInfo.setVoiceNetworkType(TelephonyManager.NETWORK_TYPE_LTE);
+ cellInfo.setDataRegState(ServiceState.STATE_IN_SERVICE);
+ mAne.onQnsTelephonyInfoChanged(cellInfo);
+ assertTrue(mAne.mIwlanAvailable);
+ assertTrue(mAne.mCellularAvailable);
+
+ // send ims call drop event.
+ ImsReasonInfo imsReasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_MEDIA_NO_DATA, 0);
+ Message.obtain(mAne.mHandler, EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED,
+ new QnsAsyncResult(null, imsReasonInfo, null)).sendToTarget();
+ waitForLastHandlerAction(mAne.mHandler);
+
+ verify(mMockQnsMetrics, atLeast(1))
+ .reportAtomForImsCallDropStats(
+ anyInt(), anyInt(), any(), any(), any(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void testEvaluateSpecificReasonToString() throws Exception {
+ Method method = AccessNetworkEvaluator.class.getDeclaredMethod(
+ "evaluateSpecificReasonToString", int.class);
+ method.setAccessible(true);
+
+ IntStream.rangeClosed(0, 4).forEach(i -> {
+ try {
+ assertTrue(((String) method.invoke(mAne, i)).startsWith(
+ "EVALUATE_SPECIFIC_REASON_"));
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/AlternativeEventListenerTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/AlternativeEventListenerTest.java
deleted file mode 100644
index f3583a3..0000000
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/AlternativeEventListenerTest.java
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- * Copyright (C) 2022 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.telephony.qns;
-
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.when;
-
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
-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;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(JUnit4.class)
-public class AlternativeEventListenerTest extends QnsTest {
-
- AlternativeEventListener mListener;
- AltEventProvider mAltEventProvider;
- TestLooper mTestLooper;
- private static final int SLOT_INDEX = 0;
- private Handler mHandler;
- CountDownLatch mLatch;
- int[] mThresholds;
- // QnsTelephonyListener mQtListener;
-
- class AltEventProvider extends AlternativeEventProvider {
-
- AltEventProvider(AlternativeEventListener altEventListener, int slotId) {
- super(altEventListener, slotId);
- }
-
- @Override
- public void requestRtpThreshold(
- int callId,
- int jitter,
- int packetLossRate,
- int packetLossTimeInMilliSec,
- int noRtpTimeInMilliSec) {}
-
- @Override
- public void setEcnoSignalThreshold(int[] threshold) {
- if (mLatch != null) {
- mThresholds = threshold;
- mLatch.countDown();
- }
- }
- }
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- super.setUp();
- mTestLooper = new TestLooper();
- Mockito.when(sMockContext.getMainLooper()).thenReturn(mTestLooper.getLooper());
- mHandler = new Handler(mTestLooper.getLooper());
- mListener = new AlternativeEventListener(sMockContext, mMockQnsTelephonyListener, 0);
- mAltEventProvider = new AltEventProvider(mMockAltEventListener, SLOT_INDEX);
- mListener.setEventProvider(mAltEventProvider);
- }
-
- @After
- public void tearDown() {
- mListener.close();
- }
-
- @Test
- public void testRegisterEmergencyPreferredTransportTypeChanged() {
- int[] expectedTransports =
- new int[] {
- AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
- AccessNetworkConstants.TRANSPORT_TYPE_WWAN
- };
-
- mListener.registerEmergencyPreferredTransportTypeChanged(mHandler, 1, null);
-
- for (int expectedTransport : expectedTransports) {
- mAltEventProvider.notifyEmergencyPreferredTransportType(expectedTransport);
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- QnsAsyncResult result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- int actualTransport = (int) result.mResult;
- assertEquals(expectedTransport, actualTransport);
- }
- }
-
- @Test
- public void testUnregisterEmergencyPreferredTransportTypeChanged() {
- mListener.registerEmergencyPreferredTransportTypeChanged(mHandler, 1, null);
- mAltEventProvider.notifyEmergencyPreferredTransportType(
- AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
-
- mListener.unregisterEmergencyPreferredTransportTypeChanged();
- mAltEventProvider.notifyEmergencyPreferredTransportType(
- AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
-
- mAltEventProvider.notifyEmergencyPreferredTransportType(
- AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
- }
-
- @Test
- public void testRegisterTryWfcConnectionStateListener() {
- mListener.registerTryWfcConnectionStateListener(mHandler, 1, null);
- boolean[] expectedStates = new boolean[] {false, true, false};
-
- for (boolean expectedState : expectedStates) {
- mAltEventProvider.notifyTryWfcConnectionState(expectedState);
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- QnsAsyncResult result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- boolean actualState = (boolean) result.mResult;
- assertEquals(expectedState, actualState);
- }
- }
-
- @Test
- public void testForRtpQualityScenarios() {
- QnsCarrierConfigManager.RtpMetricsConfig rtpConfig =
- new QnsCarrierConfigManager.RtpMetricsConfig(0, 0, 0, 0);
- int expectedReason = QnsConstants.RTP_LOW_QUALITY_REASON_JITTER;
-
- // register to IMS, Emergency:
- mListener.registerLowRtpQualityEvent(
- NetworkCapabilities.NET_CAPABILITY_IMS, mHandler, 1, null, rtpConfig);
- mListener.registerLowRtpQualityEvent(
- NetworkCapabilities.NET_CAPABILITY_EIMS, mHandler, 2, null, rtpConfig);
-
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_VOICE, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
- mAltEventProvider.notifyRtpLowQuality(expectedReason);
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- QnsAsyncResult result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- int actualReason = (int) result.mResult;
- assertEquals(expectedReason, actualReason);
-
- // Do not notify when call is disconnected:
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_VOICE, PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED);
- mAltEventProvider.notifyRtpLowQuality(expectedReason);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
-
- mAltEventProvider.notifyCallInfo(
- 2, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
- mAltEventProvider.notifyRtpLowQuality(expectedReason);
- msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- actualReason = (int) result.mResult;
- assertEquals(expectedReason, actualReason);
-
- // Do not notify when call is disconnected:
- mAltEventProvider.notifyCallInfo(
- 1,
- QnsConstants.CALL_TYPE_EMERGENCY,
- PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED);
- mAltEventProvider.notifyRtpLowQuality(expectedReason);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
- }
-
- @Test
- public void testUnregisterLowRtpQualityEvent() {
- QnsCarrierConfigManager.RtpMetricsConfig rtpConfig =
- new QnsCarrierConfigManager.RtpMetricsConfig(0, 0, 0, 0);
- int expectedReason = QnsConstants.RTP_LOW_QUALITY_REASON_JITTER;
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_VOICE, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
-
- // register to IMS, Emergency:
- mListener.registerLowRtpQualityEvent(
- NetworkCapabilities.NET_CAPABILITY_IMS, mHandler, 1, null, rtpConfig);
- mListener.registerLowRtpQualityEvent(
- NetworkCapabilities.NET_CAPABILITY_EIMS, mHandler, 2, null, rtpConfig);
- mAltEventProvider.notifyRtpLowQuality(expectedReason);
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
-
- // unregister for IMS
- mListener.unregisterLowRtpQualityEvent(NetworkCapabilities.NET_CAPABILITY_IMS, mHandler);
- mAltEventProvider.notifyRtpLowQuality(expectedReason);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
-
- // Event still registered for emergency, hence it should be notified:
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
- mAltEventProvider.notifyRtpLowQuality(expectedReason);
- msg = mTestLooper.nextMessage();
- assertNotNull(msg);
-
- // unregister for Emergency:
- mListener.unregisterLowRtpQualityEvent(NetworkCapabilities.NET_CAPABILITY_EIMS, mHandler);
- mAltEventProvider.notifyRtpLowQuality(expectedReason);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
- }
-
- @Test
- public void testForCallTypeChangedScenarios() {
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_IMS, null, 1, null);
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_IMS, mHandler, 1, null);
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_EIMS, mHandler, 1, null);
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_MMS, mHandler, 1, null);
-
- // Test1:
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_VOICE, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
-
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- QnsAsyncResult result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- assertEquals(QnsConstants.CALL_TYPE_VOICE, (int) result.mResult);
- assertFalse(mListener.isIdleState()); // for IMS calls only
-
- // Test2:
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_VOICE, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
- msg = mTestLooper.nextMessage();
-
- // Should not notify if call type is not changed
- assertNull(msg);
-
- // Test3:
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_VOICE, PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED);
- msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- assertEquals(QnsConstants.CALL_TYPE_IDLE, (int) result.mResult);
- assertTrue(mListener.isIdleState()); // for IMS calls only
-
- // Test4:
- mAltEventProvider.notifyCallInfo(
- 2, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
- msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- assertEquals(QnsConstants.CALL_TYPE_EMERGENCY, (int) result.mResult);
-
- // Test5:
- mAltEventProvider.notifyCallInfo(
- 2,
- QnsConstants.CALL_TYPE_EMERGENCY,
- PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED);
- msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- assertEquals(QnsConstants.CALL_TYPE_IDLE, (int) result.mResult);
- }
-
- @Test
- public void testUnregisterCallTypeChangedListener() {
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_IMS, null, 1, null);
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_IMS, mHandler, 1, null);
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_EIMS, mHandler, 1, null);
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_MMS, mHandler, 1, null);
-
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_VOICE, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
-
- mListener.unregisterCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_IMS, mHandler);
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_VOICE, PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
-
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
- msg = mTestLooper.nextMessage();
- assertNotNull(msg);
-
- mListener.unregisterCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_EIMS, mHandler);
- mAltEventProvider.notifyCallInfo(
- 1,
- QnsConstants.CALL_TYPE_EMERGENCY,
- PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
- }
-
- @Test
- public void testEmergencyOverImsCallTypeChangedScenarios() {
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_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();
-
- when(mMockQnsTelephonyListener.getLastPreciseDataConnectionState(
- NetworkCapabilities.NET_CAPABILITY_EIMS))
- .thenReturn(emergencyDataStatus);
- when(mMockQnsTelephonyListener.getLastPreciseDataConnectionState(
- NetworkCapabilities.NET_CAPABILITY_IMS))
- .thenReturn(imsDataStatus);
- // Test1:
- mAltEventProvider.notifyCallInfo(
- 1, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_DIALING);
-
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- QnsAsyncResult result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- assertEquals(QnsConstants.CALL_TYPE_EMERGENCY, (int) result.mResult);
-
- // 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();
- Mockito.clearInvocations(mMockQnsTelephonyListener);
- when(mMockQnsTelephonyListener.getLastPreciseDataConnectionState(
- NetworkCapabilities.NET_CAPABILITY_IMS))
- .thenReturn(imsDataStatus);
-
- mAltEventProvider.notifyCallInfo(
- 1,
- QnsConstants.CALL_TYPE_EMERGENCY,
- PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED);
- msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- assertEquals(QnsConstants.CALL_TYPE_IDLE, (int) result.mResult);
-
- // 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();
- Mockito.clearInvocations(mMockQnsTelephonyListener);
- when(mMockQnsTelephonyListener.getLastPreciseDataConnectionState(
- NetworkCapabilities.NET_CAPABILITY_EIMS))
- .thenReturn(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();
- Mockito.clearInvocations(mMockQnsTelephonyListener);
- when(mMockQnsTelephonyListener.getLastPreciseDataConnectionState(
- NetworkCapabilities.NET_CAPABILITY_IMS))
- .thenReturn(imsDataStatus);
- mAltEventProvider.notifyCallInfo(
- 2, QnsConstants.CALL_TYPE_EMERGENCY, PreciseCallState.PRECISE_CALL_STATE_ACTIVE);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
- }
-
- @Test
- public void testOnSrvccStateChanged() {
- mListener.registerCallTypeChangedListener(
- NetworkCapabilities.NET_CAPABILITY_IMS, mHandler, 1, null);
-
- mListener.onSrvccStateChanged(TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED);
- Message msg = mTestLooper.nextMessage();
- assertNotNull(msg);
- QnsAsyncResult result = (QnsAsyncResult) msg.obj;
- assertNotNull(result.mResult);
- assertEquals(QnsConstants.CALL_TYPE_IDLE, (int) result.mResult);
-
- mListener.onSrvccStateChanged(TelephonyManager.SRVCC_STATE_HANDOVER_STARTED);
- msg = mTestLooper.nextMessage();
- assertNull(msg);
- }
-
- @Test
- public void isIdleState() {
- mListener.isIdleState();
- }
-
- @Test
- public void setEcnoSignalThreshold() throws InterruptedException {
- mLatch = new CountDownLatch(1);
- int[] ecnoThresholds = new int[] {-85, -90, -95};
- mListener.setEcnoSignalThreshold(ecnoThresholds);
- assertTrue(mLatch.await(100, TimeUnit.MILLISECONDS));
- assertNotNull(mThresholds);
- assertArrayEquals(ecnoThresholds, mThresholds);
- }
-}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/CellularQualityMonitorTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/CellularQualityMonitorTest.java
index 6ab2566..e2fbb5b 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/CellularQualityMonitorTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/CellularQualityMonitorTest.java
@@ -99,7 +99,10 @@
MockitoAnnotations.initMocks(this);
super.setUp();
mCellularQualityMonitor =
- new CellularQualityMonitor(sMockContext, mMockQnsTelephonyListener, mSlotIndex);
+ new CellularQualityMonitor(sMockContext,
+ mMockQnsConfigManager,
+ mMockQnsTelephonyListener,
+ mSlotIndex);
mLatch = new CountDownLatch(1);
mThresholdListener = new ThresholdListener(mExecutor);
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsCallStatusTrackerTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsCallStatusTrackerTest.java
index 9dea914..a9247f0 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsCallStatusTrackerTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsCallStatusTrackerTest.java
@@ -24,6 +24,10 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
@@ -53,8 +57,10 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
@RunWith(JUnit4.class)
@@ -69,6 +75,8 @@
private Handler mLowQualityHandler;
private MockitoSession mMockSession;
List<CallState> mTestCallStateList = new ArrayList<>();
+ int mId = 0;
+ HashMap<Integer, Message> mMessageHashMap = new HashMap<>();
@Before
public void setUp() throws Exception {
@@ -82,8 +90,27 @@
mImsHandler = new Handler(mTestLooperListener.getLooper());
mEmergencyHandler = new Handler(mTestLooperListener.getLooper());
mLowQualityHandler = new Handler(mLowQualityListenerLooper.getLooper());
+ mMessageHashMap = new HashMap<>();
+ when(mMockQnsTimer.registerTimer(isA(Message.class), anyLong())).thenAnswer(
+ (Answer<Integer>) invocation -> {
+ Message msg = (Message) invocation.getArguments()[0];
+ long delay = (long) invocation.getArguments()[1];
+ msg.getTarget().sendMessageDelayed(msg, delay);
+ mMessageHashMap.put(++mId, msg);
+ return mId;
+ });
+
+ doAnswer(invocation -> {
+ int timerId = (int) invocation.getArguments()[0];
+ Message msg = mMessageHashMap.get(timerId);
+ if (msg != null && msg.getTarget() != null) {
+ msg.getTarget().removeMessages(msg.what, msg.obj);
+ }
+ return null;
+ }).when(mMockQnsTimer).unregisterTimer(anyInt());
mCallTracker = new QnsCallStatusTracker(
- mMockQnsTelephonyListener, mMockQnsConfigManager, 0, mTestLooper.getLooper());
+ mMockQnsTelephonyListener, mMockQnsConfigManager, mMockQnsTimer, 0,
+ mTestLooper.getLooper());
mCallTracker.registerCallTypeChangedListener(
NetworkCapabilities.NET_CAPABILITY_IMS, mImsHandler, 1, null);
mCallTracker.registerCallTypeChangedListener(
@@ -130,6 +157,8 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_VOICE, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle());
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
// Test2:
mTestCallStateList.clear();
@@ -149,7 +178,9 @@
result = (QnsAsyncResult) msg.obj;
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_IDLE, (int) result.mResult);
- assertTrue(mCallTracker.isCallIdle()); // for IMS calls only
+ assertTrue(mCallTracker.isCallIdle());
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
}
@Test
@@ -166,6 +197,9 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_VOICE, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle());
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_MMS));
mTestCallStateList.clear();
mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
@@ -181,7 +215,8 @@
new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING)
.setImsCallType(ImsCallProfile.CALL_TYPE_VOICE)
.setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NORMAL).build());
- mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
+ mTestCallStateList.add(
+ new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
.setImsCallType(ImsCallProfile.CALL_TYPE_VOICE)
.setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_EMERGENCY).build());
mCallTracker.updateCallState(mTestCallStateList);
@@ -192,6 +227,8 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_EMERGENCY, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle());
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
mTestCallStateList.clear();
mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
@@ -205,6 +242,8 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_IDLE, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle());
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
mTestCallStateList.clear();
mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ALERTING)
@@ -224,6 +263,8 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_VOICE, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle());
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
}
@Test
@@ -241,6 +282,8 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_VOICE, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle()); // for IMS calls only
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
mTestCallStateList.clear();
mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
@@ -256,6 +299,8 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_VIDEO, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle()); // for IMS calls only
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
mTestCallStateList.clear();
mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
@@ -268,6 +313,8 @@
msg = mTestLooperListener.nextMessage();
assertNull(msg);
assertFalse(mCallTracker.isCallIdle()); // for IMS calls only
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
mTestCallStateList.clear();
mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_HOLDING)
@@ -281,6 +328,8 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_VOICE, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle());
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
mTestCallStateList.clear();
mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
@@ -319,12 +368,16 @@
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_IDLE, (int) result.mResult);
assertFalse(mCallTracker.isCallIdle());
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
mTestCallStateList.clear();
mCallTracker.updateCallState(mTestCallStateList);
msg = mTestLooperListener.nextMessage();
assertNull(msg);
assertTrue(mCallTracker.isCallIdle());
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
}
@Test
@@ -406,6 +459,8 @@
QnsAsyncResult result = (QnsAsyncResult) msg.obj;
assertNotNull(result.mResult);
assertEquals(QnsConstants.CALL_TYPE_EMERGENCY, (int) result.mResult);
+ assertFalse(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_IMS));
+ assertTrue(mCallTracker.isCallIdle(NetworkCapabilities.NET_CAPABILITY_EIMS));
// Test2:
mTestCallStateList.clear();
@@ -417,6 +472,27 @@
// Should not notify if call type is not changed
assertNull(msg);
+ mTestCallStateList.clear();
+ mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
+ .setImsCallType(ImsCallProfile.CALL_TYPE_VOICE)
+ .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_EMERGENCY).build());
+ mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_WAITING)
+ .setImsCallType(ImsCallProfile.CALL_TYPE_VOICE)
+ .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NORMAL).build());
+ mCallTracker.updateCallState(mTestCallStateList);
+ msg = mTestLooperListener.nextMessage();
+ // Should not notify if call type is not changed
+ assertNull(msg);
+
+ mTestCallStateList.clear();
+ mTestCallStateList.add(new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE)
+ .setImsCallType(ImsCallProfile.CALL_TYPE_VOICE)
+ .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_EMERGENCY).build());
+ mCallTracker.updateCallState(mTestCallStateList);
+ msg = mTestLooperListener.nextMessage();
+ // Should not notify if call type is not changed
+ assertNull(msg);
+
// Test3:
imsDataStatus =
new PreciseDataConnectionState.Builder()
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsCarrierConfigManagerTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsCarrierConfigManagerTest.java
index fb3bd67..f39ea40 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsCarrierConfigManagerTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsCarrierConfigManagerTest.java
@@ -16,16 +16,16 @@
package com.android.telephony.qns;
-import static android.hardware.radio.network.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP;
import static android.hardware.radio.network.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ;
import static android.hardware.radio.network.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI;
import static android.hardware.radio.network.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR;
-import static android.hardware.radio.network.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP;
import static android.hardware.radio.network.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ;
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
+import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP;
import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP;
+import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP;
import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR;
import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_UNKNOWN;
@@ -467,6 +467,90 @@
}
@Test
+ public void testGetWwanHysteresisDbLevelWithTestbundle() {
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {"eutran:rsrp:1"});
+ mConfigManager.loadQnsAneSupportConfigurations(bundle, null);
+ Assert.assertEquals(
+ 1,
+ mConfigManager.getWwanHysteresisDbLevel(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ SIGNAL_MEASUREMENT_TYPE_RSRP));
+
+ bundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {"ngran:ssrsrp:2"});
+ mConfigManager.loadQnsAneSupportConfigurations(bundle, null);
+ Assert.assertEquals(
+ 2,
+ mConfigManager.getWwanHysteresisDbLevel(
+ AccessNetworkConstants.AccessNetworkType.NGRAN,
+ SIGNAL_MEASUREMENT_TYPE_SSRSRP));
+
+ bundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {"eutran:rsrp:-5"});
+ mConfigManager.loadQnsAneSupportConfigurations(bundle, null);
+ Assert.assertEquals(
+ QnsConstants.KEY_DEFAULT_VALUE,
+ mConfigManager.getWwanHysteresisDbLevel(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ SIGNAL_MEASUREMENT_TYPE_RSRP));
+
+ bundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {"utran:rscp:5"});
+ mConfigManager.loadQnsAneSupportConfigurations(bundle, null);
+ Assert.assertEquals(
+ 5,
+ mConfigManager.getWwanHysteresisDbLevel(
+ AccessNetworkConstants.AccessNetworkType.UTRAN,
+ SIGNAL_MEASUREMENT_TYPE_RSCP));
+
+ bundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {"eutran::-2"});
+ mConfigManager.loadQnsAneSupportConfigurations(bundle, null);
+ Assert.assertEquals(
+ QnsConstants.KEY_DEFAULT_VALUE,
+ mConfigManager.getWwanHysteresisDbLevel(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ SIGNAL_MEASUREMENT_TYPE_RSRP));
+
+ bundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {":rsrp:-2"});
+ mConfigManager.loadQnsAneSupportConfigurations(bundle, null);
+ Assert.assertEquals(
+ QnsConstants.KEY_DEFAULT_VALUE,
+ mConfigManager.getWwanHysteresisDbLevel(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ SIGNAL_MEASUREMENT_TYPE_RSRP));
+
+ bundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {""});
+ mConfigManager.loadQnsAneSupportConfigurations(bundle, null);
+ Assert.assertEquals(
+ QnsConstants.KEY_DEFAULT_VALUE,
+ mConfigManager.getWwanHysteresisDbLevel(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ SIGNAL_MEASUREMENT_TYPE_RSRP));
+
+ bundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {":"});
+ mConfigManager.loadQnsAneSupportConfigurations(bundle, null);
+ Assert.assertEquals(
+ QnsConstants.KEY_DEFAULT_VALUE,
+ mConfigManager.getWwanHysteresisDbLevel(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ SIGNAL_MEASUREMENT_TYPE_RSRP));
+ }
+
+ @Test
public void testGetQnsSupportedNetCapabilitiesWithDefaultValues() {
List<Integer> imsNetCapability = new ArrayList<>();
imsNetCapability.add(NetworkCapabilities.NET_CAPABILITY_IMS);
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsComponentsTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsComponentsTest.java
index 9924331..73a5249 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsComponentsTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsComponentsTest.java
@@ -42,7 +42,6 @@
assertNull(qnsComponents.getQnsTelephonyListener(slotId));
assertNull(qnsComponents.getQnsImsManager(slotId));
- assertNull(qnsComponents.getAlternativeEventListener(slotId));
assertNull(qnsComponents.getCellularNetworkStatusTracker(slotId));
assertNull(qnsComponents.getCellularQualityMonitor(slotId));
assertNull(qnsComponents.getQnsProvisioningListener(slotId));
@@ -52,12 +51,12 @@
assertNull(qnsComponents.getWifiBackhaulMonitor(slotId));
assertNull(qnsComponents.getWifiQualityMonitor());
assertNull(qnsComponents.getIwlanNetworkStatusTracker());
+ assertNull(qnsComponents.getQnsTimer());
qnsComponents.createQnsComponents(slotId);
assertNotNull(qnsComponents.getQnsTelephonyListener(slotId));
assertNotNull(qnsComponents.getQnsImsManager(slotId));
- assertNotNull(qnsComponents.getAlternativeEventListener(slotId));
assertNotNull(qnsComponents.getCellularNetworkStatusTracker(slotId));
assertNotNull(qnsComponents.getCellularQualityMonitor(slotId));
assertNotNull(qnsComponents.getQnsProvisioningListener(slotId));
@@ -67,6 +66,7 @@
assertNotNull(qnsComponents.getWifiBackhaulMonitor(slotId));
assertNotNull(qnsComponents.getWifiQualityMonitor());
assertNotNull(qnsComponents.getIwlanNetworkStatusTracker());
+ assertNotNull(qnsComponents.getQnsTimer());
}
@@ -75,7 +75,6 @@
int slotId = 0;
QnsComponents qnsComponents = new QnsComponents(
sMockContext,
- mMockAltEventListener,
mMockCellNetStatusTracker,
mMockCellularQm,
mMockIwlanNetworkStatusTracker,
@@ -85,13 +84,14 @@
mMockQnsProvisioningListener,
mMockQnsTelephonyListener,
mMockQnsCallStatusTracker,
+ mMockQnsTimer,
mMockWifiBm,
mMockWifiQm,
+ mMockQnsMetrics,
slotId);
assertNotNull(qnsComponents.getQnsTelephonyListener(slotId));
assertNotNull(qnsComponents.getQnsImsManager(slotId));
- assertNotNull(qnsComponents.getAlternativeEventListener(slotId));
assertNotNull(qnsComponents.getCellularNetworkStatusTracker(slotId));
assertNotNull(qnsComponents.getCellularQualityMonitor(slotId));
assertNotNull(qnsComponents.getQnsProvisioningListener(slotId));
@@ -101,12 +101,13 @@
assertNotNull(qnsComponents.getWifiBackhaulMonitor(slotId));
assertNotNull(qnsComponents.getWifiQualityMonitor());
assertNotNull(qnsComponents.getIwlanNetworkStatusTracker());
+ assertNotNull(qnsComponents.getQnsTimer());
+ assertNotNull(qnsComponents.getQnsMetrics());
qnsComponents.closeComponents(slotId);
assertNull(qnsComponents.getQnsTelephonyListener(slotId));
assertNull(qnsComponents.getQnsImsManager(slotId));
- assertNull(qnsComponents.getAlternativeEventListener(slotId));
assertNull(qnsComponents.getCellularNetworkStatusTracker(slotId));
assertNull(qnsComponents.getCellularQualityMonitor(slotId));
assertNull(qnsComponents.getQnsProvisioningListener(slotId));
@@ -116,10 +117,11 @@
assertNull(qnsComponents.getWifiBackhaulMonitor(slotId));
assertNull(qnsComponents.getWifiQualityMonitor());
assertNull(qnsComponents.getIwlanNetworkStatusTracker());
+ assertNull(qnsComponents.getQnsTimer());
+ assertNull(qnsComponents.getQnsMetrics());
verify(mMockQnsTelephonyListener).close();
verify(mMockQnsImsManager).close();
- verify(mMockAltEventListener).close();
verify(mMockCellNetStatusTracker).close();
verify(mMockCellularQm).close();
verify(mMockQnsProvisioningListener).close();
@@ -129,5 +131,7 @@
verify(mMockWifiBm).close();
verify(mMockWifiQm).close();
verify(mMockIwlanNetworkStatusTracker).close();
+ verify(mMockQnsTimer).close();
+ verify(mMockQnsMetrics).close();
}
}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsMetricsTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsMetricsTest.java
new file mode 100644
index 0000000..e7d1d6f
--- /dev/null
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsMetricsTest.java
@@ -0,0 +1,773 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.net.NetworkCapabilities;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.qns.QnsProtoEnums;
+
+import com.android.telephony.qns.DataConnectionStatusTracker.DataConnectionChangedInfo;
+import com.android.telephony.qns.QualifiedNetworksServiceImpl.QualifiedNetworksInfo;
+import com.android.telephony.qns.atoms.AtomsQnsFallbackRestrictionChangedInfo;
+import com.android.telephony.qns.atoms.AtomsQnsHandoverPingPongInfo;
+import com.android.telephony.qns.atoms.AtomsQnsHandoverTimeMillisInfo;
+import com.android.telephony.qns.atoms.AtomsQnsImsCallDropStats;
+import com.android.telephony.qns.atoms.AtomsQnsRatPreferenceMismatchInfo;
+import com.android.telephony.qns.atoms.AtomsQualifiedRatListChangedInfo;
+import com.android.telephony.statslib.AtomsPulled;
+import com.android.telephony.statslib.AtomsPushed;
+import com.android.telephony.statslib.StatsLib;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class QnsMetricsTest extends QnsTest {
+ private static final int DEFAULT_CARRIER_ID = 1;
+
+ private final int mSlotId = 0;
+ private final int mNetCapability = NetworkCapabilities.NET_CAPABILITY_IMS;
+
+ @Mock private StatsLib mMockStatsLib;
+ @Mock private RestrictManager mMockRestrictManager;
+ @Mock private QualityMonitor mMockCellularQualityMonitor;
+ @Mock private QualityMonitor mMockWifiQualityMonitor;
+
+ private MockitoSession mStaticMockSession;
+ private QnsMetrics mQnsMetrics;
+ private long mSystemElapsedRealTime;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mStaticMockSession = mockitoSession().mockStatic(QnsUtils.class).startMocking();
+
+ mSystemElapsedRealTime = 0L;
+ lenient()
+ .when(QnsUtils.getSystemElapsedRealTime())
+ .thenAnswer((Answer<Long>) invocation -> mSystemElapsedRealTime);
+
+ mQnsMetrics = new QnsMetrics(mMockStatsLib);
+ }
+
+ @After
+ public void cleanUp() {
+ mStaticMockSession.finishMocking();
+ }
+
+ private void spendSystemTime(long appendElapsedTime) {
+ mSystemElapsedRealTime += appendElapsedTime;
+ }
+
+ private void sendDataConnectionMessage(int event, int state, int transportType) {
+ DataConnectionChangedInfo info = new DataConnectionChangedInfo(event, state, transportType);
+ mQnsMetrics.log("QnsMetricsTest currentTime:" + mSystemElapsedRealTime + "ms " + info);
+ mQnsMetrics.reportAtomForDataConnectionChanged(
+ mNetCapability, mSlotId, info, DEFAULT_CARRIER_ID);
+ waitForLastHandlerAction(mQnsMetrics.getHandler());
+ }
+
+ private void sendQualifiedNetworksMessage(int accessNetworkType) {
+
+ List<Integer> list = new ArrayList<>();
+ list.add(accessNetworkType);
+
+ sendQualifiedNetworksMessage(
+ list,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ QnsConstants.COVERAGE_HOME,
+ true,
+ false,
+ QnsConstants.CELL_PREF,
+ QnsConstants.WIFI_PREF,
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ true,
+ false,
+ mMockRestrictManager,
+ mMockCellularQualityMonitor,
+ mMockWifiQualityMonitor,
+ QnsConstants.CALL_TYPE_IDLE);
+ }
+
+ private void sendQualifiedNetworksMessage(
+ List<Integer> accessNetworkTypes,
+ int dataConnectionCurrentTransportType,
+ int coverage,
+ boolean settingWfcEnabled,
+ boolean settingWfcRoamingEnabled,
+ int settingWfcMode,
+ int settingWfcRoamingMode,
+ int cellularAccessNetworkType,
+ boolean iwlanAvailable,
+ boolean isCrossWfc,
+ RestrictManager restrictManager,
+ QualityMonitor cellularQualityMonitor,
+ QualityMonitor wifiQualityMonitor,
+ int callType) {
+ QualifiedNetworksInfo info = new QualifiedNetworksInfo(
+ NetworkCapabilities.NET_CAPABILITY_IMS, accessNetworkTypes);
+
+ mQnsMetrics.log("QnsMetricsTest currentTime:" + mSystemElapsedRealTime + "ms " + info);
+ mQnsMetrics.reportAtomForQualifiedNetworks(
+ info,
+ mSlotId,
+ dataConnectionCurrentTransportType,
+ coverage,
+ settingWfcEnabled,
+ settingWfcRoamingEnabled,
+ settingWfcMode,
+ settingWfcRoamingMode,
+ cellularAccessNetworkType,
+ iwlanAvailable,
+ isCrossWfc,
+ restrictManager,
+ cellularQualityMonitor,
+ wifiQualityMonitor,
+ callType);
+ waitForLastHandlerAction(mQnsMetrics.getHandler());
+ }
+
+ @Test
+ public void testAtomsQnsHandoverTimeMillisInfo() {
+
+ ArgumentCaptor<AtomsPulled> capturePulled = ArgumentCaptor.forClass(AtomsPulled.class);
+ ArgumentCaptor<AtomsPushed> capturePushed = ArgumentCaptor.forClass(AtomsPushed.class);
+
+ spendSystemTime(10000L);
+ sendQualifiedNetworksMessage(AccessNetworkConstants.AccessNetworkType.EUTRAN);
+
+ spendSystemTime(4010L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_STARTED,
+ DataConnectionStatusTracker.STATE_CONNECTING,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4020L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(501L);
+ sendQualifiedNetworksMessage(AccessNetworkConstants.AccessNetworkType.IWLAN);
+
+ spendSystemTime(4030L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4040L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(5002L);
+ sendQualifiedNetworksMessage(AccessNetworkConstants.AccessNetworkType.EUTRAN);
+
+ spendSystemTime(4050L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4060L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(50002L);
+ sendQualifiedNetworksMessage(AccessNetworkConstants.AccessNetworkType.IWLAN);
+
+ spendSystemTime(4070L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4080L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4090L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4100L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4110L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4120L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4130L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED,
+ DataConnectionStatusTracker.STATE_INACTIVE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ verify(mMockStatsLib, timeout(1000).times(4)).append(capturePulled.capture());
+ verify(mMockStatsLib, timeout(1000).times(4)).write(capturePushed.capture());
+ List<AtomsQnsHandoverTimeMillisInfo> listHandoverTime = new ArrayList<>();
+ List<AtomsQualifiedRatListChangedInfo> listQualifiedRat = new ArrayList<>();
+ for (AtomsPulled pulled : capturePulled.getAllValues()) {
+ if (pulled instanceof AtomsQnsHandoverTimeMillisInfo) {
+ listHandoverTime.add((AtomsQnsHandoverTimeMillisInfo) pulled);
+ mQnsMetrics.log("QnsMetricsTest HandoverTime atom:" + pulled);
+ }
+ }
+ for (AtomsPushed pushed : capturePushed.getAllValues()) {
+ if (pushed instanceof AtomsQualifiedRatListChangedInfo) {
+ listQualifiedRat.add((AtomsQualifiedRatListChangedInfo) pushed);
+ mQnsMetrics.log("QnsMetricsTest QualifiedRat atom:" + pushed);
+ }
+ }
+ assertEquals(3, listHandoverTime.size());
+ assertEquals(8070, listHandoverTime.get(0).getTimeForHoSuccess());
+ assertEquals(8110, listHandoverTime.get(1).getTimeForHoSuccess());
+ assertEquals(24570, listHandoverTime.get(2).getTimeForHoSuccess());
+
+ assertEquals(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ listQualifiedRat.get(0).getFirstQualifiedRat());
+ assertEquals(
+ AccessNetworkConstants.AccessNetworkType.IWLAN,
+ listQualifiedRat.get(1).getFirstQualifiedRat());
+ assertEquals(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ listQualifiedRat.get(2).getFirstQualifiedRat());
+ assertEquals(
+ AccessNetworkConstants.AccessNetworkType.IWLAN,
+ listQualifiedRat.get(3).getFirstQualifiedRat());
+ }
+
+ @Test
+ public void testAtomsQualifiedRatListChangedInfo() {
+
+ ArgumentCaptor<AtomsQualifiedRatListChangedInfo> capture =
+ ArgumentCaptor.forClass(AtomsQualifiedRatListChangedInfo.class);
+
+ doReturn(true)
+ .when(mMockRestrictManager)
+ .hasRestrictionType(anyInt(), eq(RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY));
+ doReturn(true)
+ .when(mMockRestrictManager)
+ .hasRestrictionType(
+ anyInt(), eq(RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL));
+ doReturn(true)
+ .when(mMockRestrictManager)
+ .hasRestrictionType(
+ anyInt(),
+ eq(RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL));
+
+ List<Integer> cellularAccessNetwork = new ArrayList<>();
+ cellularAccessNetwork.add(AccessNetworkConstants.AccessNetworkType.EUTRAN);
+ sendQualifiedNetworksMessage(
+ cellularAccessNetwork,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ QnsConstants.COVERAGE_HOME,
+ true,
+ false,
+ QnsConstants.CELL_PREF,
+ QnsConstants.WIFI_PREF,
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ false,
+ true,
+ mMockRestrictManager,
+ mMockCellularQualityMonitor,
+ mMockWifiQualityMonitor,
+ QnsConstants.CALL_TYPE_IDLE);
+
+ List<Integer> wifiAccessNetwork = new ArrayList<>();
+ wifiAccessNetwork.add(AccessNetworkConstants.AccessNetworkType.IWLAN);
+ sendQualifiedNetworksMessage(
+ wifiAccessNetwork,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
+ QnsConstants.COVERAGE_ROAM,
+ false,
+ true,
+ QnsConstants.WIFI_PREF,
+ QnsConstants.CELL_PREF,
+ AccessNetworkConstants.AccessNetworkType.NGRAN,
+ true,
+ false,
+ mMockRestrictManager,
+ mMockCellularQualityMonitor,
+ mMockWifiQualityMonitor,
+ QnsConstants.CALL_TYPE_VOICE);
+
+ verify(mMockStatsLib, timeout(1000).times(2)).write(capture.capture());
+ List<AtomsQualifiedRatListChangedInfo> list = capture.getAllValues();
+ mQnsMetrics.log("QnsMetricsTest QualifiedRat atom[0]:" + list.get(0));
+ mQnsMetrics.log("QnsMetricsTest QualifiedRat atom[1]:" + list.get(1));
+ assertEquals(
+ AccessNetworkConstants.AccessNetworkType.EUTRAN,
+ list.get(0).getFirstQualifiedRat());
+ assertEquals(
+ AccessNetworkConstants.AccessNetworkType.IWLAN, list.get(1).getFirstQualifiedRat());
+ int expectedRestriction =
+ QnsProtoEnums.RESTRICT_TYPE_RTP_LOW_QUALITY
+ | QnsProtoEnums.RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL
+ | QnsProtoEnums.RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL;
+ assertEquals(expectedRestriction, list.get(0).getRestrictionsOnWlan());
+ assertEquals(expectedRestriction, list.get(1).getRestrictionsOnWwan());
+ }
+
+ @Test
+ public void testAtomsQnsHandoverPingPongInfo() {
+
+ ArgumentCaptor<AtomsQnsHandoverPingPongInfo> capture =
+ ArgumentCaptor.forClass(AtomsQnsHandoverPingPongInfo.class);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_STARTED,
+ DataConnectionStatusTracker.STATE_CONNECTING,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(50000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED,
+ DataConnectionStatusTracker.STATE_INACTIVE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ verify(mMockStatsLib, timeout(1000).times(2)).append(capture.capture());
+ List<AtomsQnsHandoverPingPongInfo> list = capture.getAllValues();
+ mQnsMetrics.log("QnsMetricsTest PingPong atom[0]:" + list.get(0));
+ mQnsMetrics.log("QnsMetricsTest PingPong atom[1]:" + list.get(1));
+ assertEquals(2, list.get(0).getCountHandoverPingPong());
+ assertEquals(1, list.get(1).getCountHandoverPingPong());
+ }
+
+ @Test
+ public void testAtomsQnsRatPreferenceMismatchInfo() {
+
+ ArgumentCaptor<AtomsQnsRatPreferenceMismatchInfo> capture =
+ ArgumentCaptor.forClass(AtomsQnsRatPreferenceMismatchInfo.class);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_STARTED,
+ DataConnectionStatusTracker.STATE_CONNECTING,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4100L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4200L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED,
+ DataConnectionStatusTracker.STATE_INACTIVE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(50000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_STARTED,
+ DataConnectionStatusTracker.STATE_CONNECTING,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_SUCCESS,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4100L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4200L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_STARTED,
+ DataConnectionStatusTracker.STATE_HANDOVER,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4300L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_HANDOVER_FAILED,
+ DataConnectionStatusTracker.STATE_CONNECTED,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ spendSystemTime(4000L);
+ sendDataConnectionMessage(
+ DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED,
+ DataConnectionStatusTracker.STATE_INACTIVE,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ verify(mMockStatsLib, timeout(1000).times(2)).append(capture.capture());
+ List<AtomsQnsRatPreferenceMismatchInfo> list = capture.getAllValues();
+ mQnsMetrics.log("QnsMetricsTest RatMismatch atom[0]:" + list.get(0));
+ mQnsMetrics.log("QnsMetricsTest RatMismatch atom[1]:" + list.get(1));
+ assertEquals(2, list.get(0).getHandoverFailCount());
+ assertEquals(3, list.get(1).getHandoverFailCount());
+ assertEquals(20300, list.get(0).getDurationOfMismatch());
+ assertEquals(24600, list.get(1).getDurationOfMismatch());
+ }
+
+ private void sendCallTypeChanged(
+ int oldCallType,
+ int newCallType,
+ RestrictManager restrictManager,
+ int transportTypeOfCall) {
+ mQnsMetrics.log(
+ "QnsMetricsTest callTypeChanged "
+ + QnsConstants.callTypeToString(oldCallType)
+ + "->"
+ + QnsConstants.callTypeToString(newCallType)
+ + " transportType:"
+ + AccessNetworkConstants.transportTypeToString(transportTypeOfCall));
+ mQnsMetrics.reportAtomForCallTypeChanged(mNetCapability, mSlotId,
+ oldCallType, newCallType, restrictManager, transportTypeOfCall);
+ waitForLastHandlerAction(mQnsMetrics.getHandler());
+ }
+
+ private void sendImsCallDropStats(int transportTypeOfCall, int cellularAccessNetworkType) {
+ mQnsMetrics.log(
+ "QnsMetricsTest ImsCallDropStats transportTypeOfCall:"
+ + AccessNetworkConstants.transportTypeToString(transportTypeOfCall)
+ + " cellularAccessNetworkType:"
+ + AccessNetworkConstants.AccessNetworkType.toString(
+ cellularAccessNetworkType));
+ mQnsMetrics.reportAtomForImsCallDropStats(mNetCapability, mSlotId, mMockRestrictManager,
+ mMockCellularQualityMonitor, mMockWifiQualityMonitor, transportTypeOfCall,
+ cellularAccessNetworkType);
+ waitForLastHandlerAction(mQnsMetrics.getHandler());
+ }
+ private void sendFallbackRestrictionChanged(
+ List<Integer> wlanRestrictions, List<Integer> wwanRestrictions) {
+ mQnsMetrics.log(
+ "QnsMetricsTest FallbackRestrictionChanged wlanRestrictions:"
+ + wlanRestrictions
+ + ", wwanRestrictions:"
+ + wwanRestrictions);
+ mQnsMetrics.reportAtomForRestrictions(
+ mNetCapability, mSlotId, wlanRestrictions, wwanRestrictions, DEFAULT_CARRIER_ID);
+ waitForLastHandlerAction(mQnsMetrics.getHandler());
+ }
+
+ @Test
+ public void testAtomsQnsImsCallDropStats() {
+
+ ArgumentCaptor<AtomsQnsImsCallDropStats> capture =
+ ArgumentCaptor.forClass(AtomsQnsImsCallDropStats.class);
+
+ // call start
+ sendCallTypeChanged(
+ QnsConstants.CALL_TYPE_IDLE,
+ QnsConstants.CALL_TYPE_VOICE,
+ mMockRestrictManager,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ // got rtp low from wwan side
+ spendSystemTime(10000L);
+ doReturn(true)
+ .when(mMockRestrictManager)
+ .hasRestrictionType(
+ eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN),
+ eq(RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY));
+
+ // call end
+ spendSystemTime(3000L);
+ sendCallTypeChanged(
+ QnsConstants.CALL_TYPE_VOICE,
+ QnsConstants.CALL_TYPE_IDLE,
+ mMockRestrictManager,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ // media no data cause.
+ spendSystemTime(3000L);
+ sendImsCallDropStats(
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ AccessNetworkConstants.AccessNetworkType.EUTRAN);
+
+ // call start over iwlan
+ spendSystemTime(10000L);
+ sendCallTypeChanged(
+ QnsConstants.CALL_TYPE_IDLE,
+ QnsConstants.CALL_TYPE_VOICE,
+ mMockRestrictManager,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ // got rtp low from wlan side
+ spendSystemTime(10000L);
+ doReturn(true)
+ .when(mMockRestrictManager)
+ .hasRestrictionType(
+ eq(AccessNetworkConstants.TRANSPORT_TYPE_WLAN),
+ eq(RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY));
+
+ // call end
+ spendSystemTime(3000L);
+ sendCallTypeChanged(
+ QnsConstants.CALL_TYPE_VOICE,
+ QnsConstants.CALL_TYPE_IDLE,
+ mMockRestrictManager,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+
+ // media no data cause
+ spendSystemTime(3000L);
+ sendImsCallDropStats(
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
+ AccessNetworkConstants.AccessNetworkType.IWLAN);
+
+ // verify
+ verify(mMockStatsLib, timeout(1000).times(2)).write(capture.capture());
+ List<AtomsQnsImsCallDropStats> list = capture.getAllValues();
+ mQnsMetrics.log("QnsMetricsTest ImsCallDrop atom[0]:" + list.get(0));
+ mQnsMetrics.log("QnsMetricsTest ImsCallDrop atom[1]:" + list.get(1));
+ assertTrue(list.get(0).getRtpThresholdBreached());
+ assertTrue(list.get(1).getRtpThresholdBreached());
+ }
+
+
+ @Test
+ public void testAtomsQnsFallbackRestrictionChangedInfo() {
+
+ ArgumentCaptor<AtomsQnsFallbackRestrictionChangedInfo> capture =
+ ArgumentCaptor.forClass(AtomsQnsFallbackRestrictionChangedInfo.class);
+
+ List<Integer> wlanRestrictions = new ArrayList<>();
+ List<Integer> wwanRestrictions = new ArrayList<>();
+ sendFallbackRestrictionChanged(wlanRestrictions, wwanRestrictions);
+
+ wlanRestrictions.add(RestrictManager.RESTRICT_TYPE_GUARDING);
+ wwanRestrictions.add(RestrictManager.RESTRICT_TYPE_GUARDING);
+ sendFallbackRestrictionChanged(wlanRestrictions, wwanRestrictions);
+
+ wlanRestrictions.clear();
+ wwanRestrictions.clear();
+ wlanRestrictions.add(RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY);
+ sendFallbackRestrictionChanged(wlanRestrictions, wwanRestrictions);
+
+ wlanRestrictions.clear();
+ wwanRestrictions.clear();
+ wwanRestrictions.add(RestrictManager.RESTRICT_TYPE_RTP_LOW_QUALITY);
+ sendFallbackRestrictionChanged(wlanRestrictions, wwanRestrictions);
+
+ wlanRestrictions.clear();
+ wwanRestrictions.clear();
+ wlanRestrictions.add(RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL);
+ sendFallbackRestrictionChanged(wlanRestrictions, wwanRestrictions);
+
+ wlanRestrictions.clear();
+ wwanRestrictions.clear();
+ wwanRestrictions.add(RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_IMS_REGI_FAIL);
+ sendFallbackRestrictionChanged(wlanRestrictions, wwanRestrictions);
+
+ wlanRestrictions.clear();
+ wwanRestrictions.clear();
+ wlanRestrictions.add(RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL);
+ sendFallbackRestrictionChanged(wlanRestrictions, wwanRestrictions);
+
+ wlanRestrictions.clear();
+ wwanRestrictions.clear();
+ wwanRestrictions.add(RestrictManager.RESTRICT_TYPE_FALLBACK_TO_WWAN_RTT_BACKHAUL_FAIL);
+ sendFallbackRestrictionChanged(wlanRestrictions, wwanRestrictions);
+
+ // verify
+ verify(mMockStatsLib, timeout(1000).times(4)).write(capture.capture());
+ List<AtomsQnsFallbackRestrictionChangedInfo> list = capture.getAllValues();
+ mQnsMetrics.log("QnsMetricsTest ImsCallDrop atom[0]:" + list.get(0));
+ mQnsMetrics.log("QnsMetricsTest ImsCallDrop atom[1]:" + list.get(1));
+ mQnsMetrics.log("QnsMetricsTest ImsCallDrop atom[2]:" + list.get(2));
+ mQnsMetrics.log("QnsMetricsTest ImsCallDrop atom[3]:" + list.get(3));
+ assertTrue(list.get(0).getRestrictionOnWlanByRtpThresholdBreached());
+ assertTrue(list.get(1).getRestrictionOnWwanByRtpThresholdBreached());
+ assertTrue(list.get(2).getRestrictionOnWlanByImsRegistrationFailed());
+ assertTrue(list.get(3).getRestrictionOnWlanByWifiBackhaulProblem());
+ }
+}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTelephonyListenerTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTelephonyListenerTest.java
index f1d63fa..2f50ff8 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTelephonyListenerTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTelephonyListenerTest.java
@@ -47,6 +47,7 @@
import android.telephony.VopsSupportInfo;
import android.telephony.data.ApnSetting;
import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
import android.util.SparseArray;
@@ -1035,6 +1036,20 @@
}
@Test
+ public void testOnImsCallDisconnectCauseChanged() {
+ mQtListener.registerImsCallDropDisconnectCauseListener(mMockHandler, 0, null);
+ assertTrue(mQtListener.mImsCallDropDisconnectCauseListener.size() > 0);
+ verify(mMockHandler, never()).sendMessage(any());
+
+ ImsReasonInfo imsReasonInfo = new ImsReasonInfo();
+ mQtListener.onImsCallDisconnectCauseChanged(imsReasonInfo);
+ verify(mMockHandler, times(1)).sendMessage(any());
+
+ mQtListener.unregisterImsCallDropDisconnectCauseListener(mMockHandler);
+ assertEquals(0, mQtListener.mImsCallDropDisconnectCauseListener.size());
+ }
+
+ @Test
public void testNullTelephonyListener() {
mQtListener.close();
setReady(false);
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTest.java
index 2144516..0dff376 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTest.java
@@ -32,6 +32,7 @@
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
+import android.os.PowerManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -69,11 +70,11 @@
@Mock protected Resources mMockResources;
// qns mocks
- @Mock AlternativeEventListener mMockAltEventListener;
@Mock protected IwlanNetworkStatusTracker mMockIwlanNetworkStatusTracker;
@Mock protected WifiQualityMonitor mMockWifiQm;
@Mock protected CellularNetworkStatusTracker mMockCellNetStatusTracker;
@Mock protected CellularQualityMonitor mMockCellularQm;
+ @Mock protected PowerManager mMockPowerManager;
@Mock protected QnsImsManager mMockQnsImsManager;
@Mock protected QnsCarrierConfigManager mMockQnsConfigManager;
@Mock protected QnsEventDispatcher mMockQnsEventDispatcher;
@@ -81,6 +82,8 @@
@Mock protected QnsTelephonyListener mMockQnsTelephonyListener;
@Mock protected QnsCallStatusTracker mMockQnsCallStatusTracker;
@Mock protected WifiBackhaulMonitor mMockWifiBm;
+ @Mock protected QnsTimer mMockQnsTimer;
+ @Mock protected QnsMetrics mMockQnsMetrics;
protected QnsComponents[] mQnsComponents = new QnsComponents[2];
@@ -100,7 +103,6 @@
mQnsComponents[0] =
new QnsComponents(
sMockContext,
- mMockAltEventListener,
mMockCellNetStatusTracker,
mMockCellularQm,
mMockIwlanNetworkStatusTracker,
@@ -110,14 +112,15 @@
mMockQnsProvisioningListener,
mMockQnsTelephonyListener,
mMockQnsCallStatusTracker,
+ mMockQnsTimer,
mMockWifiBm,
mMockWifiQm,
+ mMockQnsMetrics,
0);
mQnsComponents[1] =
new QnsComponents(
sMockContext,
- mMockAltEventListener,
mMockCellNetStatusTracker,
mMockCellularQm,
mMockIwlanNetworkStatusTracker,
@@ -127,8 +130,10 @@
mMockQnsProvisioningListener,
mMockQnsTelephonyListener,
mMockQnsCallStatusTracker,
+ mMockQnsTimer,
mMockWifiBm,
mMockWifiQm,
+ mMockQnsMetrics,
1);
}
@@ -144,7 +149,7 @@
when(sMockContext.getSystemService(ImsManager.class)).thenReturn(mMockImsManager);
when(sMockContext.getSystemService(WifiManager.class)).thenReturn(mMockWifiManager);
when(sMockContext.getSystemService(CountryDetector.class)).thenReturn(mMockCountryDetector);
-
+ when(sMockContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager);
when(sMockContext.getResources()).thenReturn(mMockResources);
}
@@ -165,6 +170,7 @@
when(mMockCountryDetector.detectCountry())
.thenReturn(new Country("US", Country.COUNTRY_SOURCE_LOCATION));
+ when(mMockPowerManager.isDeviceIdleMode()).thenReturn(false);
}
private void stubOthers() {
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTimerTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTimerTest.java
new file mode 100644
index 0000000..50a36b5
--- /dev/null
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsTimerTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2023 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.telephony.qns;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.test.TestLooper;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.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 org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.CountDownLatch;
+
+@RunWith(AndroidJUnit4.class)
+public class QnsTimerTest extends QnsTest {
+
+ private static final int EVENT_QNS_TIMER_EXPIRED = 1;
+ static final String ACTION_ALARM_TIMER_EXPIRED =
+ "com.android.telephony.qns.action.ALARM_TIMER_EXPIRED";
+ static final String KEY_TIMER_ID = "key_timer_id";
+ @Mock private Context mContext;
+ @Mock private AlarmManager mAlarmManager;
+ @Mock private PowerManager mPowerManager;
+ @Mock Message mMessage;
+ private QnsTimer mQnsTimer;
+ private BroadcastReceiver mBroadcastReceiver;
+ int mTimerId;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
+ when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
+ mQnsTimer = new QnsTimer(mContext);
+ ArgumentCaptor<BroadcastReceiver> args = ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(args.capture(), isA(IntentFilter.class), anyInt());
+ mBroadcastReceiver = args.getValue();
+ }
+
+ @After
+ public void tearDown() {
+ mQnsTimer.close();
+ }
+
+ @Test
+ public void testRegisterTimerForScreenOff() {
+ mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ mTimerId = mQnsTimer.registerTimer(mMessage, 30000);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ assertTrue(mQnsTimer.getTimersInfo().contains(new QnsTimer.TimerInfo(mTimerId)));
+ assertTrue(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+ verify(mAlarmManager)
+ .setExactAndAllowWhileIdle(anyInt(), anyLong(), isA(PendingIntent.class));
+ }
+
+ @Test
+ public void testRegisterTimerForScreenOn() {
+ mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_ON));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ mTimerId = mQnsTimer.registerTimer(mMessage, 80000);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ assertTrue(mQnsTimer.getTimersInfo().contains(new QnsTimer.TimerInfo(mTimerId)));
+ assertTrue(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+ verify(mAlarmManager, never())
+ .setExactAndAllowWhileIdle(anyInt(), anyLong(), isA(PendingIntent.class));
+ }
+
+ @Test
+ public void testUnregisterForInvalidId() {
+ testRegisterTimerForScreenOn();
+ int timerInfoSize = mQnsTimer.getTimersInfo().size();
+ mQnsTimer.unregisterTimer(QnsConstants.INVALID_ID);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ assertEquals(timerInfoSize, mQnsTimer.getTimersInfo().size());
+ }
+
+ @Test
+ public void testUnregisterTimerForScreenOff() {
+ testRegisterTimerForScreenOff();
+ mQnsTimer.unregisterTimer(mTimerId);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ assertFalse(mQnsTimer.getTimersInfo().contains(new QnsTimer.TimerInfo(mTimerId)));
+ assertFalse(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+ verify(mAlarmManager).cancel(isA(PendingIntent.class));
+ }
+
+ @Test
+ public void testUnregisterTimerForScreenOn() {
+ testRegisterTimerForScreenOn();
+ mQnsTimer.unregisterTimer(mTimerId);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ assertFalse(mQnsTimer.getTimersInfo().contains(new QnsTimer.TimerInfo(mTimerId)));
+ assertFalse(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+ verify(mAlarmManager, never()).cancel(isA(PendingIntent.class));
+ }
+
+ @Test
+ public void testUpdateTimerTypeToAlarm() {
+ testRegisterTimerForScreenOn();
+
+ mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ verify(mAlarmManager)
+ .setExactAndAllowWhileIdle(anyInt(), anyLong(), isA(PendingIntent.class));
+ }
+
+ @Test
+ public void testTimerExpired() {
+ mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ mTimerId = mQnsTimer.registerTimer(mMessage, 50);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ assertTrue(mQnsTimer.getTimersInfo().contains(new QnsTimer.TimerInfo(mTimerId)));
+ assertTrue(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+ verify(mAlarmManager)
+ .setExactAndAllowWhileIdle(anyInt(), anyLong(), isA(PendingIntent.class));
+
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 40, 200);
+ mBroadcastReceiver.onReceive(mContext, new Intent(ACTION_ALARM_TIMER_EXPIRED));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ verify(mMessage).sendToTarget();
+ assertFalse(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+ verify(mAlarmManager).cancel(isA(PendingIntent.class));
+ }
+
+ @Test
+ public void testMultipleTimerRegistered() {
+ mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ TestLooper testLooper = new TestLooper();
+ Handler h = new Handler(testLooper.getLooper());
+
+ mQnsTimer.registerTimer(Message.obtain(h, 4), 300);
+ mQnsTimer.registerTimer(Message.obtain(h, 3), 200);
+ mQnsTimer.registerTimer(Message.obtain(h, 1), 50);
+ mQnsTimer.registerTimer(Message.obtain(h, 1), 50);
+ mQnsTimer.registerTimer(Message.obtain(h, 2), 100);
+ mQnsTimer.registerTimer(Message.obtain(h, 2), 100);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 320, 100);
+
+ // alarm timer should update for shortest delay and since the minimum timer value is 10
+ // secs for screen off condition, the alarm timer will not replace be replaced until new
+ // timer requested for less than 10 secs.
+ verify(mAlarmManager)
+ .setExactAndAllowWhileIdle(anyInt(), anyLong(), isA(PendingIntent.class));
+
+ // verify order of message received:
+ Message msg = testLooper.nextMessage();
+ assertEquals(1, msg.what);
+ msg = testLooper.nextMessage();
+ assertEquals(1, msg.what);
+ msg = testLooper.nextMessage();
+ assertEquals(2, msg.what);
+ msg = testLooper.nextMessage();
+ assertEquals(2, msg.what);
+ msg = testLooper.nextMessage();
+ assertEquals(3, msg.what);
+ msg = testLooper.nextMessage();
+ assertEquals(4, msg.what);
+ }
+
+ @Test
+ public void testCancelOngoingAlarm() {
+ mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ TestLooper testLooper = new TestLooper();
+ Handler h = new Handler(testLooper.getLooper());
+
+ int timerId1 = mQnsTimer.registerTimer(Message.obtain(h, 1), 61 * 1000);
+ int timerId2 = mQnsTimer.registerTimer(Message.obtain(h, 2), 1000);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+
+ assertEquals(2, mQnsTimer.getTimersInfo().size());
+ assertEquals(timerId2, mQnsTimer.getTimersInfo().peek().getTimerId());
+ assertTrue(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+ verify(mAlarmManager, times(2))
+ .setExactAndAllowWhileIdle(anyInt(), anyLong(), isA(PendingIntent.class));
+
+ mQnsTimer.unregisterTimer(timerId2);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ assertEquals(1, mQnsTimer.getTimersInfo().size());
+ assertEquals(timerId1, mQnsTimer.getTimersInfo().peek().getTimerId());
+ assertTrue(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+
+ verify(mAlarmManager, times(3))
+ .setExactAndAllowWhileIdle(anyInt(), anyLong(), isA(PendingIntent.class));
+ }
+
+ @Test
+ public void testAlarmOnLiteIdleModeMinDelay() {
+ int setDelay = 20000;
+ when(mPowerManager.isDeviceLightIdleMode()).thenReturn(true);
+ mBroadcastReceiver.onReceive(
+ sMockContext, new Intent(PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED));
+ long delay = setupAlarmForDelay(setDelay);
+
+ // assume 100ms as max delay in execution
+ assertTrue(delay < 30000 && delay > 30000 - 100);
+ }
+
+ @Test
+ public void testAlarmOnLiteIdleMode() {
+ int setDelay = 40000;
+ when(mPowerManager.isDeviceLightIdleMode()).thenReturn(true);
+ mBroadcastReceiver.onReceive(
+ sMockContext, new Intent(PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED));
+ long delay = setupAlarmForDelay(setDelay);
+
+ // assume 100ms as max delay in execution
+ assertTrue(delay < setDelay && delay > setDelay - 100);
+ }
+
+ @Test
+ public void testAlarmOnIdleModeMinDelay() {
+ int setDelay = 50000;
+ when(mPowerManager.isDeviceIdleMode()).thenReturn(true);
+ mBroadcastReceiver.onReceive(
+ sMockContext, new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
+ long delay = setupAlarmForDelay(setDelay);
+
+ // assume 100ms as max delay in execution
+ assertTrue(delay < 60000 && delay > 60000 - 100);
+ }
+
+ @Test
+ public void testAlarmOnIdleMode() {
+ int setDelay = 70000;
+ when(mPowerManager.isDeviceIdleMode()).thenReturn(true);
+ mBroadcastReceiver.onReceive(
+ sMockContext, new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
+ long delay = setupAlarmForDelay(setDelay);
+
+ // assume 100ms as max delay in execution
+ assertTrue(delay < setDelay && delay > setDelay - 100);
+ }
+
+ private long setupAlarmForDelay(int setDelay) {
+ mQnsTimer.registerTimer(mMessage, setDelay);
+
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ ArgumentCaptor<Long> capture = ArgumentCaptor.forClass(Long.class);
+ verify(mAlarmManager)
+ .setExactAndAllowWhileIdle(anyInt(), capture.capture(), isA(PendingIntent.class));
+ return capture.getValue() - SystemClock.elapsedRealtime();
+ }
+
+ @Test
+ public void testAlarmInCallActiveState() {
+ mQnsTimer.updateCallState(QnsConstants.CALL_TYPE_VOICE);
+ int setDelay = 4000;
+ when(mPowerManager.isDeviceIdleMode()).thenReturn(true);
+ mBroadcastReceiver.onReceive(
+ sMockContext, new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
+ long delay = setupAlarmForDelay(setDelay);
+
+ // assume 100ms as max delay in execution
+ assertTrue(delay < setDelay && delay > setDelay - 100);
+ }
+
+ @Test
+ public void testDeviceMovesToActiveState() {
+ int setDelay = 30000;
+ CountDownLatch latch = new CountDownLatch(2);
+ HandlerThread ht = new HandlerThread("");
+ ht.start();
+ Handler tempHandler = spy(new Handler(ht.getLooper()));
+ when(mPowerManager.isDeviceLightIdleMode()).thenReturn(true, false);
+ mBroadcastReceiver.onReceive(sMockContext, new Intent(Intent.ACTION_SCREEN_OFF));
+ mBroadcastReceiver.onReceive(
+ sMockContext, new Intent(PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED));
+ mQnsTimer.registerTimer(mMessage, setDelay);
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ verify(mAlarmManager)
+ .setExactAndAllowWhileIdle(anyInt(), anyLong(), isA(PendingIntent.class));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 5000);
+
+ mQnsTimer.mHandler = tempHandler;
+ mBroadcastReceiver.onReceive(
+ sMockContext, new Intent(PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED));
+ mBroadcastReceiver.onReceive(sMockContext, new Intent(Intent.ACTION_SCREEN_ON));
+ waitForDelayedHandlerAction(mQnsTimer.mHandler, 10, 200);
+ verify(mAlarmManager).cancel(isA(PendingIntent.class));
+
+ // Handler should reset for the updated delay
+ verify(tempHandler).removeMessages(EVENT_QNS_TIMER_EXPIRED);
+ verify(tempHandler).sendEmptyMessageDelayed(anyInt(), anyLong());
+ assertTrue(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
+ ht.quit();
+ }
+}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsUtilsTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsUtilsTest.java
index 7b1db18..7c68069 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsUtilsTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QnsUtilsTest.java
@@ -256,6 +256,8 @@
String[] defaultStringArray = new String[] {"LTE", "UMTS"};
String[] defaultGapOffsetStringArray =
new String[] {"eutran:rsrp:-5", "ngran:ssrsp:-2", "utran:rscp:-3"};
+ String[] defaultHysteresisDbLevelStringArray =
+ new String[] {"eutran:rsrp:1", "ngran:ssrsp:2", "utran:rscp:5"};
String[] defaultHandoverPolicyArray = new String[] {HANDOVER_POLICY_1, HANDOVER_POLICY_2};
String[] fallbackWwanRuleWithImsUnregistered =
new String[] {FALLBACK_RULE0, FALLBACK_RULE1};
@@ -515,6 +517,13 @@
QnsCarrierConfigManager
.KEY_QNS_ROVEIN_THRESHOLD_GAP_WITH_GUARD_TIMER_STRING_ARRAY));
assertArrayEquals(
+ defaultHysteresisDbLevelStringArray,
+ QnsUtils.getConfig(
+ mTestBundle,
+ null,
+ QnsCarrierConfigManager
+ .KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY));
+ assertArrayEquals(
defaultHandoverPolicyArray,
QnsUtils.getConfig(
mTestBundle,
@@ -662,6 +671,9 @@
mTestBundle.putStringArray(
QnsCarrierConfigManager.KEY_QNS_FALLBACK_ON_INITIAL_CONNECTION_FAILURE_STRING_ARRAY,
new String[] {"ims:2:30000:60000:5", "mms:1:10000:5000:2"});
+ mTestBundle.putStringArray(
+ QnsCarrierConfigManager.KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY,
+ new String[] {"eutran:rsrp:1", "ngran:ssrsp:2", "utran:rscp:5"});
}
@Test
@@ -1079,6 +1091,13 @@
null,
QnsCarrierConfigManager
.KEY_QNS_FALLBACK_ON_INITIAL_CONNECTION_FAILURE_STRING_ARRAY));
+ assertArrayEquals(
+ (String[]) null,
+ QnsUtils.getConfig(
+ null,
+ null,
+ QnsCarrierConfigManager
+ .KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY));
}
@Test
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QualifiedNetworksServiceImplTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QualifiedNetworksServiceImplTest.java
index 3a82244..9a1d559 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QualifiedNetworksServiceImplTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/QualifiedNetworksServiceImplTest.java
@@ -81,7 +81,6 @@
TestQnsComponents(int slotId) {
super(
sMockContext,
- mMockAltEventListener,
mMockCellNetStatusTracker,
mMockCellularQm,
mMockIwlanNetworkStatusTracker,
@@ -91,8 +90,10 @@
mMockQnsProvisioningListener,
mMockQnsTelephonyListener,
mMockQnsCallStatusTracker,
+ mMockQnsTimer,
mMockWifiBm,
mMockWifiQm,
+ mMockQnsMetrics,
slotId);
}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/RestrictManagerTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/RestrictManagerTest.java
index 466e687..ddc193a 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/RestrictManagerTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/RestrictManagerTest.java
@@ -46,7 +46,10 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
@@ -74,6 +77,11 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
+import org.mockito.stubbing.Answer;
+
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
@RunWith(JUnit4.class)
public class RestrictManagerTest extends QnsTest {
@@ -81,7 +89,6 @@
@Mock DataConnectionStatusTracker mMockDcst;
private MockitoSession mMockSession;
- private AlternativeEventListener mAltListener;
private QnsTelephonyListener mTelephonyListener;
private static final int DEFAULT_GUARDING_TIME = 30000;
@@ -91,15 +98,14 @@
private QnsImsManager mQnsImsManager;
protected TestLooper mTestLooper;
+ int mId = 0;
+ HashMap<Integer, Message> mMessageHashMap = new HashMap<>();
HandlerThread mHandlerThread =
new HandlerThread("") {
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
- mAltListener =
- new AlternativeEventListener(
- sMockContext, mMockQnsTelephonyListener, 0);
mTelephonyListener = new QnsTelephonyListener(sMockContext, 0);
mQnsImsManager = new QnsImsManager(sMockContext, 0);
setReady(true);
@@ -124,6 +130,24 @@
when(mMockQnsConfigManager.getWaitingTimerForPreferredTransportOnPowerOn(
AccessNetworkConstants.TRANSPORT_TYPE_WWAN))
.thenReturn(0);
+ when(mMockQnsTimer.registerTimer(isA(Message.class), anyLong())).thenAnswer(
+ (Answer<Integer>) invocation -> {
+ Message msg = (Message) invocation.getArguments()[0];
+ long delay = (long) invocation.getArguments()[1];
+ msg.getTarget().sendMessageDelayed(msg, delay);
+ mMessageHashMap.put(++mId, msg);
+ return mId;
+ });
+
+ doAnswer(invocation -> {
+ int timerId = (int) invocation.getArguments()[0];
+ Message msg = mMessageHashMap.get(timerId);
+ if (msg != null && msg.getTarget() != null) {
+ msg.getTarget().removeMessages(msg.what, msg.obj);
+ }
+ return null;
+ }).when(mMockQnsTimer).unregisterTimer(anyInt());
+
mTestLooper = new TestLooper();
mHandlerThread.start();
@@ -132,7 +156,6 @@
mQnsComponents[0] =
new QnsComponents(
sMockContext,
- mAltListener,
mMockCellNetStatusTracker,
mMockCellularQm,
mMockIwlanNetworkStatusTracker,
@@ -142,8 +165,10 @@
mMockQnsProvisioningListener,
mTelephonyListener,
mMockQnsCallStatusTracker,
+ mMockQnsTimer,
mMockWifiBm,
mMockWifiQm,
+ mMockQnsMetrics,
0);
mRestrictManager =
@@ -2790,4 +2815,29 @@
mRestrictManager.releaseRestriction(
AccessNetworkConstants.TRANSPORT_TYPE_WLAN, RESTRICT_TYPE_GUARDING, true);
}
+
+ @Test
+ public void testSendRestrictionsForMetrics() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+ Handler handler = new Handler(mHandlerThread.getLooper()) {
+ public void handleMessage(Message msg) {
+ latch.countDown();
+ }
+ };
+
+ mRestrictManager.registerRestrictInfoChanged(handler, 0);
+ assertNotNull(mRestrictManager.mRestrictInfoRegistrant);
+
+ mRestrictManager.addRestriction(
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
+ RESTRICT_TYPE_RTP_LOW_QUALITY,
+ sReleaseEventMap.get(RESTRICT_TYPE_NON_PREFERRED_TRANSPORT),
+ DEFAULT_RESTRICT_NON_PREFERRED_TRANSPORT_TIME);
+
+ assertTrue(latch.await(3, TimeUnit.SECONDS));
+
+ mRestrictManager.unRegisterRestrictInfoChanged(handler);
+ assertNull(mRestrictManager.mRestrictInfoRegistrant);
+ }
+
}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/WifiBackhaulMonitorTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/WifiBackhaulMonitorTest.java
index 3f81fb1..b05d3c1 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/WifiBackhaulMonitorTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/WifiBackhaulMonitorTest.java
@@ -17,9 +17,11 @@
package com.android.telephony.qns;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.telephony.qns.QnsConstants.INVALID_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyInt;
@@ -76,6 +78,7 @@
private StaticMockitoSession mMockitoSession;
private LinkProperties mLinkProperties = new LinkProperties();
private String mServerAddress;
+ private QnsTimer mQnsTimer;
private int[] mRttConfigs;
HandlerThread mHt =
@@ -85,7 +88,11 @@
super.onLooperPrepared();
mWbm =
new WifiBackhaulMonitor(
- sMockContext, mMockQnsConfigManager, mMockQnsImsManager, 0);
+ sMockContext,
+ mMockQnsConfigManager,
+ mMockQnsImsManager,
+ mQnsTimer,
+ 0);
setReady(true);
}
};
@@ -121,6 +128,7 @@
mRttConfigs = null;
mLinkProperties.setInterfaceName("iwlan0");
mLatch = new CountDownLatch(1);
+ mQnsTimer = new QnsTimer(sMockContext);
mMockitoSession =
mockitoSession()
@@ -282,7 +290,7 @@
null))
.sendToTarget();
waitForDelayedHandlerAction(mRttHandler, 100, 100);
- assertTrue(mRttHandler.hasMessages(EVENT_START_RTT_CHECK));
+ assertNotEquals(mWbm.getRttTimerId(), INVALID_ID);
}
@Test
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/WifiQualityMonitorTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/WifiQualityMonitorTest.java
index 75d8db7..8e51d2c 100644
--- a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/WifiQualityMonitorTest.java
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/WifiQualityMonitorTest.java
@@ -53,8 +53,10 @@
@RunWith(JUnit4.class)
public class WifiQualityMonitorTest extends QnsTest {
+ private static final int EVENT_QNS_TIMER_EXPIRED = 1;
Context mContext;
@Mock ConnectivityManager mConnectivityManager;
+ QnsTimer mQnsTimer;
@Mock WifiManager mWifiManager;
@Mock NetworkCapabilities mNetworkCapabilityManager;
@Mock private Network mMockNetwork;
@@ -96,7 +98,8 @@
mWifiInfo = new WifiInfo.Builder().setRssi(mSetRssi).build();
mLatch = new CountDownLatch(1);
mThresholdListener = new ThresholdListener(mExecutor);
- mWifiQualityMonitor = new WifiQualityMonitor(mContext);
+ mQnsTimer = new QnsTimer(mContext);
+ mWifiQualityMonitor = new WifiQualityMonitor(mContext, mQnsTimer);
}
@Test
@@ -232,7 +235,7 @@
}
@Test
- public void testBackhaulTimer() throws InterruptedException {
+ public void testBackhaulTimer() {
mSetRssi = -65;
mLatch = new CountDownLatch(1);
mWifiInfo = new WifiInfo.Builder().setRssi(mSetRssi).build();
@@ -277,8 +280,9 @@
mWifiQualityMonitor.mHandler.obtainMessage(EVENT_WIFI_RSSI_CHANGED, -65, 0).sendToTarget();
waitForDelayedHandlerAction(mWifiQualityMonitor.mHandler, 1000, 200);
- assertTrue(mWifiQualityMonitor.mHandler.hasMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED));
+ assertTrue(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
waitForDelayedHandlerAction(mWifiQualityMonitor.mHandler, 4000, 200);
+ assertFalse(mQnsTimer.mHandler.hasMessages(EVENT_QNS_TIMER_EXPIRED));
assertFalse(mWifiQualityMonitor.mHandler.hasMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED));
}
@@ -329,23 +333,6 @@
isWifiRssiChangedHandlerNotPosted();
}
- @Test
- public void testSkipValidateWqmStatus_WithBackhaulInProgress() {
- mSetRssi = -65;
- mLatch = new CountDownLatch(1);
- mWifiInfo = new WifiInfo.Builder().setRssi(mSetRssi).build();
- when(mWifiManager.getConnectionInfo()).thenReturn(mWifiInfo);
-
- setWqmThreshold();
- mWifiQualityMonitor.validateWqmStatus(-65);
-
- waitForDelayedHandlerAction(mWifiQualityMonitor.mHandler, 1000, 200);
- assertTrue(mWifiQualityMonitor.mHandler.hasMessages(EVENT_WIFI_NOTIFY_TIMER_EXPIRED));
-
- mWifiQualityMonitor.validateWqmStatus(-68);
- assertFalse(mWifiQualityMonitor.mHandler.hasMessages(EVENT_WIFI_RSSI_CHANGED));
- }
-
private void setWqmThreshold() {
mThs1[0] =
new Threshold(
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsFallbackRestrictionChangedInfoTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsFallbackRestrictionChangedInfoTest.java
new file mode 100644
index 0000000..159ab07
--- /dev/null
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsFallbackRestrictionChangedInfoTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.util.StatsEvent;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public class AtomsQnsFallbackRestrictionChangedInfoTest {
+
+ @Mock
+ private StatsEvent.Builder mStatsEventBuilder;
+
+ private static final boolean DEFAULT_RESTRICTION_WLAN_RTP_THRESHOLD_BREACHED = true;
+ private static final boolean DEFAULT_RESTRICTION_WWAN_RTP_THRESHOLD_BREACHED = true;
+ private static final boolean DEFAULT_RESTRICTION_WWAN_IMS_REGI_FAIL = true;
+ private static final boolean DEFAULT_RESTRICTION_WWAN_WIFI_BACKHAUL_PROBLEM = true;
+ private static final int DEFAULT_CARRIER_ID = 1; // TMO
+
+ private AtomsQnsFallbackRestrictionChangedInfo mInfoEmpty;
+ private AtomsQnsFallbackRestrictionChangedInfo mInfoDefault;
+ private AtomsQnsFallbackRestrictionChangedInfo mInfoCopy;
+
+ /** atom #1 : Restriction on WLAN caused by RTP threshold breached */
+ private boolean mRestrictionWlanRtpThresholdBreached;
+
+ /** atom #2 : Restriction on WWAN caused by RTP threshold breached */
+ private boolean mRestrictionWwanRtpThresholdBreached;
+
+ /** atom #3 : Restriction on WLAN caused by IMS registration fail */
+ private boolean mRestrictionWwanImsRegiFail;
+
+ /** atom #4 : Restriction on WLAN caused by Wifi backhaul problem. */
+ private boolean mRestrictionWwanWifiBackhaulProblem;
+
+ /** atom #5 : Carrier Id */
+ private int mCarrierId;
+
+ /** atom #6 : Slot Index */
+ private int mSlotIndex;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mRestrictionWlanRtpThresholdBreached = DEFAULT_RESTRICTION_WLAN_RTP_THRESHOLD_BREACHED;
+ mRestrictionWwanRtpThresholdBreached = DEFAULT_RESTRICTION_WWAN_RTP_THRESHOLD_BREACHED;
+ mRestrictionWwanImsRegiFail = DEFAULT_RESTRICTION_WWAN_IMS_REGI_FAIL;
+ mRestrictionWwanWifiBackhaulProblem = DEFAULT_RESTRICTION_WWAN_WIFI_BACKHAUL_PROBLEM;
+ mCarrierId = DEFAULT_CARRIER_ID;
+ mSlotIndex = 0;
+ mInfoEmpty = new AtomsQnsFallbackRestrictionChangedInfo();
+ mInfoDefault =
+ new AtomsQnsFallbackRestrictionChangedInfo(
+ mRestrictionWlanRtpThresholdBreached,
+ mRestrictionWwanRtpThresholdBreached,
+ mRestrictionWwanImsRegiFail,
+ mRestrictionWwanWifiBackhaulProblem,
+ mCarrierId,
+ mSlotIndex);
+ mInfoCopy = new AtomsQnsFallbackRestrictionChangedInfo(mInfoDefault);
+ }
+
+ @After
+ public void tearDown() {
+ mInfoEmpty = null;
+ mInfoDefault = null;
+ mInfoCopy = null;
+ }
+
+ @Test
+ public void testGetSetRestrictionWlanRtpThresholdBreached() {
+ assertFalse(mInfoEmpty.getRestrictionOnWlanByRtpThresholdBreached());
+ assertTrue(mInfoDefault.getRestrictionOnWlanByRtpThresholdBreached());
+ assertTrue(mInfoCopy.getRestrictionOnWlanByRtpThresholdBreached());
+
+ mInfoEmpty.setRestrictionOnWlanByRtpThresholdBreached(true);
+ mInfoDefault.setRestrictionOnWlanByRtpThresholdBreached(true);
+ mInfoCopy.setRestrictionOnWlanByRtpThresholdBreached(true);
+
+ assertTrue(mInfoEmpty.getRestrictionOnWlanByRtpThresholdBreached());
+ assertTrue(mInfoDefault.getRestrictionOnWlanByRtpThresholdBreached());
+ assertTrue(mInfoCopy.getRestrictionOnWlanByRtpThresholdBreached());
+ }
+
+ @Test
+ public void testGetSetRestrictionWwanRtpThresholdBreached() {
+ assertFalse(mInfoEmpty.getRestrictionOnWwanByRtpThresholdBreached());
+ assertTrue(mInfoDefault.getRestrictionOnWwanByRtpThresholdBreached());
+ assertTrue(mInfoCopy.getRestrictionOnWwanByRtpThresholdBreached());
+
+ mInfoEmpty.setRestrictionOnWwanByRtpThresholdBreached(true);
+ mInfoDefault.setRestrictionOnWwanByRtpThresholdBreached(true);
+ mInfoCopy.setRestrictionOnWwanByRtpThresholdBreached(true);
+
+ assertTrue(mInfoEmpty.getRestrictionOnWwanByRtpThresholdBreached());
+ assertTrue(mInfoDefault.getRestrictionOnWwanByRtpThresholdBreached());
+ assertTrue(mInfoCopy.getRestrictionOnWwanByRtpThresholdBreached());
+ }
+
+ @Test
+ public void testGetSetRestrictionWwanImsRegiFail() {
+ assertFalse(mInfoEmpty.getRestrictionOnWlanByImsRegistrationFailed());
+ assertTrue(mInfoDefault.getRestrictionOnWlanByImsRegistrationFailed());
+ assertTrue(mInfoCopy.getRestrictionOnWlanByImsRegistrationFailed());
+
+ mInfoEmpty.setRestrictionOnWlanByImsRegistrationFailed(true);
+ mInfoDefault.setRestrictionOnWlanByImsRegistrationFailed(true);
+ mInfoCopy.setRestrictionOnWlanByImsRegistrationFailed(true);
+
+ assertTrue(mInfoEmpty.getRestrictionOnWlanByImsRegistrationFailed());
+ assertTrue(mInfoDefault.getRestrictionOnWlanByImsRegistrationFailed());
+ assertTrue(mInfoCopy.getRestrictionOnWlanByImsRegistrationFailed());
+ }
+
+ @Test
+ public void testGetSetRestrictionWwanWifiBackhaulProblem() {
+ assertFalse(mInfoEmpty.getRestrictionOnWlanByWifiBackhaulProblem());
+ assertTrue(mInfoDefault.getRestrictionOnWlanByWifiBackhaulProblem());
+ assertTrue(mInfoCopy.getRestrictionOnWlanByWifiBackhaulProblem());
+
+ mInfoEmpty.setRestrictionOnWlanByWifiBackhaulProblem(true);
+ mInfoDefault.setRestrictionOnWlanByWifiBackhaulProblem(true);
+ mInfoCopy.setRestrictionOnWlanByWifiBackhaulProblem(true);
+
+ assertTrue(mInfoEmpty.getRestrictionOnWlanByWifiBackhaulProblem());
+ assertTrue(mInfoDefault.getRestrictionOnWlanByWifiBackhaulProblem());
+ assertTrue(mInfoCopy.getRestrictionOnWlanByWifiBackhaulProblem());
+ }
+
+ @Test
+ public void testGetSetCarrierId() {
+ assertEquals(0, mInfoEmpty.getCarrierId());
+ assertEquals(DEFAULT_CARRIER_ID, mInfoDefault.getCarrierId());
+ assertEquals(DEFAULT_CARRIER_ID, mInfoCopy.getCarrierId());
+
+ mInfoEmpty.setCarrierId(1);
+ mInfoDefault.setCarrierId(2);
+ mInfoCopy.setCarrierId(3);
+
+ assertEquals(1, mInfoEmpty.getCarrierId());
+ assertEquals(2, mInfoDefault.getCarrierId());
+ assertEquals(3, mInfoCopy.getCarrierId());
+ }
+
+ @Test
+ public void testGetSetSlotIndex() {
+ assertEquals(0, mInfoEmpty.getSlotIndex());
+ assertEquals(0, mInfoDefault.getSlotIndex());
+ assertEquals(0, mInfoCopy.getSlotIndex());
+
+ mInfoEmpty.setSlotIndex(1);
+ mInfoDefault.setSlotIndex(2);
+ mInfoCopy.setSlotIndex(3);
+
+ assertEquals(1, mInfoEmpty.getSlotIndex());
+ assertEquals(2, mInfoDefault.getSlotIndex());
+ assertEquals(3, mInfoCopy.getSlotIndex());
+ }
+
+ @Test
+ public void testToString() {
+ String strInfoEmpty = mInfoEmpty.toString();
+ String strInfoDefault = mInfoDefault.toString();
+ String strInfoCopy = mInfoCopy.toString();
+
+ assertNotNull(strInfoEmpty);
+ assertNotNull(strInfoDefault);
+ assertNotNull(strInfoCopy);
+
+ assertTrue(strInfoDefault.startsWith("AtomsQnsFallbackRestrictionChangedInfo"));
+
+ assertEquals(strInfoDefault, strInfoCopy);
+ assertNotEquals(strInfoEmpty, strInfoDefault);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(mInfoDefault, mInfoDefault);
+ assertNotEquals(mInfoDefault, new Object());
+ assertEquals(mInfoDefault, mInfoCopy);
+ mInfoDefault.setRestrictionOnWlanByRtpThresholdBreached(false);
+ mInfoCopy.setRestrictionOnWlanByRtpThresholdBreached(true);
+ assertNotEquals(mInfoDefault, mInfoCopy);
+ }
+
+ @Test
+ public void testHashCode() {
+ AtomsQnsFallbackRestrictionChangedInfo a1, a2;
+
+ a1 =
+ new AtomsQnsFallbackRestrictionChangedInfo(
+ true, true, false, false, mCarrierId, mSlotIndex);
+ a2 =
+ new AtomsQnsFallbackRestrictionChangedInfo(
+ false, false, false, false, mCarrierId, mSlotIndex);
+ assertNotEquals(a1.hashCode(), a2.hashCode());
+
+ a1 =
+ new AtomsQnsFallbackRestrictionChangedInfo(
+ mRestrictionWlanRtpThresholdBreached,
+ mRestrictionWwanRtpThresholdBreached,
+ mRestrictionWwanImsRegiFail,
+ mRestrictionWwanWifiBackhaulProblem,
+ mCarrierId,
+ mSlotIndex);
+ a2 =
+ new AtomsQnsFallbackRestrictionChangedInfo(
+ mRestrictionWlanRtpThresholdBreached,
+ mRestrictionWwanRtpThresholdBreached,
+ mRestrictionWwanImsRegiFail,
+ mRestrictionWwanWifiBackhaulProblem,
+ mCarrierId,
+ mSlotIndex);
+ assertEquals(a1.hashCode(), a2.hashCode());
+ }
+
+ @Test
+ public void testStatsId() {
+ final int statsId = 636; // QnsFallbackRestrictionChanged
+ assertEquals(statsId, mInfoDefault.copy().getStatsId());
+ }
+
+ @Test
+ public void testStatsEventBuilder() {
+ mInfoDefault.build(mStatsEventBuilder);
+
+ verify(mStatsEventBuilder, times(4)).writeBoolean(anyBoolean());
+ verify(mStatsEventBuilder, times(2)).writeInt(anyInt());
+ }
+}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsHandoverPingPongInfoTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsHandoverPingPongInfoTest.java
new file mode 100644
index 0000000..e914579
--- /dev/null
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsHandoverPingPongInfoTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.util.StatsEvent;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public class AtomsQnsHandoverPingPongInfoTest {
+
+ @Mock
+ private StatsEvent.Builder mStatsEventBuilder;
+
+ private static final int DEFAULT_COUNT_HANDOVER_PING_PONG = 2;
+ private static final int DEFAULT_CARRIER_ID = 1; // TMO
+
+ private AtomsQnsHandoverPingPongInfo mInfoEmpty;
+ private AtomsQnsHandoverPingPongInfo mInfoDefault;
+ private AtomsQnsHandoverPingPongInfo mInfoCopy;
+
+ /** atom #1 : Count of handover ping-pong */
+ private int mCountHandoverPingPong;
+
+ /** atom #2 : Carrier Id */
+ private int mCarrierId;
+
+ /** atom #3 : Slot Index */
+ private int mSlotIndex;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mCountHandoverPingPong = DEFAULT_COUNT_HANDOVER_PING_PONG;
+ mCarrierId = DEFAULT_CARRIER_ID;
+ mSlotIndex = 0;
+ mInfoEmpty = new AtomsQnsHandoverPingPongInfo();
+ mInfoDefault =
+ new AtomsQnsHandoverPingPongInfo(mCountHandoverPingPong, mCarrierId, mSlotIndex);
+ mInfoCopy = new AtomsQnsHandoverPingPongInfo(mInfoDefault);
+ }
+
+ @After
+ public void tearDown() {
+ mInfoEmpty = null;
+ mInfoDefault = null;
+ mInfoCopy = null;
+ }
+
+ @Test
+ public void testGetSetCountHandoverPingPong() {
+ assertEquals(0, mInfoEmpty.getCountHandoverPingPong());
+ assertEquals(DEFAULT_COUNT_HANDOVER_PING_PONG, mInfoDefault.getCountHandoverPingPong());
+ assertEquals(DEFAULT_COUNT_HANDOVER_PING_PONG, mInfoCopy.getCountHandoverPingPong());
+
+ mInfoEmpty.setCountHandoverPingPong(3);
+ mInfoDefault.setCountHandoverPingPong(4);
+ mInfoCopy.setCountHandoverPingPong(5);
+
+ assertEquals(3, mInfoEmpty.getCountHandoverPingPong());
+ assertEquals(4, mInfoDefault.getCountHandoverPingPong());
+ assertEquals(5, mInfoCopy.getCountHandoverPingPong());
+ }
+
+ @Test
+ public void testGetSetCarrierId() {
+ assertEquals(0, mInfoEmpty.getCarrierId());
+ assertEquals(DEFAULT_CARRIER_ID, mInfoDefault.getCarrierId());
+ assertEquals(DEFAULT_CARRIER_ID, mInfoCopy.getCarrierId());
+
+ mInfoEmpty.setCarrierId(1);
+ mInfoDefault.setCarrierId(2);
+ mInfoCopy.setCarrierId(3);
+
+ assertEquals(1, mInfoEmpty.getCarrierId());
+ assertEquals(2, mInfoDefault.getCarrierId());
+ assertEquals(3, mInfoCopy.getCarrierId());
+ }
+
+ @Test
+ public void testGetSetSlotIndex() {
+ assertEquals(0, mInfoEmpty.getSlotIndex());
+ assertEquals(0, mInfoDefault.getSlotIndex());
+ assertEquals(0, mInfoCopy.getSlotIndex());
+
+ mInfoEmpty.setSlotIndex(1);
+ mInfoDefault.setSlotIndex(2);
+ mInfoCopy.setSlotIndex(3);
+
+ assertEquals(1, mInfoEmpty.getSlotIndex());
+ assertEquals(2, mInfoDefault.getSlotIndex());
+ assertEquals(3, mInfoCopy.getSlotIndex());
+ }
+
+ @Test
+ public void testToString() {
+ String strInfoEmpty = mInfoEmpty.toString();
+ String strInfoDefault = mInfoDefault.toString();
+ String strInfoCopy = mInfoCopy.toString();
+
+ assertNotNull(strInfoEmpty);
+ assertNotNull(strInfoDefault);
+ assertNotNull(strInfoCopy);
+
+ assertTrue(strInfoDefault.startsWith("AtomsQnsHandoverPingPongInfo"));
+
+ assertEquals(strInfoDefault, strInfoCopy);
+ assertNotEquals(strInfoEmpty, strInfoDefault);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(mInfoDefault, mInfoDefault);
+ assertNotEquals(mInfoDefault, new Object());
+ assertEquals(mInfoDefault, mInfoCopy);
+ mInfoDefault.setCountHandoverPingPong(2);
+ mInfoCopy.setCountHandoverPingPong(3);
+ assertNotEquals(mInfoDefault, mInfoCopy);
+ }
+
+ @Test
+ public void testHashCode() {
+ AtomsQnsHandoverPingPongInfo a1, a2;
+
+ a1 = new AtomsQnsHandoverPingPongInfo(2, 1, 0);
+ a2 = new AtomsQnsHandoverPingPongInfo(3, 1, 0);
+ assertNotEquals(a1.hashCode(), a2.hashCode());
+
+ a1 = new AtomsQnsHandoverPingPongInfo(mCountHandoverPingPong, mCarrierId, mSlotIndex);
+ a2 = new AtomsQnsHandoverPingPongInfo(mCountHandoverPingPong, mCarrierId, mSlotIndex);
+ assertEquals(a1.hashCode(), a2.hashCode());
+ }
+
+ @Test
+ public void testDimension() {
+ AtomsQnsHandoverPingPongInfo a1, a2;
+
+ a1 = new AtomsQnsHandoverPingPongInfo(mCountHandoverPingPong, 3, mSlotIndex);
+ a2 = new AtomsQnsHandoverPingPongInfo(mCountHandoverPingPong, 1, mSlotIndex);
+ assertNotEquals(a1.getDimension(), a2.getDimension());
+
+ a1 = new AtomsQnsHandoverPingPongInfo(mCountHandoverPingPong, mCarrierId, 0);
+ a2 = new AtomsQnsHandoverPingPongInfo(mCountHandoverPingPong, mCarrierId, 1);
+ assertNotEquals(a1.getDimension(), a2.getDimension());
+
+ a1 = new AtomsQnsHandoverPingPongInfo(1, mCarrierId, mSlotIndex);
+ a2 = new AtomsQnsHandoverPingPongInfo(2, mCarrierId, mSlotIndex);
+ assertEquals(a1.getDimension(), a2.getDimension());
+ }
+
+ @Test
+ public void testStatsId() {
+ final int statsId = 10179; // QnsHandoverPingpong
+ assertEquals(statsId, mInfoDefault.copy().getStatsId());
+ }
+
+ @Test
+ public void testStatsEventBuilder() {
+ mInfoDefault.build(mStatsEventBuilder);
+
+ verify(mStatsEventBuilder, times(3)).writeInt(anyInt());
+ }
+}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsHandoverTimeMillisInfoTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsHandoverTimeMillisInfoTest.java
new file mode 100644
index 0000000..701874b
--- /dev/null
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsHandoverTimeMillisInfoTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.util.StatsEvent;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public class AtomsQnsHandoverTimeMillisInfoTest {
+
+ @Mock
+ private StatsEvent.Builder mStatsEventBuilder;
+
+ private static final int DEFAULT_TIMER_FOR_HANDOVER_SUCCESS = 5000;
+
+ private AtomsQnsHandoverTimeMillisInfo mInfoEmpty;
+ private AtomsQnsHandoverTimeMillisInfo mInfoDefault;
+ private AtomsQnsHandoverTimeMillisInfo mInfoCopy;
+
+ /** atom #1 : Time in milliseconds from QNS RAT update to successful HO completion */
+ private int mTimeForHoSuccess;
+
+ /** atom #2 : Slot Index */
+ private int mSlotIndex;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTimeForHoSuccess = DEFAULT_TIMER_FOR_HANDOVER_SUCCESS;
+ mSlotIndex = 0;
+ mInfoEmpty = new AtomsQnsHandoverTimeMillisInfo();
+ mInfoDefault = new AtomsQnsHandoverTimeMillisInfo(mTimeForHoSuccess, mSlotIndex);
+ mInfoCopy = new AtomsQnsHandoverTimeMillisInfo(mInfoDefault);
+ }
+
+ @After
+ public void tearDown() {
+ mInfoEmpty = null;
+ mInfoDefault = null;
+ mInfoCopy = null;
+ }
+
+ @Test
+ public void testGetSetTimeForHoSuccess() {
+ assertEquals(0, mInfoEmpty.getTimeForHoSuccess());
+ assertEquals(DEFAULT_TIMER_FOR_HANDOVER_SUCCESS, mInfoDefault.getTimeForHoSuccess());
+ assertEquals(DEFAULT_TIMER_FOR_HANDOVER_SUCCESS, mInfoCopy.getTimeForHoSuccess());
+
+ mInfoEmpty.setTimeForHoSuccess(3000);
+ mInfoDefault.setTimeForHoSuccess(4000);
+ mInfoCopy.setTimeForHoSuccess(7000);
+
+ assertEquals(3000, mInfoEmpty.getTimeForHoSuccess());
+ assertEquals(4000, mInfoDefault.getTimeForHoSuccess());
+ assertEquals(7000, mInfoCopy.getTimeForHoSuccess());
+ }
+
+ @Test
+ public void testGetSetSlotIndex() {
+ assertEquals(0, mInfoEmpty.getSlotIndex());
+ assertEquals(0, mInfoDefault.getSlotIndex());
+ assertEquals(0, mInfoCopy.getSlotIndex());
+
+ mInfoEmpty.setSlotIndex(1);
+ mInfoDefault.setSlotIndex(2);
+ mInfoCopy.setSlotIndex(3);
+
+ assertEquals(1, mInfoEmpty.getSlotIndex());
+ assertEquals(2, mInfoDefault.getSlotIndex());
+ assertEquals(3, mInfoCopy.getSlotIndex());
+ }
+
+ @Test
+ public void testToString() {
+ String strInfoEmpty = mInfoEmpty.toString();
+ String strInfoDefault = mInfoDefault.toString();
+ String strInfoCopy = mInfoCopy.toString();
+
+ assertNotNull(strInfoEmpty);
+ assertNotNull(strInfoDefault);
+ assertNotNull(strInfoCopy);
+
+ assertTrue(strInfoDefault.startsWith("AtomsQnsHandoverTimeMillisInfo"));
+
+ assertEquals(strInfoDefault, strInfoCopy);
+ assertNotEquals(strInfoEmpty, strInfoDefault);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(mInfoDefault, mInfoDefault);
+ assertNotEquals(mInfoDefault, new Object());
+ assertEquals(mInfoDefault, mInfoCopy);
+ mInfoDefault.setTimeForHoSuccess(2000);
+ mInfoCopy.setTimeForHoSuccess(3000);
+ assertNotEquals(mInfoDefault, mInfoCopy);
+ }
+
+ @Test
+ public void testHashCode() {
+ AtomsQnsHandoverTimeMillisInfo a1, a2;
+
+ a1 = new AtomsQnsHandoverTimeMillisInfo(2000, 0);
+ a2 = new AtomsQnsHandoverTimeMillisInfo(3000, 0);
+ assertNotEquals(a1.hashCode(), a2.hashCode());
+
+ a1 = new AtomsQnsHandoverTimeMillisInfo(mTimeForHoSuccess, mSlotIndex);
+ a2 = new AtomsQnsHandoverTimeMillisInfo(mTimeForHoSuccess, mSlotIndex);
+ assertEquals(a1.hashCode(), a2.hashCode());
+ }
+
+ @Test
+ public void testDimension() {
+ AtomsQnsHandoverTimeMillisInfo a1, a2;
+ a1 = new AtomsQnsHandoverTimeMillisInfo(1000, 0);
+ a2 = new AtomsQnsHandoverTimeMillisInfo(2000, 1);
+ assertNotEquals(a1.getDimension(), a2.getDimension());
+ assertEquals(a1.getDimension(), mInfoDefault.getDimension());
+ }
+
+ @Test
+ public void testStatsId() {
+ final int statsId = 10178; // QnsHandoverTimeMillis
+ assertEquals(statsId, mInfoDefault.copy().getStatsId());
+ }
+
+ @Test
+ public void testStatsEventBuilder() {
+ mInfoDefault.build(mStatsEventBuilder);
+
+ verify(mStatsEventBuilder, times(2)).writeInt(anyInt());
+ }
+}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsImsCallDropStatsTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsImsCallDropStatsTest.java
new file mode 100644
index 0000000..a2b68ad
--- /dev/null
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsImsCallDropStatsTest.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.telephony.qns.QnsProtoEnums;
+import android.util.StatsEvent;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public class AtomsQnsImsCallDropStatsTest {
+
+ @Mock
+ private StatsEvent.Builder mStatsEventBuilder;
+
+ private static final int DEFAULT_CURRENT_TRANSPORT_TYPE = QnsProtoEnums.TRANSPORT_TYPE_WWAN;
+ private static final int DEFAULT_RESTRICTIONS = QnsProtoEnums.RESTRICT_TYPE_NONE;
+ private static final int DEFAULT_SIGNAL_STRENGTH = -100;
+ private static final int DEFAULT_SIGNAL_QUALITY = -10;
+ private static final int DEFAULT_SIGNAL_NOISE = -1;
+ private static final int DEFAULT_IWLAN_SIGNAL_STRENGTH = -70;
+ private static final int DEFAULT_CELLULAR_NETWORK_TYPE = QnsProtoEnums.EUTRAN;
+
+ private AtomsQnsImsCallDropStats mInfoEmpty;
+ private AtomsQnsImsCallDropStats mInfoDefault;
+ private AtomsQnsImsCallDropStats mInfoCopy;
+
+ /** atom #1 : Transport type in where IMS call drop occurred. */
+ private int mTransportTypeCallDropped;
+
+ /** atom #2 : RTP threshold breached event occurred. */
+ private boolean mRtpThresholdBreached;
+
+ /** atom #3 : Bit mask of restrictions on another transport type */
+ private int mRestrictionsOnOtherTransportType;
+
+ /** atom #4 : Cellular network signal strength {e.g. SSRSRP in NR, RSRP in LTE} */
+ private int mSignalStrength;
+
+ /** atom #5 : Cellular network signal quality {e.g. SSRSRQ in NR, RSRQ in LTE} */
+ private int mSignalQuality;
+
+ /** atom #6 : Cellular network signal noise ratio {e.g. SSSINR in NR, RSSNR in LTE} */
+ private int mSignalNoise;
+
+ /** atom #7 : Iwlan network signal strength (Wi-Fi RSSI) */
+ private int mIwlanSignalStrength;
+
+ /** atom #8 : Slot Index */
+ private int mSlotIndex;
+
+ /** atom #9 : cellular access network type. */
+ private int mCellularNetworkType;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTransportTypeCallDropped = DEFAULT_CURRENT_TRANSPORT_TYPE;
+ mRtpThresholdBreached = true;
+ mRestrictionsOnOtherTransportType = DEFAULT_RESTRICTIONS;
+ mSignalStrength = DEFAULT_SIGNAL_STRENGTH;
+ mSignalQuality = DEFAULT_SIGNAL_QUALITY;
+ mSignalNoise = DEFAULT_SIGNAL_NOISE;
+ mIwlanSignalStrength = DEFAULT_IWLAN_SIGNAL_STRENGTH;
+ mSlotIndex = 0;
+ mCellularNetworkType = DEFAULT_CELLULAR_NETWORK_TYPE;
+
+ mInfoEmpty = new AtomsQnsImsCallDropStats();
+ mInfoDefault =
+ new AtomsQnsImsCallDropStats(
+ mTransportTypeCallDropped,
+ mRtpThresholdBreached,
+ mRestrictionsOnOtherTransportType,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mSlotIndex,
+ mCellularNetworkType);
+ mInfoCopy = new AtomsQnsImsCallDropStats(mInfoDefault);
+ }
+
+ @After
+ public void tearDown() {
+ mInfoEmpty = null;
+ mInfoDefault = null;
+ mInfoCopy = null;
+ }
+
+ @Test
+ public void testGetSetTransportTypeCallDropped() {
+ assertEquals(0, mInfoEmpty.getTransportTypeCallDropped());
+ assertEquals(DEFAULT_CURRENT_TRANSPORT_TYPE, mInfoDefault.getTransportTypeCallDropped());
+ assertEquals(DEFAULT_CURRENT_TRANSPORT_TYPE, mInfoCopy.getTransportTypeCallDropped());
+
+ mInfoEmpty.setTransportTypeCallDropped(QnsProtoEnums.TRANSPORT_TYPE_WWAN);
+ mInfoDefault.setTransportTypeCallDropped(QnsProtoEnums.TRANSPORT_TYPE_WLAN);
+ mInfoCopy.setTransportTypeCallDropped(QnsProtoEnums.TRANSPORT_TYPE_INVALID);
+
+ assertEquals(QnsProtoEnums.TRANSPORT_TYPE_WWAN, mInfoEmpty.getTransportTypeCallDropped());
+ assertEquals(QnsProtoEnums.TRANSPORT_TYPE_WLAN, mInfoDefault.getTransportTypeCallDropped());
+ assertEquals(QnsProtoEnums.TRANSPORT_TYPE_INVALID, mInfoCopy.getTransportTypeCallDropped());
+ }
+
+ @Test
+ public void testGetSetRtpThresholdBreached() {
+ assertFalse(mInfoEmpty.getRtpThresholdBreached());
+ assertTrue(mInfoDefault.getRtpThresholdBreached());
+ assertTrue(mInfoCopy.getRtpThresholdBreached());
+
+ mInfoEmpty.setRtpThresholdBreached(true);
+ mInfoDefault.setRtpThresholdBreached(true);
+ mInfoCopy.setRtpThresholdBreached(false);
+
+ assertTrue(mInfoEmpty.getRtpThresholdBreached());
+ assertTrue(mInfoDefault.getRtpThresholdBreached());
+ assertFalse(mInfoCopy.getRtpThresholdBreached());
+ }
+
+ @Test
+ public void testGetSetRestrictionsOnOtherTransportType() {
+ assertEquals(0, mInfoEmpty.getRestrictionsOnOtherTransportType());
+ assertEquals(DEFAULT_RESTRICTIONS, mInfoDefault.getRestrictionsOnOtherTransportType());
+ assertEquals(DEFAULT_RESTRICTIONS, mInfoCopy.getRestrictionsOnOtherTransportType());
+
+ mInfoEmpty.setRestrictionsOnOtherTransportType(QnsProtoEnums.RESTRICT_TYPE_GUARDING);
+ mInfoDefault.setRestrictionsOnOtherTransportType(QnsProtoEnums.RESTRICT_TYPE_THROTTLING);
+ mInfoCopy.setRestrictionsOnOtherTransportType(QnsProtoEnums.RESTRICT_TYPE_NONE);
+
+ assertEquals(
+ QnsProtoEnums.RESTRICT_TYPE_GUARDING,
+ mInfoEmpty.getRestrictionsOnOtherTransportType());
+ assertEquals(
+ QnsProtoEnums.RESTRICT_TYPE_THROTTLING,
+ mInfoDefault.getRestrictionsOnOtherTransportType());
+ assertEquals(
+ QnsProtoEnums.RESTRICT_TYPE_NONE, mInfoCopy.getRestrictionsOnOtherTransportType());
+ }
+
+ @Test
+ public void testGetSetSignalStrength() {
+ assertEquals(0, mInfoEmpty.getSignalStrength());
+ assertEquals(DEFAULT_SIGNAL_STRENGTH, mInfoDefault.getSignalStrength());
+ assertEquals(DEFAULT_SIGNAL_STRENGTH, mInfoCopy.getSignalStrength());
+
+ mInfoEmpty.setSignalStrength(DEFAULT_SIGNAL_STRENGTH);
+ mInfoDefault.setSignalStrength(-120);
+ mInfoCopy.setSignalStrength(-110);
+
+ assertEquals(DEFAULT_SIGNAL_STRENGTH, mInfoEmpty.getSignalStrength());
+ assertEquals(-120, mInfoDefault.getSignalStrength());
+ assertEquals(-110, mInfoCopy.getSignalStrength());
+ }
+
+ @Test
+ public void testGetSetSignalQuality() {
+ assertEquals(0, mInfoEmpty.getSignalQuality());
+ assertEquals(DEFAULT_SIGNAL_QUALITY, mInfoDefault.getSignalQuality());
+ assertEquals(DEFAULT_SIGNAL_QUALITY, mInfoCopy.getSignalQuality());
+
+ mInfoEmpty.setSignalQuality(DEFAULT_SIGNAL_QUALITY);
+ mInfoDefault.setSignalQuality(-10);
+ mInfoCopy.setSignalQuality(-5);
+
+ assertEquals(DEFAULT_SIGNAL_QUALITY, mInfoEmpty.getSignalQuality());
+ assertEquals(-10, mInfoDefault.getSignalQuality());
+ assertEquals(-5, mInfoCopy.getSignalQuality());
+ }
+
+ @Test
+ public void testGetSetSignalNoise() {
+ assertEquals(0, mInfoEmpty.getSignalNoise());
+ assertEquals(DEFAULT_SIGNAL_NOISE, mInfoDefault.getSignalNoise());
+ assertEquals(DEFAULT_SIGNAL_NOISE, mInfoCopy.getSignalNoise());
+
+ mInfoEmpty.setSignalNoise(DEFAULT_SIGNAL_NOISE);
+ mInfoDefault.setSignalNoise(1);
+ mInfoCopy.setSignalNoise(-1);
+
+ assertEquals(DEFAULT_SIGNAL_NOISE, mInfoEmpty.getSignalNoise());
+ assertEquals(1, mInfoDefault.getSignalNoise());
+ assertEquals(-1, mInfoCopy.getSignalNoise());
+ }
+
+ @Test
+ public void testGetSetIwlanSignalStrength() {
+ assertEquals(0, mInfoEmpty.getIwlanSignalStrength());
+ assertEquals(DEFAULT_IWLAN_SIGNAL_STRENGTH, mInfoDefault.getIwlanSignalStrength());
+ assertEquals(DEFAULT_IWLAN_SIGNAL_STRENGTH, mInfoCopy.getIwlanSignalStrength());
+
+ mInfoEmpty.setIwlanSignalStrength(DEFAULT_IWLAN_SIGNAL_STRENGTH);
+ mInfoDefault.setIwlanSignalStrength(-80);
+ mInfoCopy.setIwlanSignalStrength(-50);
+
+ assertEquals(DEFAULT_IWLAN_SIGNAL_STRENGTH, mInfoEmpty.getIwlanSignalStrength());
+ assertEquals(-80, mInfoDefault.getIwlanSignalStrength());
+ assertEquals(-50, mInfoCopy.getIwlanSignalStrength());
+ }
+
+ @Test
+ public void testGetSetSlotIndex() {
+ assertEquals(0, mInfoEmpty.getSlotIndex());
+ assertEquals(0, mInfoDefault.getSlotIndex());
+ assertEquals(0, mInfoCopy.getSlotIndex());
+
+ mInfoEmpty.setSlotIndex(1);
+ mInfoDefault.setSlotIndex(2);
+ mInfoCopy.setSlotIndex(3);
+
+ assertEquals(1, mInfoEmpty.getSlotIndex());
+ assertEquals(2, mInfoDefault.getSlotIndex());
+ assertEquals(3, mInfoCopy.getSlotIndex());
+ }
+
+ @Test
+ public void testGetSetCellularNetworkType() {
+ assertEquals(0, mInfoEmpty.getCellularNetworkType());
+ assertEquals(DEFAULT_CELLULAR_NETWORK_TYPE, mInfoDefault.getCellularNetworkType());
+ assertEquals(DEFAULT_CELLULAR_NETWORK_TYPE, mInfoCopy.getCellularNetworkType());
+
+ mInfoEmpty.setCellularNetworkType(QnsProtoEnums.NGRAN);
+ mInfoDefault.setCellularNetworkType(QnsProtoEnums.UTRAN);
+ mInfoCopy.setCellularNetworkType(QnsProtoEnums.GERAN);
+
+ assertEquals(QnsProtoEnums.NGRAN, mInfoEmpty.getCellularNetworkType());
+ assertEquals(QnsProtoEnums.UTRAN, mInfoDefault.getCellularNetworkType());
+ assertEquals(QnsProtoEnums.GERAN, mInfoCopy.getCellularNetworkType());
+ }
+
+ @Test
+ public void testToString() {
+ String strInfoEmpty = mInfoEmpty.toString();
+ String strInfoDefault = mInfoDefault.toString();
+ String strInfoCopy = mInfoCopy.toString();
+
+ assertNotNull(strInfoEmpty);
+ assertNotNull(strInfoDefault);
+ assertNotNull(strInfoCopy);
+
+ assertTrue(strInfoDefault.startsWith("AtomsQnsImsCallDropStats"));
+
+ assertEquals(strInfoDefault, strInfoCopy);
+ assertNotEquals(strInfoEmpty, strInfoDefault);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(mInfoDefault, mInfoDefault);
+ assertNotEquals(mInfoDefault, new Object());
+ assertEquals(mInfoDefault, mInfoCopy);
+ mInfoDefault.setSignalQuality(3);
+ mInfoCopy.setSignalQuality(1);
+ assertNotEquals(mInfoDefault, mInfoCopy);
+ }
+
+ @Test
+ public void testHashCode() {
+ AtomsQnsImsCallDropStats a1, a2;
+
+ a1 =
+ new AtomsQnsImsCallDropStats(
+ mInfoDefault.getTransportTypeCallDropped(),
+ mInfoDefault.getRtpThresholdBreached(),
+ mInfoDefault.getRestrictionsOnOtherTransportType(),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0);
+ a2 =
+ new AtomsQnsImsCallDropStats(
+ mInfoDefault.getTransportTypeCallDropped(),
+ mInfoDefault.getRtpThresholdBreached(),
+ mInfoDefault.getRestrictionsOnOtherTransportType(),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1);
+ assertNotEquals(a1.hashCode(), a2.hashCode());
+
+ a1 =
+ new AtomsQnsImsCallDropStats(
+ mTransportTypeCallDropped,
+ mRtpThresholdBreached,
+ mRestrictionsOnOtherTransportType,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mSlotIndex,
+ mCellularNetworkType);
+ a2 =
+ new AtomsQnsImsCallDropStats(
+ mTransportTypeCallDropped,
+ mRtpThresholdBreached,
+ mRestrictionsOnOtherTransportType,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mSlotIndex,
+ mCellularNetworkType);
+ assertEquals(a1.hashCode(), a2.hashCode());
+ }
+
+ @Test
+ public void testStatsId() {
+ final int statsId = 635; // QnsImsCallDropStats
+ assertEquals(statsId, mInfoDefault.copy().getStatsId());
+ }
+
+ @Test
+ public void testStatsEventBuilder() {
+ mInfoDefault.build(mStatsEventBuilder);
+
+ verify(mStatsEventBuilder, times(1)).writeBoolean(anyBoolean());
+ verify(mStatsEventBuilder, times(8)).writeInt(anyInt());
+ }
+}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsRatPreferenceMismatchInfoTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsRatPreferenceMismatchInfoTest.java
new file mode 100644
index 0000000..4c5b469
--- /dev/null
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQnsRatPreferenceMismatchInfoTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.telephony.qns.QnsProtoEnums;
+import android.util.StatsEvent;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public class AtomsQnsRatPreferenceMismatchInfoTest {
+
+ @Mock
+ private StatsEvent.Builder mStatsEventBuilder;
+
+ private static final int DEFAULT_NET_CAPABILITY = QnsProtoEnums.NET_CAPABILITY_IMS;
+ private static final int DEFAULT_HANDOVER_FAIL_COUNT = 1;
+ private static final int DEFAULT_DURATION_OF_MISMATCH = 13500;
+ private static final int DEFAULT_CARRIER_ID = 1; // TMO
+
+ private AtomsQnsRatPreferenceMismatchInfo mInfoEmpty;
+ private AtomsQnsRatPreferenceMismatchInfo mInfoDefault;
+ private AtomsQnsRatPreferenceMismatchInfo mInfoCopy;
+
+ /** atom #1 : Net capability of this information. */
+ private int mNetCapability;
+
+ /** atom #2 : Count of handover failed. */
+ private int mHandoverFailCount;
+
+ /** atom #3 : Duration of this mismatch. */
+ private int mDurationOfMismatch;
+
+ /** atom #4 : Carrier ID */
+ private int mCarrierId;
+
+ /** atom #5 : Slot Index */
+ private int mSlotIndex;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mNetCapability = DEFAULT_NET_CAPABILITY;
+ mHandoverFailCount = DEFAULT_HANDOVER_FAIL_COUNT;
+ mDurationOfMismatch = DEFAULT_DURATION_OF_MISMATCH;
+ mCarrierId = DEFAULT_CARRIER_ID;
+ mSlotIndex = 0;
+ mInfoEmpty = new AtomsQnsRatPreferenceMismatchInfo();
+ mInfoDefault =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ mNetCapability,
+ mHandoverFailCount,
+ mDurationOfMismatch,
+ mCarrierId,
+ mSlotIndex);
+ mInfoCopy = new AtomsQnsRatPreferenceMismatchInfo(mInfoDefault);
+ }
+
+ @After
+ public void tearDown() {
+ mInfoEmpty = null;
+ mInfoDefault = null;
+ mInfoCopy = null;
+ }
+
+ @Test
+ public void testGetSetNetCapability() {
+ assertEquals(0, mInfoEmpty.getNetCapability());
+ assertEquals(DEFAULT_NET_CAPABILITY, mInfoDefault.getNetCapability());
+ assertEquals(DEFAULT_NET_CAPABILITY, mInfoCopy.getNetCapability());
+
+ mInfoEmpty.setNetCapability(QnsProtoEnums.NET_CAPABILITY_MMS);
+ mInfoDefault.setNetCapability(QnsProtoEnums.NET_CAPABILITY_CBS);
+ mInfoCopy.setNetCapability(QnsProtoEnums.NET_CAPABILITY_XCAP);
+
+ assertEquals(QnsProtoEnums.NET_CAPABILITY_MMS, mInfoEmpty.getNetCapability());
+ assertEquals(QnsProtoEnums.NET_CAPABILITY_CBS, mInfoDefault.getNetCapability());
+ assertEquals(QnsProtoEnums.NET_CAPABILITY_XCAP, mInfoCopy.getNetCapability());
+ }
+
+ @Test
+ public void testGetSetHandoverFailCount() {
+ assertEquals(0, mInfoEmpty.getHandoverFailCount());
+ assertEquals(DEFAULT_HANDOVER_FAIL_COUNT, mInfoDefault.getHandoverFailCount());
+ assertEquals(DEFAULT_HANDOVER_FAIL_COUNT, mInfoCopy.getHandoverFailCount());
+
+ mInfoEmpty.setHandoverFailCount(DEFAULT_HANDOVER_FAIL_COUNT);
+ mInfoDefault.setHandoverFailCount(4);
+ mInfoCopy.setHandoverFailCount(0);
+
+ assertEquals(DEFAULT_HANDOVER_FAIL_COUNT, mInfoEmpty.getHandoverFailCount());
+ assertEquals(4, mInfoDefault.getHandoverFailCount());
+ assertEquals(0, mInfoCopy.getHandoverFailCount());
+ }
+
+ @Test
+ public void testGetSetDurationOfMismatch() {
+ assertEquals(0, mInfoEmpty.getDurationOfMismatch());
+ assertEquals(DEFAULT_DURATION_OF_MISMATCH, mInfoDefault.getDurationOfMismatch());
+ assertEquals(DEFAULT_DURATION_OF_MISMATCH, mInfoCopy.getDurationOfMismatch());
+
+ mInfoEmpty.setDurationOfMismatch(DEFAULT_DURATION_OF_MISMATCH);
+ mInfoDefault.setDurationOfMismatch(4000);
+ mInfoCopy.setDurationOfMismatch(0);
+
+ assertEquals(DEFAULT_DURATION_OF_MISMATCH, mInfoEmpty.getDurationOfMismatch());
+ assertEquals(4000, mInfoDefault.getDurationOfMismatch());
+ assertEquals(0, mInfoCopy.getDurationOfMismatch());
+ }
+
+ @Test
+ public void testGetSetCarrierId() {
+ assertEquals(0, mInfoEmpty.getCarrierId());
+ assertEquals(DEFAULT_CARRIER_ID, mInfoDefault.getCarrierId());
+ assertEquals(DEFAULT_CARRIER_ID, mInfoCopy.getCarrierId());
+
+ mInfoEmpty.setCarrierId(1);
+ mInfoDefault.setCarrierId(2);
+ mInfoCopy.setCarrierId(3);
+
+ assertEquals(1, mInfoEmpty.getCarrierId());
+ assertEquals(2, mInfoDefault.getCarrierId());
+ assertEquals(3, mInfoCopy.getCarrierId());
+ }
+
+ @Test
+ public void testGetSetSlotIndex() {
+ assertEquals(0, mInfoEmpty.getSlotIndex());
+ assertEquals(0, mInfoDefault.getSlotIndex());
+ assertEquals(0, mInfoCopy.getSlotIndex());
+
+ mInfoEmpty.setSlotIndex(1);
+ mInfoDefault.setSlotIndex(2);
+ mInfoCopy.setSlotIndex(3);
+
+ assertEquals(1, mInfoEmpty.getSlotIndex());
+ assertEquals(2, mInfoDefault.getSlotIndex());
+ assertEquals(3, mInfoCopy.getSlotIndex());
+ }
+
+ @Test
+ public void testToString() {
+ String strInfoEmpty = mInfoEmpty.toString();
+ String strInfoDefault = mInfoDefault.toString();
+ String strInfoCopy = mInfoCopy.toString();
+
+ assertNotNull(strInfoEmpty);
+ assertNotNull(strInfoDefault);
+ assertNotNull(strInfoCopy);
+
+ assertTrue(strInfoDefault.startsWith("AtomsQnsRatPreferenceMismatchInfo"));
+
+ assertEquals(strInfoDefault, strInfoCopy);
+ assertNotEquals(strInfoEmpty, strInfoDefault);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(mInfoDefault, mInfoDefault);
+ assertNotEquals(mInfoDefault, new Object());
+ assertEquals(mInfoDefault, mInfoCopy);
+ mInfoDefault.setHandoverFailCount(0);
+ mInfoCopy.setHandoverFailCount(1);
+ assertNotEquals(mInfoDefault, mInfoCopy);
+ }
+
+ @Test
+ public void testHashCode() {
+ AtomsQnsRatPreferenceMismatchInfo a1, a2;
+
+ a1 =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ QnsProtoEnums.NET_CAPABILITY_IMS, 0, 0, mCarrierId, mSlotIndex);
+ a2 =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ QnsProtoEnums.NET_CAPABILITY_MMS, 0, 0, mCarrierId, mSlotIndex);
+ assertNotEquals(a1.hashCode(), a2.hashCode());
+
+ a1 =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ mNetCapability,
+ mHandoverFailCount,
+ mDurationOfMismatch,
+ mCarrierId,
+ mSlotIndex);
+ a2 =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ mNetCapability,
+ mHandoverFailCount,
+ mDurationOfMismatch,
+ mCarrierId,
+ mSlotIndex);
+ assertEquals(a1.hashCode(), a2.hashCode());
+ }
+
+ @Test
+ public void testDimension() {
+ AtomsQnsRatPreferenceMismatchInfo a1, a2;
+
+ a1 =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ mNetCapability, mHandoverFailCount, mDurationOfMismatch, 1, mSlotIndex);
+ a2 =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ mNetCapability, mHandoverFailCount, mDurationOfMismatch, 3, mSlotIndex);
+ assertNotEquals(a1.getDimension(), a2.getDimension());
+
+ a1 =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ mNetCapability, mHandoverFailCount, mDurationOfMismatch, mCarrierId, 0);
+ a2 =
+ new AtomsQnsRatPreferenceMismatchInfo(
+ mNetCapability, mHandoverFailCount, mDurationOfMismatch, mCarrierId, 1);
+ assertNotEquals(a1.getDimension(), a2.getDimension());
+
+ a1 = new AtomsQnsRatPreferenceMismatchInfo(9, 0, 100, mCarrierId, mSlotIndex);
+ a2 = new AtomsQnsRatPreferenceMismatchInfo(9, 1, 200, mCarrierId, mSlotIndex);
+ assertEquals(a1.getDimension(), a2.getDimension());
+ }
+
+ @Test
+ public void testStatsId() {
+ final int statsId = 10177; // QnsRatPreferenceMismatchInfo
+ assertEquals(statsId, mInfoDefault.copy().getStatsId());
+ }
+
+ @Test
+ public void testStatsEventBuilder() {
+ mInfoDefault.build(mStatsEventBuilder);
+
+ verify(mStatsEventBuilder, times(5)).writeInt(anyInt());
+ }
+}
diff --git a/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQualifiedRatListChangedInfoTest.java b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQualifiedRatListChangedInfoTest.java
new file mode 100644
index 0000000..5eb6a42
--- /dev/null
+++ b/services/QualifiedNetworksService/tests/src/com/android/telephony/qns/atoms/AtomsQualifiedRatListChangedInfoTest.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2022 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.telephony.qns.atoms;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.telephony.qns.QnsProtoEnums;
+import android.util.StatsEvent;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+public class AtomsQualifiedRatListChangedInfoTest {
+
+ @Mock
+ private StatsEvent.Builder mStatsEventBuilder;
+
+ private static final int DEFAULT_NET_CAPABILITY = QnsProtoEnums.NET_CAPABILITY_IMS;
+ private static final int DEFAULT_FIRST_QUALIFIED_RAT = QnsProtoEnums.EUTRAN;
+ private static final int DEFAULT_SECOND_QUALIFIED_RAT = QnsProtoEnums.IWLAN;
+ private static final int DEFAULT_CURRENT_TRANSPORT_TYPE = QnsProtoEnums.TRANSPORT_TYPE_WLAN;
+ private static final boolean DEFAULT_WFC_ENABLED = true;
+ private static final int DEFAULT_WFC_MODE = QnsProtoEnums.CELLULAR_PREFERRED;
+ private static final int DEFAULT_CELLULAR_NETWORK_TYPE = QnsProtoEnums.EUTRAN;
+ private static final int DEFAULT_IWLAN_NETWORK_TYPE = QnsProtoEnums.IWLAN_NETWORK_TYPE_WIFI;
+ private static final int DEFAULT_RESTRICTIONS_ON_WWAN = QnsProtoEnums.RESTRICT_TYPE_NONE;
+ private static final int DEFAULT_RESTRICTIONS_ON_WLAN = QnsProtoEnums.RESTRICT_TYPE_NONE;
+ private static final int DEFAULT_SIGNAL_STRENGTH = -100;
+ private static final int DEFAULT_SIGNAL_QUALITY = -10;
+ private static final int DEFAULT_SIGNAL_NOISE = -1;
+ private static final int DEFAULT_IWLAN_SIGNAL_STRENGTH = -70;
+ private static final int DEFAULT_UPDATE_REASON = 0;
+
+ private AtomsQualifiedRatListChangedInfo mInfoEmpty;
+ private AtomsQualifiedRatListChangedInfo mInfoDefault;
+ private AtomsQualifiedRatListChangedInfo mInfoCopy;
+
+ /** atom #1 : NetCapability of this Qualified RAT update */
+ private int mNetCapability;
+ /** atom #2 : The most preferred qualified RAT */
+ private int mFirstQualifiedRat;
+ /** atom #3 : Second preferred qualified RAT */
+ private int mSecondQualifiedRat;
+ /** atom #4 : Current actual transport type of Data session for this NetCapability */
+ private int mCurrentTransportType;
+ /** atom #5 : Indicates whether WFC is enabled */
+ private boolean mWfcEnabled;
+ /** atom #6 : Indicates the user's WFC mode */
+ private int mWfcMode;
+ /** atom #7 : Current Cellular AccessNetwork Type */
+ private int mCellularNetworkType;
+ /** atom #8 : Available IWLAN AccessNetwork */
+ private int mIwlanNetworkType;
+ /** atom #9 : Bit mask of restrictions on WWAN */
+ private int mRestrictionsOnWwan;
+ /** atom #10 : Bit mask of restrictions on WLAN */
+ private int mRestrictionsOnWlan;
+ /**
+ * atom #11 : Cellular network signal strength {e.g. SSRSRP in NR, RSRP in LTE, RSCP in UMTS}
+ */
+ private int mSignalStrength;
+ /** atom #12 : Cellular network signal quality {e.g. SSRSRQ in NR, RSRQ in LTE} */
+ private int mSignalQuality;
+ /** atom #13 : Cellular network signal noise ratio {e.g. SSSINR in NR, RSSNR in LTE} */
+ private int mSignalNoise;
+ /** atom #14 : Iwlan network signal strength (Wi-Fi RSSI) */
+ private int mIwlanSignalStrength;
+ /** atom #15 : Reason for preferred RAT update */
+ private int mUpdateReason;
+ /** atom #16: IMS Call Type */
+ private int mImsCallType;
+ /** atom #17 : IMS Call Quality */
+ private int mImsCallQuality;
+ /** atom #18 : Slot Index */
+ private int mSlotIndex;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mNetCapability = DEFAULT_NET_CAPABILITY;
+ mFirstQualifiedRat = DEFAULT_FIRST_QUALIFIED_RAT;
+ mSecondQualifiedRat = DEFAULT_SECOND_QUALIFIED_RAT;
+ mCurrentTransportType = DEFAULT_CURRENT_TRANSPORT_TYPE;
+ mWfcEnabled = DEFAULT_WFC_ENABLED;
+ mWfcMode = DEFAULT_WFC_MODE;
+ mCellularNetworkType = DEFAULT_CELLULAR_NETWORK_TYPE;
+ mIwlanNetworkType = DEFAULT_IWLAN_NETWORK_TYPE;
+ mRestrictionsOnWwan = DEFAULT_RESTRICTIONS_ON_WWAN;
+ mRestrictionsOnWlan = DEFAULT_RESTRICTIONS_ON_WLAN;
+ mSignalStrength = DEFAULT_SIGNAL_STRENGTH;
+ mSignalQuality = DEFAULT_SIGNAL_QUALITY;
+ mSignalNoise = DEFAULT_SIGNAL_NOISE;
+ mIwlanSignalStrength = DEFAULT_IWLAN_SIGNAL_STRENGTH;
+ mUpdateReason = DEFAULT_UPDATE_REASON;
+ mImsCallType = 1;
+ mImsCallQuality = 0;
+ mSlotIndex = 0;
+ mInfoEmpty = new AtomsQualifiedRatListChangedInfo();
+ mInfoDefault =
+ new AtomsQualifiedRatListChangedInfo(
+ mNetCapability,
+ mFirstQualifiedRat,
+ mSecondQualifiedRat,
+ mCurrentTransportType,
+ mWfcEnabled,
+ mWfcMode,
+ mCellularNetworkType,
+ mIwlanNetworkType,
+ mRestrictionsOnWwan,
+ mRestrictionsOnWlan,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mUpdateReason,
+ mImsCallType,
+ mImsCallQuality,
+ mSlotIndex);
+ mInfoCopy = new AtomsQualifiedRatListChangedInfo(mInfoDefault);
+ }
+
+ @After
+ public void tearDown() {
+ mInfoEmpty = null;
+ mInfoDefault = null;
+ mInfoCopy = null;
+ }
+
+ @Test
+ public void testGetSetNetCapability() {
+ assertEquals(0, mInfoEmpty.getNetCapability());
+ assertEquals(DEFAULT_NET_CAPABILITY, mInfoDefault.getNetCapability());
+ assertEquals(DEFAULT_NET_CAPABILITY, mInfoCopy.getNetCapability());
+
+ mInfoEmpty.setNetCapability(QnsProtoEnums.NET_CAPABILITY_IMS);
+ mInfoDefault.setNetCapability(QnsProtoEnums.NET_CAPABILITY_EIMS);
+ mInfoCopy.setNetCapability(QnsProtoEnums.NET_CAPABILITY_XCAP);
+
+ assertEquals(QnsProtoEnums.NET_CAPABILITY_IMS, mInfoEmpty.getNetCapability());
+ assertEquals(QnsProtoEnums.NET_CAPABILITY_EIMS, mInfoDefault.getNetCapability());
+ assertEquals(QnsProtoEnums.NET_CAPABILITY_XCAP, mInfoCopy.getNetCapability());
+ }
+
+ @Test
+ public void testGetSetFirstQualifiedRat() {
+ assertEquals(0, mInfoEmpty.getFirstQualifiedRat());
+ assertEquals(DEFAULT_FIRST_QUALIFIED_RAT, mInfoDefault.getFirstQualifiedRat());
+ assertEquals(DEFAULT_FIRST_QUALIFIED_RAT, mInfoCopy.getFirstQualifiedRat());
+
+ mInfoEmpty.setFirstQualifiedRat(QnsProtoEnums.IWLAN);
+ mInfoDefault.setFirstQualifiedRat(QnsProtoEnums.EUTRAN);
+ mInfoCopy.setFirstQualifiedRat(QnsProtoEnums.NGRAN);
+
+ assertEquals(QnsProtoEnums.IWLAN, mInfoEmpty.getFirstQualifiedRat());
+ assertEquals(QnsProtoEnums.EUTRAN, mInfoDefault.getFirstQualifiedRat());
+ assertEquals(QnsProtoEnums.NGRAN, mInfoCopy.getFirstQualifiedRat());
+ }
+
+ @Test
+ public void testGetSetSecondQualifiedRat() {
+ assertEquals(0, mInfoEmpty.getSecondQualifiedRat());
+ assertEquals(DEFAULT_SECOND_QUALIFIED_RAT, mInfoDefault.getSecondQualifiedRat());
+ assertEquals(DEFAULT_SECOND_QUALIFIED_RAT, mInfoCopy.getSecondQualifiedRat());
+
+ mInfoEmpty.setSecondQualifiedRat(QnsProtoEnums.IWLAN);
+ mInfoDefault.setSecondQualifiedRat(QnsProtoEnums.EUTRAN);
+ mInfoCopy.setSecondQualifiedRat(QnsProtoEnums.NGRAN);
+
+ assertEquals(QnsProtoEnums.IWLAN, mInfoEmpty.getSecondQualifiedRat());
+ assertEquals(QnsProtoEnums.EUTRAN, mInfoDefault.getSecondQualifiedRat());
+ assertEquals(QnsProtoEnums.NGRAN, mInfoCopy.getSecondQualifiedRat());
+ }
+
+ @Test
+ public void testGetSetCurrentTransportType() {
+ assertEquals(0, mInfoEmpty.getCurrentTransportType());
+ assertEquals(DEFAULT_CURRENT_TRANSPORT_TYPE, mInfoDefault.getCurrentTransportType());
+ assertEquals(DEFAULT_CURRENT_TRANSPORT_TYPE, mInfoCopy.getCurrentTransportType());
+
+ mInfoEmpty.setCurrentTransportType(QnsProtoEnums.TRANSPORT_TYPE_INVALID);
+ mInfoDefault.setCurrentTransportType(QnsProtoEnums.TRANSPORT_TYPE_WWAN);
+ mInfoCopy.setCurrentTransportType(QnsProtoEnums.TRANSPORT_TYPE_WLAN);
+
+ assertEquals(QnsProtoEnums.TRANSPORT_TYPE_INVALID, mInfoEmpty.getCurrentTransportType());
+ assertEquals(QnsProtoEnums.TRANSPORT_TYPE_WWAN, mInfoDefault.getCurrentTransportType());
+ assertEquals(QnsProtoEnums.TRANSPORT_TYPE_WLAN, mInfoCopy.getCurrentTransportType());
+ }
+
+ @Test
+ public void testGetSetWfcEnabled() {
+ assertFalse(mInfoEmpty.getWfcEnabled());
+ assertTrue(mInfoDefault.getWfcEnabled());
+ assertTrue(mInfoCopy.getWfcEnabled());
+
+ mInfoEmpty.setWfcEnabled(true);
+ mInfoDefault.setWfcEnabled(true);
+ mInfoCopy.setWfcEnabled(true);
+
+ assertTrue(mInfoEmpty.getWfcEnabled());
+ assertTrue(mInfoDefault.getWfcEnabled());
+ assertTrue(mInfoCopy.getWfcEnabled());
+ }
+
+ @Test
+ public void testGetSetWfcMode() {
+ assertEquals(0, mInfoEmpty.getWfcMode());
+ assertEquals(DEFAULT_WFC_MODE, mInfoDefault.getWfcMode());
+ assertEquals(DEFAULT_WFC_MODE, mInfoCopy.getWfcMode());
+
+ mInfoEmpty.setWfcMode(QnsProtoEnums.CELLULAR_PREFERRED);
+ mInfoDefault.setWfcMode(QnsProtoEnums.WIFI_ONLY);
+ mInfoCopy.setWfcMode(QnsProtoEnums.WIFI_PREFERRED);
+
+ assertEquals(QnsProtoEnums.CELLULAR_PREFERRED, mInfoEmpty.getWfcMode());
+ assertEquals(QnsProtoEnums.WIFI_ONLY, mInfoDefault.getWfcMode());
+ assertEquals(QnsProtoEnums.WIFI_PREFERRED, mInfoCopy.getWfcMode());
+ }
+
+ @Test
+ public void testGetSetCellularNetworkType() {
+ assertEquals(0, mInfoEmpty.getCellularNetworkType());
+ assertEquals(DEFAULT_CELLULAR_NETWORK_TYPE, mInfoDefault.getCellularNetworkType());
+ assertEquals(DEFAULT_CELLULAR_NETWORK_TYPE, mInfoCopy.getCellularNetworkType());
+
+ mInfoEmpty.setCellularNetworkType(QnsProtoEnums.EUTRAN);
+ mInfoDefault.setCellularNetworkType(QnsProtoEnums.NGRAN);
+ mInfoCopy.setCellularNetworkType(QnsProtoEnums.UTRAN);
+
+ assertEquals(QnsProtoEnums.EUTRAN, mInfoEmpty.getCellularNetworkType());
+ assertEquals(QnsProtoEnums.NGRAN, mInfoDefault.getCellularNetworkType());
+ assertEquals(QnsProtoEnums.UTRAN, mInfoCopy.getCellularNetworkType());
+ }
+
+ @Test
+ public void testGetSetIwlanNetworkType() {
+ assertEquals(0, mInfoEmpty.getIwlanNetworkType());
+ assertEquals(DEFAULT_IWLAN_NETWORK_TYPE, mInfoDefault.getIwlanNetworkType());
+ assertEquals(DEFAULT_IWLAN_NETWORK_TYPE, mInfoCopy.getIwlanNetworkType());
+
+ mInfoEmpty.setIwlanNetworkType(QnsProtoEnums.EUTRAN);
+ mInfoDefault.setIwlanNetworkType(QnsProtoEnums.NGRAN);
+ mInfoCopy.setIwlanNetworkType(QnsProtoEnums.UTRAN);
+
+ assertEquals(QnsProtoEnums.EUTRAN, mInfoEmpty.getIwlanNetworkType());
+ assertEquals(QnsProtoEnums.NGRAN, mInfoDefault.getIwlanNetworkType());
+ assertEquals(QnsProtoEnums.UTRAN, mInfoCopy.getIwlanNetworkType());
+ }
+
+ @Test
+ public void testGetSetRestrictionsOnWwan() {
+ assertEquals(0, mInfoEmpty.getRestrictionsOnWwan());
+ assertEquals(DEFAULT_RESTRICTIONS_ON_WWAN, mInfoDefault.getRestrictionsOnWwan());
+ assertEquals(DEFAULT_RESTRICTIONS_ON_WWAN, mInfoCopy.getRestrictionsOnWwan());
+
+ mInfoEmpty.setRestrictionsOnWwan(QnsProtoEnums.RESTRICT_TYPE_GUARDING);
+ mInfoDefault.setRestrictionsOnWwan(QnsProtoEnums.RESTRICT_TYPE_THROTTLING);
+ mInfoCopy.setRestrictionsOnWwan(QnsProtoEnums.RESTRICT_TYPE_NONE);
+
+ assertEquals(QnsProtoEnums.RESTRICT_TYPE_GUARDING, mInfoEmpty.getRestrictionsOnWwan());
+ assertEquals(QnsProtoEnums.RESTRICT_TYPE_THROTTLING, mInfoDefault.getRestrictionsOnWwan());
+ assertEquals(QnsProtoEnums.RESTRICT_TYPE_NONE, mInfoCopy.getRestrictionsOnWwan());
+ }
+
+ @Test
+ public void testGetSetRestrictionsOnWlan() {
+ assertEquals(0, mInfoEmpty.getRestrictionsOnWlan());
+ assertEquals(DEFAULT_RESTRICTIONS_ON_WWAN, mInfoDefault.getRestrictionsOnWlan());
+ assertEquals(DEFAULT_RESTRICTIONS_ON_WWAN, mInfoCopy.getRestrictionsOnWlan());
+
+ mInfoEmpty.setRestrictionsOnWlan(QnsProtoEnums.RESTRICT_TYPE_GUARDING);
+ mInfoDefault.setRestrictionsOnWlan(QnsProtoEnums.RESTRICT_TYPE_THROTTLING);
+ mInfoCopy.setRestrictionsOnWlan(QnsProtoEnums.RESTRICT_TYPE_NONE);
+
+ assertEquals(QnsProtoEnums.RESTRICT_TYPE_GUARDING, mInfoEmpty.getRestrictionsOnWlan());
+ assertEquals(QnsProtoEnums.RESTRICT_TYPE_THROTTLING, mInfoDefault.getRestrictionsOnWlan());
+ assertEquals(QnsProtoEnums.RESTRICT_TYPE_NONE, mInfoCopy.getRestrictionsOnWlan());
+ }
+
+ @Test
+ public void testGetSetSignalStrength() {
+ assertEquals(0, mInfoEmpty.getSignalStrength());
+ assertEquals(DEFAULT_SIGNAL_STRENGTH, mInfoDefault.getSignalStrength());
+ assertEquals(DEFAULT_SIGNAL_STRENGTH, mInfoCopy.getSignalStrength());
+
+ mInfoEmpty.setSignalStrength(DEFAULT_SIGNAL_STRENGTH);
+ mInfoDefault.setSignalStrength(-120);
+ mInfoCopy.setSignalStrength(-110);
+
+ assertEquals(DEFAULT_SIGNAL_STRENGTH, mInfoEmpty.getSignalStrength());
+ assertEquals(-120, mInfoDefault.getSignalStrength());
+ assertEquals(-110, mInfoCopy.getSignalStrength());
+ }
+
+ @Test
+ public void testGetSetSignalQuality() {
+ assertEquals(0, mInfoEmpty.getSignalQuality());
+ assertEquals(DEFAULT_SIGNAL_QUALITY, mInfoDefault.getSignalQuality());
+ assertEquals(DEFAULT_SIGNAL_QUALITY, mInfoCopy.getSignalQuality());
+
+ mInfoEmpty.setSignalQuality(DEFAULT_SIGNAL_QUALITY);
+ mInfoDefault.setSignalQuality(-10);
+ mInfoCopy.setSignalQuality(-5);
+
+ assertEquals(DEFAULT_SIGNAL_QUALITY, mInfoEmpty.getSignalQuality());
+ assertEquals(-10, mInfoDefault.getSignalQuality());
+ assertEquals(-5, mInfoCopy.getSignalQuality());
+ }
+
+ @Test
+ public void testGetSetSignalNoise() {
+ assertEquals(0, mInfoEmpty.getSignalNoise());
+ assertEquals(DEFAULT_SIGNAL_NOISE, mInfoDefault.getSignalNoise());
+ assertEquals(DEFAULT_SIGNAL_NOISE, mInfoCopy.getSignalNoise());
+
+ mInfoEmpty.setSignalNoise(DEFAULT_SIGNAL_NOISE);
+ mInfoDefault.setSignalNoise(1);
+ mInfoCopy.setSignalNoise(-1);
+
+ assertEquals(DEFAULT_SIGNAL_NOISE, mInfoEmpty.getSignalNoise());
+ assertEquals(1, mInfoDefault.getSignalNoise());
+ assertEquals(-1, mInfoCopy.getSignalNoise());
+ }
+
+ @Test
+ public void testGetSetIwlanSignalStrength() {
+ assertEquals(0, mInfoEmpty.getIwlanSignalStrength());
+ assertEquals(DEFAULT_IWLAN_SIGNAL_STRENGTH, mInfoDefault.getIwlanSignalStrength());
+ assertEquals(DEFAULT_IWLAN_SIGNAL_STRENGTH, mInfoCopy.getIwlanSignalStrength());
+
+ mInfoEmpty.setIwlanSignalStrength(DEFAULT_IWLAN_SIGNAL_STRENGTH);
+ mInfoDefault.setIwlanSignalStrength(-80);
+ mInfoCopy.setIwlanSignalStrength(-50);
+
+ assertEquals(DEFAULT_IWLAN_SIGNAL_STRENGTH, mInfoEmpty.getIwlanSignalStrength());
+ assertEquals(-80, mInfoDefault.getIwlanSignalStrength());
+ assertEquals(-50, mInfoCopy.getIwlanSignalStrength());
+ }
+
+ @Test
+ public void testGetSetUpdateReason() {
+ assertEquals(0, mInfoEmpty.getUpdateReason());
+ assertEquals(DEFAULT_UPDATE_REASON, mInfoDefault.getUpdateReason());
+ assertEquals(DEFAULT_UPDATE_REASON, mInfoCopy.getUpdateReason());
+
+ mInfoEmpty.setUpdateReason(0);
+ mInfoDefault.setUpdateReason(0);
+ mInfoCopy.setUpdateReason(0);
+
+ assertEquals(0, mInfoEmpty.getUpdateReason());
+ assertEquals(0, mInfoDefault.getUpdateReason());
+ assertEquals(0, mInfoCopy.getUpdateReason());
+ }
+
+ @Test
+ public void testGetSetImsCallType() {
+ assertEquals(0, mInfoEmpty.getImsCallType());
+ assertEquals(1, mInfoDefault.getImsCallType());
+ assertEquals(1, mInfoCopy.getImsCallType());
+
+ mInfoEmpty.setImsCallType(1);
+ mInfoDefault.setImsCallType(2);
+ mInfoCopy.setImsCallType(3);
+
+ assertEquals(1, mInfoEmpty.getImsCallType());
+ assertEquals(2, mInfoDefault.getImsCallType());
+ assertEquals(3, mInfoCopy.getImsCallType());
+ }
+
+ @Test
+ public void testGetSetImsCallQuality() {
+ assertEquals(0, mInfoEmpty.getImsCallQuality());
+ assertEquals(0, mInfoDefault.getImsCallQuality());
+ assertEquals(0, mInfoCopy.getImsCallQuality());
+
+ mInfoEmpty.setImsCallQuality(1);
+ mInfoDefault.setImsCallQuality(2);
+ mInfoCopy.setImsCallQuality(3);
+
+ assertEquals(1, mInfoEmpty.getImsCallQuality());
+ assertEquals(2, mInfoDefault.getImsCallQuality());
+ assertEquals(3, mInfoCopy.getImsCallQuality());
+ }
+
+ @Test
+ public void testGetSetSlotIndex() {
+ assertEquals(0, mInfoEmpty.getSlotIndex());
+ assertEquals(0, mInfoDefault.getSlotIndex());
+ assertEquals(0, mInfoCopy.getSlotIndex());
+
+ mInfoEmpty.setSlotIndex(1);
+ mInfoDefault.setSlotIndex(2);
+ mInfoCopy.setSlotIndex(3);
+
+ assertEquals(1, mInfoEmpty.getSlotIndex());
+ assertEquals(2, mInfoDefault.getSlotIndex());
+ assertEquals(3, mInfoCopy.getSlotIndex());
+ }
+
+ @Test
+ public void testToString() {
+ String strInfoEmpty = mInfoEmpty.toString();
+ String strInfoDefault = mInfoDefault.toString();
+ String strInfoCopy = mInfoCopy.toString();
+
+ assertNotNull(strInfoEmpty);
+ assertNotNull(strInfoDefault);
+ assertNotNull(strInfoCopy);
+
+ assertTrue(strInfoDefault.startsWith("AtomsQualifiedRatListChangedInfo"));
+
+ assertEquals(strInfoDefault, strInfoCopy);
+ assertNotEquals(strInfoEmpty, strInfoDefault);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(mInfoDefault, mInfoDefault);
+ assertNotEquals(mInfoDefault, new Object());
+ assertEquals(mInfoDefault, mInfoCopy);
+ mInfoDefault.setWfcEnabled(true);
+ mInfoCopy.setWfcEnabled(false);
+ assertNotEquals(mInfoDefault, mInfoCopy);
+ }
+
+ @Test
+ public void testHashCode() {
+ AtomsQualifiedRatListChangedInfo a1, a2;
+
+ a1 =
+ new AtomsQualifiedRatListChangedInfo(
+ mNetCapability,
+ mFirstQualifiedRat,
+ mSecondQualifiedRat,
+ mCurrentTransportType,
+ mWfcEnabled,
+ mWfcMode,
+ mCellularNetworkType,
+ mIwlanNetworkType,
+ mRestrictionsOnWwan,
+ mRestrictionsOnWlan,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mUpdateReason,
+ mImsCallType,
+ mImsCallQuality,
+ mSlotIndex);
+ a2 =
+ new AtomsQualifiedRatListChangedInfo(
+ mNetCapability,
+ mSecondQualifiedRat,
+ mFirstQualifiedRat,
+ mCurrentTransportType,
+ mWfcEnabled,
+ mWfcMode,
+ mCellularNetworkType,
+ mIwlanNetworkType,
+ mRestrictionsOnWwan,
+ mRestrictionsOnWlan,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mUpdateReason,
+ mImsCallType,
+ mImsCallQuality,
+ mSlotIndex);
+ assertNotEquals(a1.hashCode(), a2.hashCode());
+ a2 =
+ new AtomsQualifiedRatListChangedInfo(
+ mNetCapability,
+ mFirstQualifiedRat,
+ mSecondQualifiedRat,
+ mCurrentTransportType,
+ mWfcEnabled,
+ mWfcMode,
+ mCellularNetworkType,
+ mIwlanNetworkType,
+ mRestrictionsOnWwan,
+ mRestrictionsOnWlan,
+ mSignalStrength,
+ mSignalQuality,
+ mSignalNoise,
+ mIwlanSignalStrength,
+ mUpdateReason,
+ mImsCallType,
+ mImsCallQuality,
+ mSlotIndex);
+ assertEquals(a1.hashCode(), a2.hashCode());
+ }
+
+ @Test
+ public void testStatsId() {
+ final int statsId = 634; // QualifiedRatListChanged
+ assertEquals(statsId, mInfoDefault.copy().getStatsId());
+ }
+
+ @Test
+ public void testStatsEventBuilder() {
+ mInfoDefault.build(mStatsEventBuilder);
+
+ verify(mStatsEventBuilder, times(1)).writeBoolean(anyBoolean());
+ verify(mStatsEventBuilder, times(17)).writeInt(anyInt());
+ }
+}