blob: 6328fec3ca23311cb1edfd2e46882b5bf0bea131 [file] [log] [blame]
/*
* 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.qns;
import static android.telephony.ServiceState.ROAMING_TYPE_DOMESTIC;
import static android.telephony.ServiceState.ROAMING_TYPE_INTERNATIONAL;
import android.content.Context;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.RegistrantList;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.ims.ProvisioningManager;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.qns.AccessNetworkSelectionPolicy.GuardingPreCondition;
import com.android.qns.AccessNetworkSelectionPolicy.PreCondition;
import com.android.qns.IwlanNetworkStatusTracker.IwlanAvailabilityInfo;
import com.android.qns.QualifiedNetworksServiceImpl.QualifiedNetworksInfo;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
/**
* AccessNetworkEvaluator evaluates prioritized AccessNetwork list base on Cellular/Wi-Fi network
* status and configurations from carrier/user.
*/
public class AccessNetworkEvaluator {
private static final boolean DBG = true;
private static final int EVENT_BASE = 10000;
private static final int EVENT_IWLAN_NETWORK_STATUS_CHANGED = EVENT_BASE;
private static final int EVENT_QNS_TELEPHONY_INFO_CHANGED = EVENT_BASE + 1;
private static final int EVENT_RESTRICT_INFO_CHANGED = EVENT_BASE + 4;
private static final int EVENT_SET_CALL_TYPE = EVENT_BASE + 5;
private static final int EVENT_DATA_CONNECTION_STATE_CHANGED = EVENT_BASE + 6;
private static final int EVENT_EMERGENCY_PREFERRED_TRANSPORT_TYPE_CHANGED = EVENT_BASE + 7;
private static final int EVENT_PROVISIONING_INFO_CHANGED = EVENT_BASE + 8;
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 EVALUATE_SPECIFIC_REASON_NONE = 0;
private static final int EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE = 1;
protected final int mSlotIndex;
protected final Context mContext;
private final String LOG_TAG;
private final int mApnType;
@VisibleForTesting protected final Handler mHandler;
private final HandlerThread mHandlerThread;
private final RestrictManager mRestrictManager;
protected QnsCarrierConfigManager mConfigManager;
protected QualityMonitor mWifiQualityMonitor;
protected QualityMonitor mCellularQualityMonitor;
protected CellularNetworkStatusTracker mCellularNetworkStatusTracker;
protected IwlanNetworkStatusTracker mIwlanNetworkStatusTracker;
protected DataConnectionStatusTracker mDataConnectionStatusTracker;
protected QnsEventDispatcher mQnsEventDispatcher;
protected AlternativeEventListener mAltEventListener;
protected QnsProvisioningListener mQnsProvisioningListener;
protected ImsStatusListener mImsStatusListener;
protected int mCellularAccessNetworkType = AccessNetworkType.UNKNOWN;
protected boolean mCellularAvailable = false;
protected boolean mIwlanAvailable = false;
private boolean mIsCrossWfc = false;
protected RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList();
// pre-conditions
private int mCallType;
private int mCoverage;
private int mLatestAvailableCellularAccessNetwork = AccessNetworkType.UNKNOWN;
private List<AccessNetworkSelectionPolicy> mAccessNetworkSelectionPolicies = new ArrayList<>();
private List<Integer> mLastQualifiedAccessNetworkTypes;
private boolean mIsNotifiedLastQualifiedAccessNetworkTypes = false;
private boolean mWfcPlatformEnabled = false;
private boolean mSettingWfcEnabled = false;
private int mSettingWfcMode = QnsConstants.CELL_PREF;
private boolean mSettingWfcRoamingEnabled = false;
private int mSettingWfcRoamingMode = QnsConstants.WIFI_PREF;
private boolean mAllowIwlanForWfcActivation = false;
private Map<PreCondition, List<AccessNetworkSelectionPolicy>> mAnspPolicyMap = null;
private ThresholdListener listener;
private boolean mInitialized = false;
private QnsProvisioningListener.QnsProvisioningInfo mLastProvisioningInfo =
new QnsProvisioningListener.QnsProvisioningInfo();
public AccessNetworkEvaluator(int slotIndex, int apnType, Context context) {
LOG_TAG =
QnsConstants.QNS_TAG
+ "_"
+ AccessNetworkEvaluator.class.getSimpleName()
+ "_"
+ slotIndex
+ "_"
+ QnsUtils.getStringApnTypes(apnType);
// load configurations & sort by purpose.
mSlotIndex = slotIndex;
mApnType = apnType;
mContext = context;
log("created AccessNetworkEvaluator");
// make handler to handle events for evaluate available AccessNetworks.
mHandlerThread = new HandlerThread(AccessNetworkEvaluator.class.getSimpleName() + mApnType);
mHandlerThread.start();
mHandler = new EvaluatorEventHandler(mHandlerThread.getLooper());
Executor executor = new HandlerExecutor(mHandler);
mConfigManager = QnsCarrierConfigManager.getInstance(context, slotIndex);
mAltEventListener = AlternativeEventListener.getInstance(context, slotIndex);
mQnsProvisioningListener = QnsProvisioningListener.getInstance(context, slotIndex);
mIwlanNetworkStatusTracker = IwlanNetworkStatusTracker.getInstance(context);
mDataConnectionStatusTracker =
new DataConnectionStatusTracker(
mContext, mHandlerThread.getLooper(), mSlotIndex, mApnType);
mImsStatusListener = ImsStatusListener.getInstance(context, slotIndex);
// Pre-Conditions
mCellularNetworkStatusTracker =
CellularNetworkStatusTracker.getInstance(context, slotIndex);
mQnsEventDispatcher = QnsEventDispatcher.getInstance(context, slotIndex);
listener = new ThresholdListener(executor);
// Post-Conditions
mWifiQualityMonitor =
QualityMonitor.getInstance(
context, AccessNetworkConstants.TRANSPORT_TYPE_WLAN, slotIndex);
mCellularQualityMonitor =
QualityMonitor.getInstance(
context, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, slotIndex);
// Evaluates
mRestrictManager =
new RestrictManager(
mContext,
mHandler.getLooper(),
mSlotIndex,
mApnType,
mDataConnectionStatusTracker);
mHandler.post(() -> buildAccessNetworkSelectionPolicy(false));
initLastNotifiedQualifiedNetwork();
initSettings();
registerListeners();
}
@VisibleForTesting
public AccessNetworkEvaluator(
int slotIndex,
int apnType,
Context context,
RestrictManager restrictManager,
QnsCarrierConfigManager configManager,
QualityMonitor wifiQualityMonitor,
QualityMonitor cellularQualityMonitor,
CellularNetworkStatusTracker cellularNetworkStatusTracker,
IwlanNetworkStatusTracker iwlanNetworkStatusTracker,
DataConnectionStatusTracker dataConnectionStatusTracker,
QnsEventDispatcher qnsEventDispatcher,
AlternativeEventListener altEventListener,
QnsProvisioningListener qnsProvisioningListener,
ImsStatusListener qnsImsStateListener) {
LOG_TAG =
QnsConstants.QNS_TAG
+ "_"
+ AccessNetworkEvaluator.class.getSimpleName()
+ "_"
+ slotIndex
+ "_"
+ QnsUtils.getStringApnTypes(apnType);
// load configurations & sort by purpose.
mSlotIndex = slotIndex;
mApnType = apnType;
mContext = context;
mRestrictManager = restrictManager;
mConfigManager = configManager;
mWifiQualityMonitor = wifiQualityMonitor;
mCellularQualityMonitor = cellularQualityMonitor;
mCellularNetworkStatusTracker = cellularNetworkStatusTracker;
mIwlanNetworkStatusTracker = iwlanNetworkStatusTracker;
mDataConnectionStatusTracker = dataConnectionStatusTracker;
mQnsEventDispatcher = qnsEventDispatcher;
mAltEventListener = altEventListener;
mQnsProvisioningListener = qnsProvisioningListener;
mImsStatusListener = qnsImsStateListener;
mHandlerThread = new HandlerThread(AccessNetworkEvaluator.class.getSimpleName() + mApnType);
mHandlerThread.start();
mHandler = new EvaluatorEventHandler(mHandlerThread.getLooper());
mHandler.post(() -> buildAccessNetworkSelectionPolicy(false));
initLastNotifiedQualifiedNetwork();
initSettings();
registerListeners();
}
public void rebuild() {
log("rebuild");
initSettings();
mLastProvisioningInfo.clear();
mConfigManager.setQnsProvisioningInfo(mLastProvisioningInfo);
mHandler.post(() -> buildAccessNetworkSelectionPolicy(true));
mRestrictManager.clearRestrictions();
reportQualifiedNetwork(getInitialAccessNetworkTypes());
initLastNotifiedQualifiedNetwork();
unregisterThresholdToQualityMonitor();
}
public void close() {
log("close");
mHandlerThread.quitSafely();
notifyForQualifiedNetworksChanged(getInitialAccessNetworkTypes());
initLastNotifiedQualifiedNetwork();
unregisterListeners();
mQualifiedNetworksChangedRegistrants.removeAll();
mDataConnectionStatusTracker.close();
mRestrictManager.close();
}
public void registerForQualifiedNetworksChanged(Handler h, int what) {
mInitialized = true;
mQualifiedNetworksChangedRegistrants.addUnique(h, what, null);
if (isNotifiedQualifiedAccessNetworkTypes()) {
if (DBG) {
log(
"registerForQualifiedNetworksChanged, report:"
+ QnsUtils.getStringAccessNetworkTypes(
mLastQualifiedAccessNetworkTypes));
}
notifyForQualifiedNetworksChanged(mLastQualifiedAccessNetworkTypes);
}
mHandler.post(this::evaluate);
}
public void unregisterForQualifiedNetworksChanged(Handler h) {
mQualifiedNetworksChangedRegistrants.remove(h);
}
private List<Integer> getInitialAccessNetworkTypes() {
// The framework treats empty lists as WWAN.
return List.of();
}
protected int getLastQualifiedTransportType() {
if (mLastQualifiedAccessNetworkTypes.size() > 0
&& mLastQualifiedAccessNetworkTypes.get(0) == AccessNetworkType.IWLAN) {
return AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
}
// otherwise, returns WWAN. (includes an empty list)
return AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
}
protected boolean isNotifiedQualifiedAccessNetworkTypes() {
return mIsNotifiedLastQualifiedAccessNetworkTypes;
}
protected void initLastNotifiedQualifiedNetwork() {
mIsNotifiedLastQualifiedAccessNetworkTypes = false;
mLastQualifiedAccessNetworkTypes = getInitialAccessNetworkTypes();
log(
"initLastNotifiedQualifiedNetwork mLastQualifiedAccessNetworkTypes:"
+ QnsUtils.getStringAccessNetworkTypes(mLastQualifiedAccessNetworkTypes));
}
protected boolean equalsLastNotifiedQualifiedNetwork(List<Integer> accessNetworkTypes) {
return mLastQualifiedAccessNetworkTypes.equals(accessNetworkTypes);
}
protected void updateLastNotifiedQualifiedNetwork(List<Integer> accessNetworkTypes) {
mLastQualifiedAccessNetworkTypes = accessNetworkTypes;
mRestrictManager.updateLastNotifiedTransportType(getLastQualifiedTransportType());
log(
"updateLastNotifiedQualifiedNetwork mLastQualifiedAccessNetworkTypes:"
+ QnsUtils.getStringAccessNetworkTypes(mLastQualifiedAccessNetworkTypes));
}
protected void notifyForQualifiedNetworksChanged(List<Integer> accessNetworkTypes) {
mIsNotifiedLastQualifiedAccessNetworkTypes = true;
QualifiedNetworksInfo info = new QualifiedNetworksInfo(mApnType, accessNetworkTypes);
AsyncResult ar = new AsyncResult(null, info, null);
mQualifiedNetworksChangedRegistrants.notifyRegistrants(ar);
}
private void initSettings() {
mWfcPlatformEnabled = QnsUtils.isWfcEnabledByPlatform(mContext, mSlotIndex);
mSettingWfcEnabled = QnsUtils.isWfcEnabled(mContext, mSlotIndex, false);
mSettingWfcMode = QnsUtils.getWfcMode(mContext, mSlotIndex, false);
mSettingWfcRoamingEnabled = QnsUtils.isWfcEnabled(mContext, mSlotIndex, true);
mSettingWfcRoamingMode = QnsUtils.getWfcMode(mContext, mSlotIndex, true);
mAllowIwlanForWfcActivation = false;
log(
"WfcSettings. mWfcPlatformEnabled:"
+ mWfcPlatformEnabled
+ " WfcEnabled:"
+ mSettingWfcEnabled
+ " WfcMode:"
+ QnsConstants.preferenceToString(mSettingWfcMode)
+ " WfcRoamingEnabled:"
+ mSettingWfcRoamingEnabled
+ " WfcRoamingMode:"
+ QnsConstants.preferenceToString(mSettingWfcRoamingMode));
}
protected void registerListeners() {
log("registerListeners");
mWifiQualityMonitor.registerThresholdChange(listener, mApnType, null, mSlotIndex);
mCellularQualityMonitor.registerThresholdChange(listener, mApnType, null, mSlotIndex);
mIwlanNetworkStatusTracker.registerIwlanNetworksChanged(
mSlotIndex, mHandler, EVENT_IWLAN_NETWORK_STATUS_CHANGED);
mDataConnectionStatusTracker.registerDataConnectionStatusChanged(
mHandler, EVENT_DATA_CONNECTION_STATE_CHANGED);
mImsStatusListener.registerImsRegistrationStatusChanged(
mHandler, EVENT_IMS_REGISTRATION_STATE_CHANGED);
mCellularNetworkStatusTracker.registerQnsTelephonyInfoChanged(
mApnType, mHandler, EVENT_QNS_TELEPHONY_INFO_CHANGED);
if (mApnType == ApnSetting.TYPE_IMS || mApnType == ApnSetting.TYPE_EMERGENCY) {
mAltEventListener.registerCallTypeChangedListener(
mApnType, mHandler, EVENT_SET_CALL_TYPE, null);
}
if (mApnType == ApnSetting.TYPE_EMERGENCY) {
mAltEventListener.registerEmergencyPreferredTransportTypeChanged(
mHandler, EVENT_EMERGENCY_PREFERRED_TRANSPORT_TYPE_CHANGED, null);
}
if (mApnType == ApnSetting.TYPE_IMS) {
mAltEventListener.registerTryWfcConnectionStateListener(
mHandler, EVENT_WFC_ACTIVATION_WITH_IWLAN_CONNECTION_REQUIRED, null);
}
mQnsProvisioningListener.registerProvisioningItemInfoChanged(
mHandler, EVENT_PROVISIONING_INFO_CHANGED, null, true);
List<Integer> events = new ArrayList<>();
events.add(QnsEventDispatcher.QNS_EVENT_WFC_ENABLED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_DISABLED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_WIFI_ONLY);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_ENABLED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_DISABLED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_PLATFORM_ENABLED);
events.add(QnsEventDispatcher.QNS_EVENT_WFC_PLATFORM_DISABLED);
events.add(QnsEventDispatcher.QNS_EVENT_SIM_ABSENT);
mQnsEventDispatcher.registerEvent(events, mHandler);
mRestrictManager.registerRestrictInfoChanged(mHandler, EVENT_RESTRICT_INFO_CHANGED);
}
protected void unregisterListeners() {
log("unregisterListeners");
mWifiQualityMonitor.unregisterThresholdChange(mApnType, mSlotIndex);
mCellularQualityMonitor.unregisterThresholdChange(mApnType, mSlotIndex);
mDataConnectionStatusTracker.unRegisterDataConnectionStatusChanged(mHandler);
mImsStatusListener.unregisterImsRegistrationStatusChanged(mHandler);
mCellularNetworkStatusTracker.unregisterQnsTelephonyInfoChanged(mApnType, mHandler);
mIwlanNetworkStatusTracker.unregisterIwlanNetworksChanged(mSlotIndex, mHandler);
mAltEventListener.unregisterLowRtpQualityEvent(mApnType, mHandler);
if (mApnType == ApnSetting.TYPE_IMS || mApnType == ApnSetting.TYPE_EMERGENCY) {
mAltEventListener.unregisterCallTypeChangedListener(mApnType, mHandler);
}
if (mApnType == ApnSetting.TYPE_EMERGENCY) {
mAltEventListener.unregisterEmergencyPreferredTransportTypeChanged();
}
mQnsProvisioningListener.unregisterProvisioningItemInfoChanged(mHandler);
mQnsEventDispatcher.unregisterEvent(mHandler);
mRestrictManager.unRegisterRestrictInfoChanged(mHandler);
}
private boolean isIwlanAvailableWithoutRestrict() {
return (mIwlanAvailable
&& !mRestrictManager.isRestricted(AccessNetworkConstants.TRANSPORT_TYPE_WLAN));
}
private boolean isCellularAvailableWithoutRestrict() {
return (mCellularAvailable
&& !mRestrictManager.isRestricted(AccessNetworkConstants.TRANSPORT_TYPE_WWAN));
}
protected void log(String s) {
Log.d(LOG_TAG, s);
}
protected void onQnsTelephonyInfoChanged(QnsTelephonyListener.QnsTelephonyInfo info) {
boolean needEvaluate = false;
if (info instanceof QnsTelephonyListener.QnsTelephonyInfoIms) {
QnsTelephonyListener.QnsTelephonyInfoIms infoIms =
(QnsTelephonyListener.QnsTelephonyInfoIms) info;
boolean checkVoPs = false;
boolean volteRoamingSupported = true;
int cellularAccessNetworkType =
QnsUtils.getCellularAccessNetworkType(
infoIms.getDataRegState(), infoIms.getDataTech());
int coverage = getCoverage(infoIms, mApnType);
if (mApnType == ApnSetting.TYPE_IMS && infoIms.isCellularAvailable()) {
checkVoPs = vopsCheckRequired(cellularAccessNetworkType, coverage, mCallType);
volteRoamingSupported = mConfigManager.isVolteRoamingSupported(coverage);
}
boolean checkBarring = mConfigManager.isServiceBarringCheckSupported();
if (DBG) {
log(
"checkVoPs:"
+ checkVoPs
+ ", checkBarring:"
+ checkBarring
+ ", volteRoamingSupported:"
+ volteRoamingSupported);
}
boolean cellAvailable =
infoIms.isCellularAvailable(
mApnType, checkVoPs, checkBarring, volteRoamingSupported);
if (mCellularAvailable != cellAvailable) {
mCellularAvailable = cellAvailable;
needEvaluate = true;
log("onQnsTelephonyInfoChanged cellularAvailableIms:" + mCellularAvailable);
}
} else if (mCellularAvailable != info.isCellularAvailable()) {
mCellularAvailable = info.isCellularAvailable();
needEvaluate = true;
log("onQnsTelephonyInfoChanged cellularAvailable:" + mCellularAvailable);
}
if (mCellularAccessNetworkType
!= QnsUtils.getCellularAccessNetworkType(
info.getDataRegState(), info.getDataTech())) {
mCellularAccessNetworkType =
QnsUtils.getCellularAccessNetworkType(
info.getDataRegState(), info.getDataTech());
mRestrictManager.setCellularAccessNetwork(mCellularAccessNetworkType);
if (mCellularAccessNetworkType != AccessNetworkType.UNKNOWN) {
mLatestAvailableCellularAccessNetwork = mCellularAccessNetworkType;
}
needEvaluate = true;
log(
"onQnsTelephonyInfoChanged cellularAccessNetworkType:"
+ mCellularAccessNetworkType);
}
int coverage = getCoverage(info, mApnType);
if (mCoverage != coverage) {
mCoverage = coverage;
needEvaluate = true;
mRestrictManager.setCellularCoverage(mCoverage);
log("onQnsTelephonyInfoChanged Coverage:" + mCoverage);
}
if (needEvaluate) {
evaluate();
}
}
@VisibleForTesting
int getCoverage(QnsTelephonyListener.QnsTelephonyInfo info, int apnType) {
if (DBG) {
log(
"getCoverage roaming?"
+ info.isCoverage()
+ " roamingType:"
+ info.getRoamingType()
+ " registeredPlmn:"
+ info.getRegisteredPlmn());
}
if (info.isCoverage()) {
if (mConfigManager.needToCheckInternationalRoaming(apnType)) {
if (DBG) log("needToCheckInternationalRoaming : true ");
if (info.getRoamingType() == ROAMING_TYPE_INTERNATIONAL) {
if (mConfigManager.isDefinedDomesticRoamingPlmn(info.getRegisteredPlmn())) {
if (DBG) log("isDefinedDomesticRoamingPlmn : true ");
return QnsConstants.COVERAGE_HOME;
} else {
return QnsConstants.COVERAGE_ROAM;
}
} else if (info.getRoamingType() == ROAMING_TYPE_DOMESTIC) {
if (mConfigManager.isDefinedInternationalRoamingPlmn(
info.getRegisteredPlmn())) {
if (DBG) log("isDefinedInternationalRoamingPlmn : true");
return QnsConstants.COVERAGE_ROAM;
} else {
return QnsConstants.COVERAGE_HOME;
}
}
}
return QnsConstants.COVERAGE_ROAM;
} else {
return QnsConstants.COVERAGE_HOME;
}
}
protected void onIwlanNetworkStatusChanged(IwlanAvailabilityInfo info) {
if (info != null) {
mIwlanAvailable = info.getIwlanAvailable();
mIsCrossWfc = info.isCrossWfc();
log("onIwlanNetworkStatusChanged IwlanAvailable:" + mIwlanAvailable);
if (info.getNotifyIwlanDisabled()) {
evaluate(EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE);
} else {
evaluate();
}
}
}
private void onWfcEnabledChanged(boolean enabled, boolean roaming) {
StringBuilder sb = new StringBuilder("onWfcEnabledChanged");
sb.append(" enabled:").append(enabled);
sb.append(" coverage:")
.append(
QnsConstants.coverageToString(
roaming ? QnsConstants.COVERAGE_ROAM : QnsConstants.COVERAGE_HOME));
boolean needEvaluate = false;
if (!roaming && mSettingWfcEnabled != enabled) {
if (mCoverage == QnsConstants.COVERAGE_HOME) {
needEvaluate = true;
}
mSettingWfcEnabled = enabled;
sb.append(" mSettingWfcEnabled:").append(mSettingWfcEnabled);
} else if (roaming && mSettingWfcRoamingEnabled != enabled) {
if (mCoverage == QnsConstants.COVERAGE_ROAM) {
needEvaluate = true;
}
mSettingWfcRoamingEnabled = enabled;
sb.append(" mSettingWfcRoamingEnabled:").append(mSettingWfcRoamingEnabled);
}
if (needEvaluate) {
sb.append(" evaluate.");
log(sb.toString());
if (enabled) {
evaluate();
} else {
evaluate(EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE);
}
} else {
log(sb.toString());
}
}
private void onWfcModeChanged(int mode, boolean roaming) {
StringBuilder sb = new StringBuilder("onWfcModeChanged");
sb.append(" mode:").append(QnsConstants.preferenceToString(mode));
sb.append(" coverage:")
.append(
QnsConstants.coverageToString(
roaming ? QnsConstants.COVERAGE_ROAM : QnsConstants.COVERAGE_HOME));
boolean needEvaluate = false;
if (!roaming && mSettingWfcMode != mode) {
if (mCoverage == QnsConstants.COVERAGE_HOME) {
needEvaluate = true;
}
mSettingWfcMode = mode;
sb.append(" mSettingWfcMode:").append(QnsConstants.preferenceToString(mSettingWfcMode));
} else if (roaming && mSettingWfcRoamingMode != mode) {
if (mCoverage == QnsConstants.COVERAGE_ROAM) {
needEvaluate = true;
}
mSettingWfcRoamingMode = mode;
sb.append(" mSettingWfcRoamingMode:");
sb.append(QnsConstants.preferenceToString(mSettingWfcRoamingMode));
}
if (needEvaluate) {
sb.append(" evaluate.");
log(sb.toString());
evaluate();
} else {
log(sb.toString());
}
}
private void onWfcPlatformChanged(boolean bWfcPlatformEnabled) {
StringBuilder sb = new StringBuilder("onWfcPlatformChanged");
sb.append(" bWfcPlatformEnabled:").append(bWfcPlatformEnabled);
if (mWfcPlatformEnabled == bWfcPlatformEnabled) {
sb.append(" no changes");
log(sb.toString());
} else {
mWfcPlatformEnabled = bWfcPlatformEnabled;
if (bWfcPlatformEnabled) {
sb.append(" evaluate.");
log(sb.toString());
evaluate();
} else {
sb.append(" report cellular as qualified network directly.");
log(sb.toString());
reportQualifiedNetwork(new ArrayList<>(List.of(mCellularAccessNetworkType)));
}
}
}
private void onSimAbsent() {
log("onSimAbsent");
// report default qualified access network.
reportQualifiedNetwork(getInitialAccessNetworkTypes());
}
private void onRestrictInfoChanged() {
// TODO
log("onRestrictInfoChanged");
evaluate();
}
@VisibleForTesting
void onTryWfcConnectionStateChanged(boolean isEnabled) {
log("onTryWfcConnectionStateChanged enabled:" + isEnabled);
if (mAllowIwlanForWfcActivation == isEnabled) {
return;
}
mAllowIwlanForWfcActivation = isEnabled;
evaluate();
}
@VisibleForTesting
void onSetCallType(@QnsConstants.QnsCallType int callType) {
if (mApnType == ApnSetting.TYPE_IMS && callType == QnsConstants.CALL_TYPE_EMERGENCY) {
if (!mDataConnectionStatusTracker.isActiveState()) return;
}
mCallType = callType;
mRestrictManager.setQnsCallType(mCallType);
log("onSetCallType CallType:" + mCallType);
// call type from service manager API
// TODO
evaluate();
}
private void onEmergencyPreferredTransportTypeChanged(
@AccessNetworkConstants.TransportType int transport) {
if (mApnType != ApnSetting.TYPE_EMERGENCY) {
return;
}
log(
"onEmergencyPreferredTransportTypeChanged transport:"
+ QnsConstants.transportTypeToString(transport));
if (mDataConnectionStatusTracker.isInactiveState()) {
int accessNetwork;
List<Integer> accessNetworkTypes = new ArrayList<>();
if (transport == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
accessNetwork = AccessNetworkType.IWLAN;
accessNetworkTypes.add(accessNetwork);
} else {
accessNetwork = mCellularAccessNetworkType;
if (accessNetwork != AccessNetworkType.UNKNOWN) {
accessNetworkTypes.add(accessNetwork);
}
}
updateLastNotifiedQualifiedNetwork(accessNetworkTypes);
notifyForQualifiedNetworksChanged(accessNetworkTypes);
}
}
private void onDataConnectionStateChanged(
DataConnectionStatusTracker.DataConnectionChangedInfo info) {
log("onDataConnectionStateChanged info:" + info);
boolean needEvaluate = false;
switch (info.getEvent()) {
case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_DISCONNECTED:
needEvaluate = true;
initLastNotifiedQualifiedNetwork();
if (mApnType == ApnSetting.TYPE_IMS) {
if (mAltEventListener != null) mAltEventListener.clearNormalCallInfo();
}
mCallType = QnsConstants.CALL_TYPE_IDLE;
break;
case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_CONNECTED:
mHandler.post(() -> onDataConnectionConnected(info.getTransportType()));
break;
case DataConnectionStatusTracker.EVENT_DATA_CONNECTION_FAILED:
needEvaluate = true;
break;
}
if (needEvaluate) {
evaluate();
}
}
private void onDataConnectionConnected(int transportType) {
int otherTransportType;
if (DBG) {
log("onDataConnectionConnected :" + QnsConstants.transportTypeToString(transportType));
}
if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) {
log("Error: onDataConnectionConnected invalid transport type.");
return;
} else {
otherTransportType =
transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
? AccessNetworkConstants.TRANSPORT_TYPE_WWAN
: AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
}
if (!mRestrictManager.isRestricted(otherTransportType)) {
evaluate();
} // else case : evaluate() will process when restrictions released.
}
protected void onProvisioningInfoChanged(QnsProvisioningListener.QnsProvisioningInfo info) {
boolean needBuildAnsp = false;
boolean needEvaluate = false;
log("onProvisioningInfoChanged info:" + info);
if (!info.equalsIntegerItem(
mLastProvisioningInfo, ProvisioningManager.KEY_LTE_THRESHOLD_1)) {
log(
"onProvisioningInfoChanged, KEY_LTE_THRESHOLD_1("
+ ProvisioningManager.KEY_LTE_THRESHOLD_1
+ ") is provisioned to "
+ info.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_1));
mConfigManager.setQnsProvisioningInfo(info);
needBuildAnsp = true;
needEvaluate = true;
}
if (!info.equalsIntegerItem(
mLastProvisioningInfo, ProvisioningManager.KEY_LTE_THRESHOLD_2)) {
log(
"onProvisioningInfoChanged, KEY_LTE_THRESHOLD_2("
+ ProvisioningManager.KEY_LTE_THRESHOLD_2
+ ") is provisioned to "
+ info.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_2));
mConfigManager.setQnsProvisioningInfo(info);
needBuildAnsp = true;
needEvaluate = true;
}
if (!info.equalsIntegerItem(
mLastProvisioningInfo, ProvisioningManager.KEY_LTE_THRESHOLD_3)) {
log(
"onProvisioningInfoChanged, KEY_LTE_THRESHOLD_3("
+ ProvisioningManager.KEY_LTE_THRESHOLD_3
+ ") is provisioned to "
+ info.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_3));
mConfigManager.setQnsProvisioningInfo(info);
needBuildAnsp = true;
needEvaluate = true;
}
if (!info.equalsIntegerItem(
mLastProvisioningInfo, ProvisioningManager.KEY_WIFI_THRESHOLD_A)) {
log(
"onProvisioningInfoChanged, KEY_WIFI_THRESHOLD_A("
+ ProvisioningManager.KEY_WIFI_THRESHOLD_A
+ ") is provisioned to "
+ info.getIntegerItem(ProvisioningManager.KEY_WIFI_THRESHOLD_A));
mConfigManager.setQnsProvisioningInfo(info);
needBuildAnsp = true;
needEvaluate = true;
}
if (!info.equalsIntegerItem(
mLastProvisioningInfo, ProvisioningManager.KEY_WIFI_THRESHOLD_B)) {
log(
"onProvisioningInfoChanged, KEY_WIFI_THRESHOLD_B("
+ ProvisioningManager.KEY_WIFI_THRESHOLD_B
+ ") is provisioned to "
+ info.getIntegerItem(ProvisioningManager.KEY_WIFI_THRESHOLD_B));
mConfigManager.setQnsProvisioningInfo(info);
needBuildAnsp = true;
needEvaluate = true;
}
if (!info.equalsIntegerItem(
mLastProvisioningInfo, ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC)) {
log(
"onProvisioningInfoChanged, KEY_LTE_EPDG_TIMER_SEC("
+ ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC
+ ") is provisioned to "
+ info.getIntegerItem(ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC));
mConfigManager.setQnsProvisioningInfo(info);
needEvaluate = true;
}
if (!info.equalsIntegerItem(
mLastProvisioningInfo, ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC)) {
log(
"onProvisioningInfoChanged, KEY_WIFI_EPDG_TIMER_SEC("
+ ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC
+ ") is provisioned to "
+ info.getIntegerItem(ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC));
mConfigManager.setQnsProvisioningInfo(info);
needEvaluate = true;
}
mLastProvisioningInfo = info;
if (needBuildAnsp) {
buildAccessNetworkSelectionPolicy(true);
}
if (needEvaluate) {
evaluate();
}
/* TODO to be checked
ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS
ProvisioningManager.KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID
*/
}
private void onImsRegStateChanged(ImsStatusListener.ImsRegistrationChangedEv imsRegEvent) {
if (mConfigManager.getRatPreference(mApnType)
!= QnsConstants.RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE) {
return;
}
int transportType = imsRegEvent.getTransportType();
int event = imsRegEvent.getEvent();
if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
&& (event == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED
|| event == QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED)) {
log(
"onImsRegStateChanged, "
+ QnsConstants.transportTypeToString(transportType)
+ ","
+ QnsConstants.imsRegistrationEventToString(event));
evaluate();
}
}
protected void onCellularQualityChanged(Threshold[] ths) {
if (ths == null || ths.length == 0) {
log("onCellularQualityChanged: E threshold is null");
return;
}
log("onCellularQualityChanged Threshold:" + Arrays.toString(ths));
// TODO
evaluate();
}
protected void onWiFiQualityChanged(Threshold[] ths) {
if (ths == null || ths.length == 0) {
log("onCellularQualityChanged: E threshold is null");
return;
}
log("onWiFiQualityChanged Threshold:" + Arrays.toString(ths));
// TODO
evaluate();
}
protected boolean isWfcEnabled() {
// TODO remove for debug logging...
QnsUtils.isWfcEnabled(mContext, mSlotIndex, mCoverage == QnsConstants.COVERAGE_ROAM);
if (mAllowIwlanForWfcActivation) {
return true;
}
if (!mWfcPlatformEnabled) {
log("isWfcPlatformEnabled:false");
return false;
}
if (mCoverage == QnsConstants.COVERAGE_HOME && mSettingWfcEnabled) {
return true;
}
if ((mCoverage == QnsConstants.COVERAGE_ROAM
|| mIwlanNetworkStatusTracker.isInternationalRoaming(mContext, mSlotIndex))
&& mSettingWfcRoamingEnabled) {
return true;
}
if (mConfigManager.allowImsOverIwlanCellularLimitedCase()
&& !isAccessNetworkAllowed(mCellularAccessNetworkType, mApnType)
&& mCallType == QnsConstants.CALL_TYPE_IDLE
&& mIwlanAvailable) {
log("isWfcEnabled:true for idle, allow wfc");
return true;
}
if (mConfigManager.allowVideoOverIWLANWithCellularLimitedCase()
&& mCallType == QnsConstants.CALL_TYPE_VIDEO
&& mApnType == ApnSetting.TYPE_IMS) {
log("isWfcEnabled:true for video");
return true;
}
return false;
}
private boolean isAccessNetworkAllowed(int accessNetwork, int apnType) {
switch (apnType) {
case ApnSetting.TYPE_IMS:
return mConfigManager.isAccessNetworkAllowed(accessNetwork, apnType);
case ApnSetting.TYPE_EMERGENCY:
return mConfigManager.isAccessNetworkAllowed(accessNetwork, ApnSetting.TYPE_IMS);
default:
if (accessNetwork == AccessNetworkType.UNKNOWN) {
return false;
}
}
return true;
}
private boolean isAllowed(int transportType) {
StringBuilder sb = new StringBuilder();
sb.append(" evaluate isAllowed for transportType:")
.append(QnsConstants.transportTypeToString(transportType));
if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
boolean isWfcEnabled = isWfcEnabled();
sb.append(" isWfcEnabled:").append(isWfcEnabled);
if (!isWfcEnabled) {
log(sb.toString());
return false;
}
if (mQnsEventDispatcher.isAirplaneModeToggleOn()) {
boolean isWfcAllowInAirplaneMode = mConfigManager.allowWFCOnAirplaneModeOn();
sb.append(" isWfcAllowInAirplaneMode:").append(isWfcAllowInAirplaneMode);
if (!isWfcAllowInAirplaneMode) {
log(sb.toString());
return false;
}
}
if (mApnType == ApnSetting.TYPE_IMS
&& (mQnsEventDispatcher.isAirplaneModeToggleOn()
|| !QnsTelephonyListener.getInstance(mContext, mSlotIndex)
.getLastQnsTelephonyInfo()
.isCellularAvailable())
&& mIwlanNetworkStatusTracker.isInternationalRoaming(mContext, mSlotIndex)) {
boolean isBlockIwlan = mConfigManager.blockIwlanInInternationalRoamWithoutWwan();
sb.append(" isBlockIwlanInInternationalRoamWithoutWwan:").append(isBlockIwlan);
if (isBlockIwlan) {
log(sb.toString());
return false;
}
}
}
if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
if (mQnsEventDispatcher.isAirplaneModeToggleOn()) {
sb.append(" AirplaneModeOn");
log(sb.toString());
return false;
}
if (getPreferredMode() == QnsConstants.WIFI_ONLY) {
sb.append(" isWiFiOnly:false");
log(sb.toString());
return false;
}
}
if (mConfigManager.getRatPreference(mApnType) != QnsConstants.RAT_PREFERENCE_DEFAULT) {
switch (mConfigManager.getRatPreference(mApnType)) {
case QnsConstants.RAT_PREFERENCE_WIFI_ONLY:
if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
sb.append(" isAllowRatPrefWiFiOnly:false");
log(sb.toString());
return false;
}
sb.append(" isAllowRatPrefWiFiOnly:true");
break;
case QnsConstants.RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE:
if ((transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
&& mImsStatusListener.isImsRegistered(
AccessNetworkConstants.TRANSPORT_TYPE_WLAN))
|| (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
&& !mImsStatusListener.isImsRegistered(
AccessNetworkConstants.TRANSPORT_TYPE_WLAN))) {
sb.append(" isAllowRatPrefWfcAvail:false");
log(sb.toString());
return false;
}
sb.append(" isAllowRatPrefWfcAvail:true");
break;
case QnsConstants.RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR:
if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
&& mCellularAvailable) {
sb.append(" isAllowRatPrefNoCell:false");
log(sb.toString());
return false;
}
sb.append(" isAllowRatPrefNoCell:true");
break;
case QnsConstants.RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE:
if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
&& (!mCellularAvailable || mCoverage != QnsConstants.COVERAGE_HOME)) {
sb.append(" isAllowRatPrefNotHome:false");
log(sb.toString());
return false;
}
sb.append(" isAllowRatPrefNotHome:true");
break;
}
}
log(sb.toString());
return true;
}
private boolean evaluateAvailability(int transportType, boolean isAllowedForOtherType) {
boolean isAvailable =
(transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
? mIwlanAvailable
: mCellularAvailable;
boolean isOtherTypeAvailable =
isAllowedForOtherType
&& ((transportType != AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
? mIwlanAvailable
: mCellularAvailable);
boolean isRestricted = mRestrictManager.isRestricted(transportType);
boolean isAllowedOnSingleTransport =
mRestrictManager.isAllowedOnSingleTransport(transportType);
StringBuilder sb = new StringBuilder();
sb.append(" evaluate Available for transportType:")
.append(QnsConstants.transportTypeToString(transportType));
sb.append(" isAvailable:").append(isAvailable);
if (!isAvailable) {
log(sb.toString());
return false;
} else if (transportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
&& mIsCrossWfc
&& mCellularAvailable) {
sb.append(" CrossWfc is not allowed at Cellular available case.");
log(sb.toString());
return false;
}
if (isRestricted) {
PreCondition cond = getMatchingPreCondition();
if (cond instanceof GuardingPreCondition
&& ((GuardingPreCondition) cond).getGuarding() != QnsConstants.GUARDING_NONE) {
isRestricted = mRestrictManager.isRestrictedExceptGuarding(transportType);
sb.append(" isRestrictedExceptGuarding:").append(isRestricted);
} else {
sb.append(" isRestricted:").append(isRestricted);
}
} else {
sb.append(" isRestricted:").append(isRestricted);
}
if (!isRestricted) {
log(sb.toString());
return true;
}
sb.append(" hasIgnorableRestriction:").append(isAllowedOnSingleTransport);
if (!isAllowedOnSingleTransport) {
log(sb.toString());
return false;
}
sb.append(" isOtherTypeAvailable:").append(isOtherTypeAvailable);
log(sb.toString());
return !isOtherTypeAvailable;
}
protected void evaluate() {
evaluate(EVALUATE_SPECIFIC_REASON_NONE);
}
protected synchronized void evaluate(int specificReason) {
if (!mInitialized) {
if (DBG) log("ANE is not initialized yet.");
return;
}
log("evaluate reason:" + evaluateSpecificReasonToString(specificReason));
if (mApnType == ApnSetting.TYPE_EMERGENCY
&& mDataConnectionStatusTracker.isInactiveState()) {
log("QNS only handles HO of EMERGENCY data connection");
return;
}
/* Check handover policy */
if (needHandoverPolicyCheck()) {
if (!moveTransportTypeAllowed()) {
log("Handover is not allowed. Skip this evaluation.");
return;
}
}
/* Check network Availability */
boolean isAllowedForIwlan = isAllowed(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
boolean isAllowedForCellular = isAllowed(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
boolean availabilityIwlan =
isAllowedForIwlan
&& evaluateAvailability(
AccessNetworkConstants.TRANSPORT_TYPE_WLAN, isAllowedForCellular);
boolean availabilityCellular =
isAllowedForCellular
&& evaluateAvailability(
AccessNetworkConstants.TRANSPORT_TYPE_WWAN, isAllowedForIwlan);
log(" availability Iwlan:" + availabilityIwlan + " Cellular:" + availabilityCellular);
// QualifiedNetworksService checks AccessNetworkSelectionPolicy only in the case both
// networks(cellular and iwlan) are available. If only one network is available, no
// evaluation is run. Available network of accessNetworkType will be reported immediately.
if (availabilityIwlan && availabilityCellular) {
updateAccessNetworkSelectionPolicy();
List<Integer> accessNetworkTypes =
evaluateAccessNetworkSelectionPolicy(availabilityIwlan, availabilityCellular);
reportSatisfiedAccessNetworkTypesByState(accessNetworkTypes, true);
reevaluateLastNotifiedSecondAccessNetwork();
} else if (availabilityIwlan) {
updateAccessNetworkSelectionPolicy();
if (!mIsCrossWfc && hasWifiThresholdWithoutCellularCondition()) {
List<Integer> accessNetworkTypes =
evaluateAccessNetworkSelectionPolicy(
availabilityIwlan, availabilityCellular);
reportSatisfiedAccessNetworkTypesByState(accessNetworkTypes, true);
} else {
reportSatisfiedAccessNetworkTypesByState(List.of(AccessNetworkType.IWLAN), false);
}
} else if (availabilityCellular) {
reportSatisfiedAccessNetworkTypesByState(
new ArrayList<>(List.of(mCellularAccessNetworkType)), false);
} else {
// TODO Is it better to report to cellular when there is nothing?
log("evaluate nothing without an available network.");
if (specificReason == EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE) {
reportQualifiedNetwork(getInitialAccessNetworkTypes());
}
}
}
@VisibleForTesting
boolean vopsCheckRequired(int cellularAccessNetworkType, int coverage, int callType) {
boolean checkVoPs = false;
if (mConfigManager.isMmtelCapabilityRequired(coverage)
&& (cellularAccessNetworkType == AccessNetworkType.EUTRAN
|| cellularAccessNetworkType == AccessNetworkType.NGRAN)) {
if (mDataConnectionStatusTracker.isInactiveState()) {
checkVoPs = true;
} else if (mDataConnectionStatusTracker.getLastTransportType()
== AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
if (callType == QnsConstants.CALL_TYPE_IDLE
|| !mConfigManager.isInCallHoDecisionWlanToWwanWithoutVopsCondition()) {
checkVoPs = true;
}
} else if (mDataConnectionStatusTracker.getLastTransportType()
== AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
// If there is an on-going call and UE is moving into an area which does not support
// VoPS, don't consider VoPS condition and let AccessNetworkEvaluator decide a
// preferred RAT.
if (callType == QnsConstants.CALL_TYPE_IDLE) {
checkVoPs = true;
}
}
}
return checkVoPs;
}
private boolean hasWifiThresholdWithoutCellularCondition() {
if (mAccessNetworkSelectionPolicies == null || mAccessNetworkSelectionPolicies.isEmpty()) {
return false;
}
for (AccessNetworkSelectionPolicy policy : mAccessNetworkSelectionPolicies) {
if (policy.hasWifiThresholdWithoutCellularCondition()) {
return true;
}
}
return false;
}
protected synchronized void reportSatisfiedAccessNetworkTypesByState(
List<Integer> satisfiedAccessNetworkTypes, boolean needMonitor) {
if (needMonitor) {
if (mDataConnectionStatusTracker.isInactiveState()) {
if (satisfiedAccessNetworkTypes.size() > 0) {
reportQualifiedNetwork(satisfiedAccessNetworkTypes);
updateAccessNetworkSelectionPolicy();
}
updateQualityMonitor();
} else if (!mDataConnectionStatusTracker.isConnectionInProgress()) {
if (isHandoverNeeded(satisfiedAccessNetworkTypes)) {
reportQualifiedNetwork(satisfiedAccessNetworkTypes);
unregisterThresholdToQualityMonitor();
} else if (isFallbackCase(satisfiedAccessNetworkTypes)) {
reportQualifiedNetwork(satisfiedAccessNetworkTypes);
updateAccessNetworkSelectionPolicy();
updateQualityMonitor();
} else {
updateQualityMonitor();
}
}
} else {
if (mDataConnectionStatusTracker.isInactiveState()) {
reportQualifiedNetwork(satisfiedAccessNetworkTypes);
} else if (!mDataConnectionStatusTracker.isConnectionInProgress()) {
if (isHandoverNeeded(satisfiedAccessNetworkTypes)) {
reportQualifiedNetwork(satisfiedAccessNetworkTypes);
} else if (isFallbackCase(satisfiedAccessNetworkTypes)) {
reportQualifiedNetwork(satisfiedAccessNetworkTypes);
}
}
unregisterThresholdToQualityMonitor();
}
}
protected int getTargetTransportType(List<Integer> accessNetworkTypes) {
if (accessNetworkTypes == null || accessNetworkTypes.size() == 0) {
return AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
}
if (accessNetworkTypes.get(0) == AccessNetworkType.IWLAN) {
return AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
}
return AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
}
@VisibleForTesting
boolean needHandoverPolicyCheck() {
if (mDataConnectionStatusTracker.isActiveState()) {
int srcTransportType = mDataConnectionStatusTracker.getLastTransportType();
boolean targetNetworkAvailable =
srcTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN
? mCellularAvailable
: mIwlanAvailable;
if (srcTransportType == getLastQualifiedTransportType() && targetNetworkAvailable) {
log("Need to check handover policy for this evaluation.");
return true;
}
}
log("No need to check handover policy for this evaluation.");
return false;
}
@VisibleForTesting
boolean moveTransportTypeAllowed() {
int srcAccessNetwork =
mDataConnectionStatusTracker.getLastTransportType()
== AccessNetworkConstants.TRANSPORT_TYPE_WLAN
? AccessNetworkType.IWLAN
: mLatestAvailableCellularAccessNetwork;
int dstAccessNetwork =
srcAccessNetwork == AccessNetworkType.IWLAN
? mCellularAccessNetworkType
: AccessNetworkType.IWLAN;
if (mConfigManager.isHandoverAllowedByPolicy(
mApnType, srcAccessNetwork, dstAccessNetwork, mCoverage)) {
if (mApnType == ApnSetting.TYPE_IMS && mCallType == QnsConstants.CALL_TYPE_EMERGENCY) {
return false;
}
return true;
} else {
if (mApnType == ApnSetting.TYPE_IMS && mCallType == QnsConstants.CALL_TYPE_IDLE) {
// Telephony will make new connection with preferred AccessNetwork
log("handover is not allowed. but need to move to target Transport.");
return true;
}
if (dstAccessNetwork == AccessNetworkType.IWLAN && useDifferentApnOverIwlan()) {
// Telephony will make new connection when change transport type
log(
"handover is not allowed. but need to move to target Transport using"
+ " different apn over IWLAN.");
return true;
}
if (dstAccessNetwork != AccessNetworkType.IWLAN
&& mCellularAvailable
&& mConfigManager.getRatPreference(mApnType)
== QnsConstants.RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR) {
// Telephony will make new connection when change transport type
log(
"handover is not allowed. but need to move to target Transport for the"
+ " RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR.");
return true;
}
}
return false;
}
private boolean useDifferentApnOverIwlan() {
// supports MMS, XCAP and CBS
if (mApnType != ApnSetting.TYPE_MMS
&& mApnType != ApnSetting.TYPE_XCAP
&& mApnType != ApnSetting.TYPE_CBS) {
return false;
}
ApnSetting apnSetting =
mDataConnectionStatusTracker.getLastApnSetting(
AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (apnSetting != null
&& apnSetting.canHandleType(ApnSetting.TYPE_DEFAULT)
&& !apnSetting.canSupportNetworkType(TelephonyManager.NETWORK_TYPE_IWLAN)) {
log("useDifferentApnOverIwlan true");
return true;
}
log("useDifferentApnOverIwlan false");
return false;
}
protected boolean isHandoverNeeded(List<Integer> accessNetworkTypes) {
if (mDataConnectionStatusTracker.isInactiveState()
|| mDataConnectionStatusTracker.isHandoverState()) {
return false;
}
int targetTransportType = getTargetTransportType(accessNetworkTypes);
if (targetTransportType == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) {
return false;
}
// Handover case
int sourceTransportType = mDataConnectionStatusTracker.getLastTransportType();
return sourceTransportType != targetTransportType;
}
protected boolean isFallbackCase(List<Integer> accessNetworkTypes) {
if (mDataConnectionStatusTracker.isInactiveState()) {
return false;
}
int targetTransportType = getTargetTransportType(accessNetworkTypes);
if (targetTransportType == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) {
return false;
}
if (targetTransportType != mDataConnectionStatusTracker.getLastTransportType()) {
return false;
}
if (getLastQualifiedTransportType() == targetTransportType) {
return false;
}
log("isFallbackcase:true");
return true;
}
protected void reportQualifiedNetwork(List<Integer> accessNetworkTypes) {
if (accessNetworkTypes.contains(AccessNetworkType.UNKNOWN)) {
log(
"reportQualifiedNetwork, remove UNKNOWN access network."
+ QnsUtils.getStringAccessNetworkTypes(accessNetworkTypes));
accessNetworkTypes.remove(AccessNetworkType.UNKNOWN);
}
List<Integer> supportAccessNetworkTypes = new ArrayList<>();
if (mConfigManager.allowImsOverIwlanCellularLimitedCase()) {
for (Integer accessNetwork : accessNetworkTypes) {
if (accessNetwork == AccessNetworkType.IWLAN
|| isAccessNetworkAllowed(accessNetwork, mApnType)) {
supportAccessNetworkTypes.add(accessNetwork);
}
}
if (!accessNetworkTypes.isEmpty() && supportAccessNetworkTypes.isEmpty()) {
log("supportAccessNetworkTypes is empty");
return;
}
} else {
supportAccessNetworkTypes.addAll(accessNetworkTypes);
}
log(
"reportQualifiedNetwork supportAccessNetworkTypes:"
+ QnsUtils.getStringAccessNetworkTypes(supportAccessNetworkTypes));
if (equalsLastNotifiedQualifiedNetwork(supportAccessNetworkTypes)) {
return;
}
updateLastNotifiedQualifiedNetwork(supportAccessNetworkTypes);
notifyForQualifiedNetworksChanged(supportAccessNetworkTypes);
}
private List<Threshold> findUnmatchedThresholds() {
List<Threshold> unmatchedThresholds = new ArrayList<>();
if (mAccessNetworkSelectionPolicies == null
|| mAccessNetworkSelectionPolicies.size() == 0) {
return unmatchedThresholds;
}
List<Integer> excludeThresholdGroup = new ArrayList<>();
boolean bIwlanRegistrable = isIwlanAvailableWithoutRestrict();
boolean bCellularRegistrable = isCellularAvailableWithoutRestrict();
for (AccessNetworkSelectionPolicy policy : mAccessNetworkSelectionPolicies) {
List<Threshold> policyUnmatchedThresholds =
policy.findUnmatchedThresholds(mWifiQualityMonitor, mCellularQualityMonitor);
if (policyUnmatchedThresholds == null || policyUnmatchedThresholds.size() == 0) {
continue;
}
for (Threshold threshold : policyUnmatchedThresholds) {
if (bIwlanRegistrable && threshold.getAccessNetwork() == AccessNetworkType.IWLAN) {
unmatchedThresholds.add(threshold);
}
if (bCellularRegistrable
&& threshold.getAccessNetwork() != AccessNetworkType.IWLAN) {
if (threshold.getAccessNetwork() == mCellularAccessNetworkType) {
unmatchedThresholds.add(threshold);
} else if (threshold.getGroupId() >= 0) {
// If the current cellular access network and the access network of
// cellular threshold are different, it is not necessary to monitor the
// entire threshold of this group.
excludeThresholdGroup.add(threshold.getGroupId());
}
}
}
}
for (int excludeGid : excludeThresholdGroup) {
unmatchedThresholds.removeIf(threshold -> threshold.getGroupId() == excludeGid);
}
return unmatchedThresholds;
}
private void updateQualityMonitor() {
List<Threshold> unmatchedThresholds = findUnmatchedThresholds();
if (unmatchedThresholds.size() == 0) {
log("updateQualityMonitor empty unmatchedThresholds.");
unregisterThresholdToQualityMonitor();
return;
}
log("updateQualityMonitor");
LinkedHashSet<Integer> unmatchedGroupIdSet = new LinkedHashSet<>();
HashMap<Integer, Integer> unmatchedMonitorTypeMap = new HashMap<>();
LinkedHashSet<Integer> unmatchedMonitorTypeSet = new LinkedHashSet<>();
for (Threshold th : unmatchedThresholds) {
if (th.getGroupId() < 0) {
continue;
}
unmatchedGroupIdSet.add(th.getGroupId());
int key = th.getAccessNetwork() << 16 | th.getMeasurementType();
unmatchedMonitorTypeMap.put(key, unmatchedMonitorTypeMap.getOrDefault(key, 0) + 1);
}
List<Map.Entry<Integer, Integer>> list_entries =
new ArrayList<>(unmatchedMonitorTypeMap.entrySet());
list_entries.sort(Entry.comparingByValue());
for (Entry<Integer, Integer> entry : list_entries) {
unmatchedMonitorTypeSet.add(entry.getKey());
}
LinkedHashSet<Integer> reducedGroupIdSet = new LinkedHashSet<>();
for (int type : unmatchedMonitorTypeSet) {
reducedGroupIdSet.clear();
boolean skipReduce = false;
for (Threshold th : unmatchedThresholds) {
if (type == (th.getAccessNetwork() << 16 | th.getMeasurementType())) {
if (th.getGroupId() < 0) {
skipReduce = true;
break;
}
} else {
reducedGroupIdSet.add(th.getGroupId());
}
}
if (skipReduce) {
continue;
}
if (reducedGroupIdSet.containsAll(unmatchedGroupIdSet)) {
unmatchedThresholds.removeIf(
threshold ->
type
== (threshold.getAccessNetwork() << 16
| threshold.getMeasurementType()));
}
}
registerThresholdsToQualityMonitor(unmatchedThresholds);
}
private void unregisterThresholdToQualityMonitor() {
mWifiQualityMonitor.updateThresholdsForApn(mApnType, mSlotIndex, null);
mCellularQualityMonitor.updateThresholdsForApn(mApnType, mSlotIndex, null);
}
private void registerThresholdsToQualityMonitor(List<Threshold> thresholds) {
if (thresholds == null) {
thresholds = new ArrayList<>();
}
List<Threshold> monitorWiFiThresholds = new ArrayList<>();
List<Threshold> monitorCellThresholds = new ArrayList<>();
for (Threshold th : thresholds) {
if (th.getAccessNetwork() == AccessNetworkType.IWLAN) {
monitorWiFiThresholds.add(th);
} else {
monitorCellThresholds.add(th);
}
}
for (Threshold th : monitorWiFiThresholds) {
log(" monitorWiFiThresholds th:" + th.toShortString());
}
for (Threshold th : monitorCellThresholds) {
log(" monitorCellThresholds th:" + th.toShortString());
}
// refresh threshold to be monitored.
mWifiQualityMonitor.updateThresholdsForApn(
mApnType, mSlotIndex, monitorWiFiThresholds.toArray(new Threshold[0]));
mCellularQualityMonitor.updateThresholdsForApn(
mApnType, mSlotIndex, monitorCellThresholds.toArray(new Threshold[0]));
}
protected void updateThrottleStatus(
boolean isThrottle, long throttleTimeMillis, int transportType) {
mRestrictManager.notifyThrottling(isThrottle, throttleTimeMillis, transportType);
}
protected int getPreferredMode() {
if (mAllowIwlanForWfcActivation) {
return QnsConstants.WIFI_PREF;
}
if (mCoverage == QnsConstants.COVERAGE_ROAM) {
return mSettingWfcRoamingMode;
}
return mSettingWfcMode;
}
private int getPreferredAccessNetwork() {
switch (getPreferredMode()) {
case QnsConstants.CELL_PREF:
return mCellularAccessNetworkType;
case QnsConstants.WIFI_PREF:
case QnsConstants.WIFI_ONLY:
return AccessNetworkType.IWLAN;
}
return mCellularAccessNetworkType;
}
private List<Integer> evaluateAccessNetworkSelectionPolicy(
boolean availabilityIwlan, boolean availabilityCellular) {
log("evaluateAccessNetworkSelectionPolicy");
if (mAccessNetworkSelectionPolicies == null || mAccessNetworkSelectionPolicies.isEmpty()) {
return new ArrayList<>();
}
List<Integer> accessNetworkTypes = new ArrayList<>();
for (AccessNetworkSelectionPolicy policy : mAccessNetworkSelectionPolicies) {
if (policy.satisfiedByThreshold(
mWifiQualityMonitor,
mCellularQualityMonitor,
availabilityIwlan,
availabilityCellular,
mCellularAccessNetworkType)) {
log(
" satisfiedByThreshold TargetTransportType:"
+ QnsConstants.transportTypeToString(
policy.getTargetTransportType()));
if (policy.getTargetTransportType() == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
if (!accessNetworkTypes.contains(AccessNetworkType.IWLAN)) {
accessNetworkTypes.add(AccessNetworkType.IWLAN);
}
} else {
if (!accessNetworkTypes.contains(mCellularAccessNetworkType)) {
if (availabilityCellular) {
accessNetworkTypes.add(mCellularAccessNetworkType);
} else {
accessNetworkTypes.add(AccessNetworkType.UNKNOWN);
}
}
if ((mCallType == QnsConstants.CALL_TYPE_VOICE
|| mCallType == QnsConstants.CALL_TYPE_EMERGENCY)
&& policy.satisfiedWithWifiLowSignalStrength()) {
int reason = mConfigManager.getQnsIwlanHoRestrictReason();
if (reason == QnsConstants.FALLBACK_REASON_RTP_OR_WIFI
|| reason == QnsConstants.FALLBACK_REASON_WIFI_ONLY) {
log("WWAN decision with Wi-Fi low signalStrength in Voice call");
mRestrictManager.increaseCounterToRestrictIwlanInCall();
}
}
}
}
}
// If the evaluator has not yet reported a Qualified Networks, report preferred.
if (!isNotifiedQualifiedAccessNetworkTypes()) {
if (accessNetworkTypes.size() == 0) {
accessNetworkTypes.add(getPreferredAccessNetwork());
log(
" no candidate access network, use preferred:"
+ QnsUtils.getStringAccessNetworkTypes(accessNetworkTypes));
} else if (accessNetworkTypes.size() > 1) {
accessNetworkTypes.remove(Integer.valueOf(getPreferredAccessNetwork()));
accessNetworkTypes.add(0, getPreferredAccessNetwork());
log(
" two more candidate access network, use preferred:"
+ QnsUtils.getStringAccessNetworkTypes(accessNetworkTypes));
}
}
// TODO. need to be improved handling the second access network
// Add a second access network, if the preferred access network does not exist in list.
if (availabilityIwlan
&& availabilityCellular
&& mConfigManager.isOverrideImsPreferenceSupported()) {
if (!accessNetworkTypes.isEmpty()
&& accessNetworkTypes.get(0) != AccessNetworkType.IWLAN
&& getPreferredMode() == QnsConstants.CELL_PREF
&& isAccessNetworkAllowed(accessNetworkTypes.get(0), mApnType)) {
if (!accessNetworkTypes.contains(AccessNetworkType.IWLAN)) {
accessNetworkTypes.add(AccessNetworkType.IWLAN);
log(
" add a second accessNetworkTypes : "
+ QnsUtils.getStringAccessNetworkTypes(accessNetworkTypes));
}
} else if (accessNetworkTypes.isEmpty()
&& !mLastQualifiedAccessNetworkTypes.isEmpty()
&& mLastQualifiedAccessNetworkTypes.get(0) != AccessNetworkType.IWLAN
&& getPreferredMode() == QnsConstants.CELL_PREF
&& isAccessNetworkAllowed(mLastQualifiedAccessNetworkTypes.get(0), mApnType)) {
if (!mLastQualifiedAccessNetworkTypes.contains(AccessNetworkType.IWLAN)) {
accessNetworkTypes.addAll(mLastQualifiedAccessNetworkTypes);
accessNetworkTypes.add(AccessNetworkType.IWLAN);
log(
" add a second accessNetworkTypes in existing "
+ "mLastQualifiedAccessNetworkTypes : "
+ QnsUtils.getStringAccessNetworkTypes(accessNetworkTypes));
}
}
}
log(" accessNetworkTypes:" + QnsUtils.getStringAccessNetworkTypes(accessNetworkTypes));
return accessNetworkTypes;
}
// TODO. need to be improved handling the second access network
// A qualified conditions are required for the second access network.
// What threshold conditions are qualified for the second access network? (like rove in)
// What are the threshold conditions for exiting the second access network? (like a rove out)
private void reevaluateLastNotifiedSecondAccessNetwork() {
if (mConfigManager.isOverrideImsPreferenceSupported()
&& mLastQualifiedAccessNetworkTypes.size() > 1
&& mLastQualifiedAccessNetworkTypes.get(1) == AccessNetworkType.IWLAN) {
if (!isAccessNetworkAllowed(mCellularAccessNetworkType, mApnType)
|| getPreferredMode() != QnsConstants.CELL_PREF) {
log("reevaluateLastNotifiedSecondAccessNetwork, Removed a second access network");
reportQualifiedNetwork(
new ArrayList<>(List.of(mLastQualifiedAccessNetworkTypes.get(0))));
}
}
}
private Map<PreCondition, List<AccessNetworkSelectionPolicy>> buildAccessNetworkSelectionPolicy(
boolean bForceUpdate) {
if (mAnspPolicyMap == null || bForceUpdate) {
log("Building list of AccessNetworkSelectionPolicy.");
mAnspPolicyMap =
AccessNetworkSelectionPolicyBuilder.build(mContext, mSlotIndex, mApnType);
if (DBG) {
mAnspPolicyMap
.values()
.forEach(
list ->
list.stream()
.map(policy -> " retriMap ANSP=" + policy)
.forEach(this::log));
}
}
return mAnspPolicyMap;
}
private void updateAccessNetworkSelectionPolicy() {
Map<PreCondition, List<AccessNetworkSelectionPolicy>> map =
buildAccessNetworkSelectionPolicy(false);
if (map == null) {
map = new HashMap<>();
}
log("Create a list of AccessNetworkSelectionPolicy that match the preconditions.");
PreCondition preCondition = getMatchingPreCondition();
List<AccessNetworkSelectionPolicy> matchedPolicies = new ArrayList<>();
List<AccessNetworkSelectionPolicy> list = map.get(preCondition);
if (list != null) {
for (AccessNetworkSelectionPolicy policy : list) {
if (policy.satisfyPrecondition(preCondition)
&& !mDataConnectionStatusTracker.isConnectionInProgress()
&& (!isNotifiedQualifiedAccessNetworkTypes()
|| getLastQualifiedTransportType()
!= policy.getTargetTransportType())) {
matchedPolicies.add(policy);
}
}
}
if (mAccessNetworkSelectionPolicies.equals(matchedPolicies)) {
for (AccessNetworkSelectionPolicy policy : matchedPolicies) {
log(" Matched ANSP=" + policy);
}
}
for (AccessNetworkSelectionPolicy policy : matchedPolicies) {
log(" Found new ANSP=" + policy);
}
mAccessNetworkSelectionPolicies = matchedPolicies;
}
private PreCondition getMatchingPreCondition() {
int callType = mCallType;
if (mApnType == ApnSetting.TYPE_EMERGENCY
&& mCallType == QnsConstants.CALL_TYPE_EMERGENCY) {
callType = QnsConstants.CALL_TYPE_VOICE;
}
if (mConfigManager.hasThresholdGapWithGuardTimer()) {
@QnsConstants.QnsGuarding int guarding = QnsConstants.GUARDING_NONE;
int source = getLastQualifiedTransportType();
if (source != AccessNetworkConstants.TRANSPORT_TYPE_WLAN
&& mRestrictManager.hasRestrictionType(
AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
RestrictManager.RESTRICT_TYPE_GUARDING)) {
guarding = QnsConstants.GUARDING_WIFI;
} else if (source != AccessNetworkConstants.TRANSPORT_TYPE_WWAN
&& mRestrictManager.hasRestrictionType(
AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
RestrictManager.RESTRICT_TYPE_GUARDING)) {
guarding = QnsConstants.GUARDING_CELLULAR;
}
return new GuardingPreCondition(callType, getPreferredMode(), mCoverage, guarding);
}
return new PreCondition(callType, getPreferredMode(), mCoverage);
}
private String evaluateSpecificReasonToString(int specificReason) {
if (specificReason == EVALUATE_SPECIFIC_REASON_NONE) {
return "EVALUATE_SPECIFIC_REASON_NONE";
} else if (specificReason == EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE) {
return "EVALUATE_SPECIFIC_REASON_IWLAN_DISABLE";
}
return "UNKNOWN";
}
private class EvaluatorEventHandler extends Handler {
public EvaluatorEventHandler(Looper l) {
super(l);
}
@Override
public void handleMessage(Message message) {
log("handleMessage msg=" + message.what);
AsyncResult ar = (AsyncResult) message.obj;
switch (message.what) {
case EVENT_IWLAN_NETWORK_STATUS_CHANGED:
onIwlanNetworkStatusChanged((IwlanAvailabilityInfo) ar.result);
break;
case EVENT_QNS_TELEPHONY_INFO_CHANGED:
onQnsTelephonyInfoChanged((QnsTelephonyListener.QnsTelephonyInfo) ar.result);
break;
case EVENT_RESTRICT_INFO_CHANGED:
onRestrictInfoChanged();
break;
case EVENT_SET_CALL_TYPE:
onSetCallType((int) ar.result);
break;
case EVENT_EMERGENCY_PREFERRED_TRANSPORT_TYPE_CHANGED:
onEmergencyPreferredTransportTypeChanged((int) ar.result);
break;
case EVENT_DATA_CONNECTION_STATE_CHANGED:
onDataConnectionStateChanged(
(DataConnectionStatusTracker.DataConnectionChangedInfo) ar.result);
break;
case EVENT_WFC_ACTIVATION_WITH_IWLAN_CONNECTION_REQUIRED:
onTryWfcConnectionStateChanged((boolean) ar.result);
break;
case EVENT_PROVISIONING_INFO_CHANGED:
onProvisioningInfoChanged(
(QnsProvisioningListener.QnsProvisioningInfo) ar.result);
break;
case EVENT_IMS_REGISTRATION_STATE_CHANGED:
onImsRegStateChanged((ImsStatusListener.ImsRegistrationChangedEv) ar.result);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_ENABLED:
onWfcEnabledChanged(true, false);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_DISABLED:
onWfcEnabledChanged(false, false);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_WIFI_ONLY:
onWfcModeChanged(QnsConstants.WIFI_ONLY, false);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED:
onWfcModeChanged(QnsConstants.CELL_PREF, false);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED:
onWfcModeChanged(QnsConstants.WIFI_PREF, false);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_ENABLED:
onWfcEnabledChanged(true, true);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_DISABLED:
onWfcEnabledChanged(false, true);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY:
onWfcModeChanged(QnsConstants.WIFI_ONLY, true);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED:
onWfcModeChanged(QnsConstants.CELL_PREF, true);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED:
onWfcModeChanged(QnsConstants.WIFI_PREF, true);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_PLATFORM_ENABLED:
onWfcPlatformChanged(true);
break;
case QnsEventDispatcher.QNS_EVENT_WFC_PLATFORM_DISABLED:
onWfcPlatformChanged(false);
break;
case QnsEventDispatcher.QNS_EVENT_SIM_ABSENT:
onSimAbsent();
break;
default:
log("never reach here msg=" + message.what);
}
}
}
private class ThresholdListener extends ThresholdCallback
implements ThresholdCallback.WifiThresholdListener,
ThresholdCallback.CellularThresholdListener {
ThresholdListener(Executor executor) {
this.init(executor);
}
@Override
public void onWifiThresholdChanged(Threshold[] thresholds) {
onWiFiQualityChanged(thresholds);
}
@Override
public void onCellularThresholdChanged(Threshold[] thresholds) {
onCellularQualityChanged(thresholds);
}
}
/**
* Dumps the state of {@link QualityMonitor}
*
* @param pw {@link PrintWriter} to write the state of the object.
* @param prefix String to append at start of dumped log.
*/
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "------------------------------");
pw.println(
prefix + "ANE[" + ApnSetting.getApnTypeString(mApnType) + "_" + mSlotIndex + "]:");
pw.println(prefix + "mInitialized=" + mInitialized);
pw.println(
prefix
+ "mQualifiedNetworksChangedRegistrant size="
+ mQualifiedNetworksChangedRegistrants.size());
pw.println(
prefix
+ "mCellularAccessNetworkType="
+ QnsConstants.accessNetworkTypeToString(mCellularAccessNetworkType)
+ ", mLatestAvailableCellularAccessNetwork="
+ QnsConstants.accessNetworkTypeToString(
mLatestAvailableCellularAccessNetwork)
+ ", mIsNotifiedLastQualifiedAccessNetworkTypes="
+ mIsNotifiedLastQualifiedAccessNetworkTypes);
pw.print(prefix + "mLastQualifiedAccessNetworkTypes=");
mLastQualifiedAccessNetworkTypes.forEach(
accessNetwork ->
pw.print(QnsConstants.accessNetworkTypeToString(accessNetwork) + "|"));
pw.println(
", mIsNotifiedLastQualifiedAccessNetworkTypes="
+ mIsNotifiedLastQualifiedAccessNetworkTypes);
pw.println(
prefix
+ "mCellularAvailable="
+ mCellularAvailable
+ ", mIwlanAvailable="
+ mIwlanAvailable
+ ", mIsCrossWfc="
+ QnsConstants.callTypeToString(mCallType)
+ ", mCoverage"
+ QnsConstants.coverageToString(mCoverage));
pw.println(
prefix
+ "mWfcPlatformEnabled="
+ mWfcPlatformEnabled
+ ", mSettingWfcEnabled="
+ mSettingWfcEnabled
+ ", mSettingWfcMode="
+ QnsConstants.preferenceToString(mSettingWfcMode)
+ ", mSettingWfcRoamingEnabled="
+ mSettingWfcRoamingEnabled
+ ", mSettingWfcRoamingMode="
+ QnsConstants.preferenceToString(mSettingWfcRoamingMode)
+ ", mAllowIwlanForWfcActivation="
+ mAllowIwlanForWfcActivation);
pw.println(prefix + "mLastProvisioningInfo=" + mLastProvisioningInfo);
pw.println(prefix + "mAccessNetworkSelectionPolicies=" + mAccessNetworkSelectionPolicies);
pw.println(prefix + "mAnspPolicyMap=" + mAnspPolicyMap);
mRestrictManager.dump(pw, prefix + " ");
}
}