blob: 0ad26ff78b4e306b26b63c9bb9e19e90e928ed8f [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 android.content.Context;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.SignalThresholdInfo;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.qns.AccessNetworkSelectionPolicy.PreCondition;
import com.android.qns.QnsCarrierConfigManager.QnsConfigArray;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
public class AccessNetworkSelectionPolicyBuilder {
static final int WLAN = AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
static final int WWAN = AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
static final int ROVE_IN = QnsConstants.ROVE_IN;
static final int ROVE_OUT = QnsConstants.ROVE_OUT;
static final int IDLE = QnsConstants.CALL_TYPE_IDLE;
static final int VOICE = QnsConstants.CALL_TYPE_VOICE;
static final int VIDEO = QnsConstants.CALL_TYPE_VIDEO;
static final int WIFI_PREF = QnsConstants.WIFI_PREF;
static final int CELL_PREF = QnsConstants.CELL_PREF;
static final int HOME = QnsConstants.COVERAGE_HOME;
static final int ROAM = QnsConstants.COVERAGE_ROAM;
static final int IWLAN = AccessNetworkConstants.AccessNetworkType.IWLAN;
static final int GUARDING_NONE = QnsConstants.GUARDING_NONE;
static final int GUARDING_CELL = QnsConstants.GUARDING_CELLULAR;
static final int GUARDING_WIFI = QnsConstants.GUARDING_WIFI;
static HashMap<AnspKey, String[]> sPolicyMap;
static {
// Default policy map
sPolicyMap = new HashMap<>();
sPolicyMap.put(new AnspKey(ROVE_IN, WIFI_PREF), new String[] {"Condition:WIFI_GOOD"});
sPolicyMap.put(new AnspKey(ROVE_OUT, WIFI_PREF), new String[] {"Condition:WIFI_BAD"});
sPolicyMap.put(
new AnspKey(ROVE_IN, CELL_PREF), new String[] {"Condition:WIFI_GOOD,CELLULAR_BAD"});
sPolicyMap.put(
new AnspKey(ROVE_OUT, CELL_PREF),
new String[] {"Condition:CELLULAR_GOOD", "Condition:WIFI_BAD,CELLULAR_TOLERABLE"});
}
protected String[] getPolicyInMap(
@QnsConstants.RoveDirection int direction, PreCondition preCondition) {
return sPolicyMap.get(new AnspKey(direction, preCondition.getPreference()));
}
protected String[] getPolicyInInternal(
@QnsConstants.RoveDirection int direction, PreCondition preCondition) {
return mConfig.getPolicy(direction, preCondition);
}
protected String[] getPolicy(
@QnsConstants.RoveDirection int direction, PreCondition preCondition) {
String[] internalPolicies = getPolicyInInternal(direction, preCondition);
if (internalPolicies != null) {
return internalPolicies;
}
if (mConfig.isTransportTypeSelWithoutSSInRoamSupported()
&& preCondition.getCoverage() == QnsConstants.COVERAGE_ROAM) {
if (mConfig.allowImsOverIwlanCellularLimitedCase()) {
List<Integer> supportedAccessNetworks = getSupportAccessNetworkTypes();
List<String> policyImsOverIwlan = new ArrayList<>();
for (int accessNetwork : supportedAccessNetworks) {
if (accessNetwork == IWLAN) {
continue;
}
if (mConfig.isAccessNetworkAllowed(accessNetwork, mApnType)) {
if (preCondition.getPreference() == QnsConstants.CELL_PREF
&& direction == QnsConstants.ROVE_OUT) {
String name = AccessNetworkType.toString(accessNetwork) + "_AVAILABLE";
policyImsOverIwlan.add("Condition:WIFI_AVAILABLE," + name);
} else if (preCondition.getPreference() == QnsConstants.WIFI_PREF
&& direction == QnsConstants.ROVE_IN) {
String name = AccessNetworkType.toString(accessNetwork) + "_AVAILABLE";
policyImsOverIwlan.add("Condition:WIFI_AVAILABLE," + name);
}
} else {
if (preCondition.getPreference() == QnsConstants.CELL_PREF
&& direction == QnsConstants.ROVE_IN) {
String name = AccessNetworkType.toString(accessNetwork) + "_AVAILABLE";
policyImsOverIwlan.add("Condition:WIFI_AVAILABLE," + name);
} else if (preCondition.getPreference() == QnsConstants.WIFI_PREF
&& direction == QnsConstants.ROVE_IN) {
String name = AccessNetworkType.toString(accessNetwork) + "_AVAILABLE";
policyImsOverIwlan.add("Condition:WIFI_AVAILABLE," + name);
}
}
}
return policyImsOverIwlan.toArray(String[]::new);
} else {
if (preCondition.getPreference() == QnsConstants.CELL_PREF
&& direction == QnsConstants.ROVE_OUT) {
return new String[] {"Condition:WIFI_AVAILABLE"};
} else if (preCondition.getPreference() == QnsConstants.WIFI_PREF
&& direction == QnsConstants.ROVE_IN) {
return new String[] {"Condition:WIFI_AVAILABLE"};
} else {
return new String[] {"Condition:"};
}
}
}
if (mConfig.isCurrentTransportTypeInVoiceCallSupported()
&& direction == QnsConstants.ROVE_OUT
&& preCondition.getCallType() == QnsConstants.CALL_TYPE_VOICE
&& preCondition.getPreference() == QnsConstants.CELL_PREF) {
return new String[] {"Condition:WIFI_BAD"};
}
if (mConfig.isChooseWfcPreferredTransportInBothBadCondition(
preCondition.getPreference())) {
if (direction == QnsConstants.ROVE_OUT
&& preCondition.getPreference() == QnsConstants.CELL_PREF) {
return new String[] {"Condition:WIFI_BAD", "Condition:CELLULAR_GOOD"};
} else if (direction == QnsConstants.ROVE_IN
&& preCondition.getPreference() == QnsConstants.WIFI_PREF) {
return new String[] {"Condition:WIFI_GOOD", "Condition:CELLULAR_BAD"};
}
}
return getPolicyInMap(direction, preCondition);
}
protected List<Integer> getSupportAccessNetworkTypes() {
return List.of(
AccessNetworkType.NGRAN,
AccessNetworkType.EUTRAN,
AccessNetworkType.UTRAN,
AccessNetworkType.GERAN,
AccessNetworkType.IWLAN);
}
public static synchronized Map<PreCondition, List<AccessNetworkSelectionPolicy>> build(
Context context, int slotIndex, int apnType) {
AccessNetworkSelectionPolicyBuilder builder;
QnsCarrierConfigManager cm = QnsCarrierConfigManager.getInstance(context, slotIndex);
if (cm.isOverrideImsPreferenceSupported()) {
builder = new AnspImsPreferModePolicyBuilder(context, slotIndex, apnType);
} else {
builder = new AccessNetworkSelectionPolicyBuilder(context, slotIndex, apnType);
}
return builder.buildAnsp();
}
protected void log(String log) {
Log.d(LOG_TAG, log);
}
protected String LOG_TAG = "QnsAnspBuilder";
protected final QnsCarrierConfigManager mConfig;
protected final int mApnType;
public AccessNetworkSelectionPolicyBuilder(Context context, int slotIndex, int apnType) {
mConfig = QnsCarrierConfigManager.getInstance(context, slotIndex);
mApnType = apnType;
}
@VisibleForTesting
public AccessNetworkSelectionPolicyBuilder(QnsCarrierConfigManager configManager, int apnType) {
mConfig = configManager;
mApnType = apnType;
}
protected Map<PreCondition, List<AccessNetworkSelectionPolicy>> buildAnsp() {
List<Integer> directionList = List.of(ROVE_IN, ROVE_OUT);
List<Integer> callTypeList = List.of(IDLE, VOICE, VIDEO);
List<Integer> preferenceList = List.of(WIFI_PREF, CELL_PREF);
List<Integer> coverageList = List.of(HOME, ROAM);
List<Integer> guardingList = List.of(GUARDING_NONE, GUARDING_CELL, GUARDING_WIFI);
Map<PreCondition, List<AccessNetworkSelectionPolicy>> allPolicies = new HashMap<>();
boolean enabledGuardingPreCondition = mConfig.hasThresholdGapWithGuardTimer();
for (int coverage : coverageList) {
for (int preference : preferenceList) {
for (int callType : callTypeList) {
for (int direction : directionList) {
if (enabledGuardingPreCondition) {
for (int guarding : guardingList) {
if (direction == ROVE_IN && guarding == GUARDING_CELL) {
continue;
}
if (direction == ROVE_OUT && guarding == GUARDING_WIFI) {
continue;
}
PreCondition preCondition =
new AccessNetworkSelectionPolicy.GuardingPreCondition(
callType, preference, coverage, guarding);
AccessNetworkSelectionPolicy ansp =
buildAccessNetworkSelectionPolicy(direction, preCondition);
allPolicies.computeIfAbsent(
ansp.getPreCondition(), k -> new ArrayList<>());
allPolicies.get(ansp.getPreCondition()).add(ansp);
}
} else {
PreCondition preCondition =
new PreCondition(callType, preference, coverage);
AccessNetworkSelectionPolicy ansp =
buildAccessNetworkSelectionPolicy(direction, preCondition);
allPolicies.computeIfAbsent(
ansp.getPreCondition(), k -> new ArrayList<>());
allPolicies.get(ansp.getPreCondition()).add(ansp);
}
}
}
}
}
return allPolicies;
}
protected AccessNetworkSelectionPolicy buildAccessNetworkSelectionPolicy(
@QnsConstants.RoveDirection int direction, PreCondition preCondition) {
int transportType = direction == ROVE_IN ? WLAN : WWAN;
return new AccessNetworkSelectionPolicy(
mApnType,
transportType,
preCondition,
makeThresholdGroups(direction, preCondition));
}
protected List<ThresholdGroup> makeThresholdGroups(
@QnsConstants.RoveDirection int direction, PreCondition preCondition) {
String[] policy = getPolicy(direction, preCondition);
List<ThresholdGroup> thresholdGroups = new ArrayList<>();
if (policy == null) {
return thresholdGroups;
}
for (String condition : policy) {
List<AnspItem> anspItems = parseCondition(condition, preCondition);
addThresholdGroup(thresholdGroups, anspItems, direction, preCondition);
}
List<Threshold> wifiWithoutThs = makeThresholdsWifiWithoutCellular(direction, preCondition);
if (!wifiWithoutThs.isEmpty()) {
addThresholdGroup(thresholdGroups, wifiWithoutThs);
}
return thresholdGroups;
}
protected List<AnspItem> parseCondition(String condition, PreCondition preCondition) {
List<AnspItem> anspItems = AnspItem.parseToPrimitives(condition);
List<Integer> supportedAccessNetworkTypes = getSupportAccessNetworkTypes();
List<AnspItem> wifiAnspItems = new ArrayList<>();
List<AnspItem> cellAnspItems = new ArrayList<>();
List<AnspItem> wifiAvailableAnspItems = new ArrayList<>();
List<AnspItem> cellAvailableAnspItems = new ArrayList<>();
for (int supportedAccessNetwork : supportedAccessNetworkTypes) {
boolean bHasThreshold = false;
boolean bAddAvailable = false;
for (AnspItem anspItem : anspItems) {
if (supportedAccessNetwork != anspItem.getAccessNetwork()) {
continue;
}
if (hasThreshold(anspItem, preCondition)) {
bHasThreshold = true;
if (supportedAccessNetwork == IWLAN) {
wifiAnspItems.add(anspItem);
} else {
cellAnspItems.add(anspItem);
}
} else {
bAddAvailable = true;
}
}
if (!bHasThreshold && bAddAvailable) {
String itemName = AccessNetworkType.toString(supportedAccessNetwork) + "_AVAILABLE";
if (supportedAccessNetwork == IWLAN) {
wifiAvailableAnspItems.add(AnspItem.find(itemName));
} else {
cellAvailableAnspItems.add(AnspItem.find(itemName));
}
}
}
if (!wifiAnspItems.isEmpty() && !cellAvailableAnspItems.isEmpty()) {
cellAnspItems.addAll(cellAvailableAnspItems);
}
if (!cellAnspItems.isEmpty() && !wifiAvailableAnspItems.isEmpty()) {
wifiAnspItems.addAll(wifiAvailableAnspItems);
}
wifiAnspItems.addAll(cellAnspItems);
return wifiAnspItems;
}
protected void addThresholdGroup(
List<ThresholdGroup> thresholdGroups, List<Threshold> thresholds) {
for (ThresholdGroup thresholdGroup : thresholdGroups) {
if (thresholdGroup.identicalThreshold(thresholds)) {
return;
}
}
thresholdGroups.add(new ThresholdGroup(thresholds));
}
protected void addThresholdGroup(
List<ThresholdGroup> thresholdGroups,
List<AnspItem> anspItems,
@QnsConstants.RoveDirection int direction,
PreCondition preCondition) {
if (anspItems == null || anspItems.isEmpty()) {
return;
}
List<AnspItem> wifiAnspItems = new ArrayList<>();
List<AnspItem> cellAnspItems = new ArrayList<>();
List<Integer> supportedAccessNetworkTypes = getSupportAccessNetworkTypes();
for (AnspItem anspItem : anspItems) {
if (anspItem.getAccessNetwork() == IWLAN) {
wifiAnspItems.add(anspItem);
} else {
cellAnspItems.add(anspItem);
}
}
if (direction == QnsConstants.ROVE_IN) {
if (!wifiAnspItems.isEmpty() && !cellAnspItems.isEmpty()) {
for (AnspItem wifi : wifiAnspItems) {
for (AnspItem cell : cellAnspItems) {
Threshold wifiTh = makeThreshold(wifi, direction, preCondition);
Threshold cellTh = makeThreshold(cell, direction, preCondition);
addThresholdGroup(thresholdGroups, List.of(wifiTh, cellTh));
}
}
} else {
for (AnspItem cell : cellAnspItems) {
Threshold cellTh = makeThreshold(cell, direction, preCondition);
addThresholdGroup(thresholdGroups, List.of(cellTh));
}
for (AnspItem wifi : wifiAnspItems) {
Threshold wifiTh = makeThreshold(wifi, direction, preCondition);
addThresholdGroup(thresholdGroups, List.of(wifiTh));
}
}
} else { // ROVE_OUT
for (int supportedAccessNetwork : supportedAccessNetworkTypes) {
if (supportedAccessNetwork == IWLAN) {
continue;
}
List<Threshold> thresholdList = new ArrayList<>();
for (AnspItem wifi : wifiAnspItems) {
Threshold wifiTh = makeThreshold(wifi, direction, preCondition);
thresholdList.add(wifiTh);
}
if (!cellAnspItems.isEmpty()) {
boolean isAddedThreshold = false;
for (AnspItem cell : cellAnspItems) {
if (cell.getAccessNetwork() == supportedAccessNetwork) {
Threshold cellTh = makeThreshold(cell, direction, preCondition);
thresholdList.add(cellTh);
isAddedThreshold = true;
}
}
if (!isAddedThreshold) {
continue;
}
}
if (!thresholdList.isEmpty()) {
addThresholdGroup(thresholdGroups, thresholdList);
}
}
}
}
private Threshold makeThreshold(
AnspItem anspItem,
@QnsConstants.RoveDirection int direction,
PreCondition preCondition) {
int adjustThreshold = 0;
if (preCondition instanceof AccessNetworkSelectionPolicy.GuardingPreCondition) {
AccessNetworkSelectionPolicy.GuardingPreCondition guardingPreCondition =
(AccessNetworkSelectionPolicy.GuardingPreCondition) preCondition;
if (direction == ROVE_IN && guardingPreCondition.getGuarding() == GUARDING_WIFI) {
adjustThreshold =
mConfig.getThresholdGapWithGuardTimer(
anspItem.getAccessNetwork(), anspItem.getMeasurementType());
}
}
return new Threshold(
anspItem.getAccessNetwork(),
anspItem.getMeasurementType(),
getThreshold(anspItem, preCondition) + adjustThreshold,
anspItem.getMatchType(),
getBackHaulTimer(anspItem.getAccessNetwork()));
}
protected boolean hasThreshold(AnspItem anspItem, PreCondition preCondition) {
return getThreshold(anspItem, preCondition) != QnsConfigArray.INVALID;
}
protected int getThreshold(AnspItem anspItem, PreCondition preCondition) {
if (anspItem.getMeasurementType() == AVAILABILITY) {
if (anspItem.getQualityType() == AVAIL || anspItem.getQualityType() == UNAVAIL) {
return anspItem.getQualityType();
}
return QnsConfigArray.INVALID;
}
QnsConfigArray thresholds =
mConfig.getThresholdByPref(
anspItem.getAccessNetwork(),
preCondition.getCallType(),
anspItem.getMeasurementType(),
preCondition.getPreference());
if (thresholds == null) {
return QnsConfigArray.INVALID;
}
switch (anspItem.getQualityType()) {
case GOOD:
return thresholds.mGood;
case BAD:
return thresholds.mBad;
case TOLERABLE:
if (thresholds.mWorst != QnsConfigArray.INVALID) {
return thresholds.mWorst;
}
return thresholds.mBad;
}
return QnsConfigArray.INVALID;
}
protected Threshold makeUnavailableThreshold(
@AccessNetworkConstants.RadioAccessNetworkType int accessNetwork) {
int backHaulTimer = getBackHaulTimer(accessNetwork);
return new Threshold(
accessNetwork,
QnsConstants.SIGNAL_MEASUREMENT_AVAILABILITY,
UNAVAIL,
QnsConstants.THRESHOLD_MATCH_TYPE_EQUAL_TO,
backHaulTimer);
}
protected List<Threshold> makeThresholdsWifiWithoutCellular(
@QnsConstants.RoveDirection int direction, PreCondition preCondition) {
List<Threshold> thresholds = new ArrayList<>();
int backHaulTimer = getBackHaulTimer(AccessNetworkConstants.AccessNetworkType.IWLAN);
QnsConfigArray threshold =
mConfig.getWifiRssiThresholdWithoutCellular(preCondition.getCallType());
if (threshold == null) {
return thresholds;
}
if (threshold.mGood != QnsConfigArray.INVALID && direction == QnsConstants.ROVE_IN) {
thresholds.add(
new Threshold(
AccessNetworkConstants.AccessNetworkType.IWLAN,
SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI,
threshold.mGood,
QnsConstants.THRESHOLD_EQUAL_OR_LARGER,
backHaulTimer));
}
if (threshold.mBad != QnsConfigArray.INVALID && direction == QnsConstants.ROVE_OUT) {
thresholds.add(
new Threshold(
AccessNetworkConstants.AccessNetworkType.IWLAN,
SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI,
threshold.mBad,
QnsConstants.THRESHOLD_EQUAL_OR_SMALLER,
backHaulTimer));
}
if (!thresholds.isEmpty()) {
for (int an : getSupportAccessNetworkTypes()) {
if (an == IWLAN) {
continue;
}
thresholds.add(makeUnavailableThreshold(an));
}
}
return thresholds;
}
private int getBackHaulTimer(int accessNetwork) {
if (accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN) {
return mConfig.getWIFIRssiBackHaulTimer();
}
return mConfig.getCellularSSBackHaulTimer();
}
static final int AVAILABILITY = QnsConstants.SIGNAL_MEASUREMENT_AVAILABILITY;
static final int EQUAL = QnsConstants.THRESHOLD_MATCH_TYPE_EQUAL_TO;
static final int LARGER = QnsConstants.THRESHOLD_EQUAL_OR_LARGER;
static final int SMALLER = QnsConstants.THRESHOLD_EQUAL_OR_SMALLER;
static final int NGRAN = AccessNetworkConstants.AccessNetworkType.NGRAN;
static final int EUTRAN = AccessNetworkConstants.AccessNetworkType.EUTRAN;
static final int UTRAN = AccessNetworkConstants.AccessNetworkType.UTRAN;
static final int GERAN = AccessNetworkConstants.AccessNetworkType.GERAN;
static final int RSSI = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI;
static final int SSRSRP = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP;
static final int SSRSRQ = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ;
static final int SSSINR = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR;
static final int RSRP = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP;
static final int RSRQ = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ;
static final int RSSNR = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR;
static final int RSCP = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP;
static final int ECNO = QnsConstants.SIGNAL_MEASUREMENT_TYPE_ECNO;
static final int AVAIL = QnsConstants.SIGNAL_AVAILABLE;
static final int UNAVAIL = QnsConstants.SIGNAL_UNAVAILABLE;
static final int GOOD = QnsConstants.POLICY_GOOD;
static final int BAD = QnsConstants.POLICY_BAD;
static final int TOLERABLE = QnsConstants.POLICY_TOLERABLE;
public enum AnspItem {
IWLAN_AVAILABLE("IWLAN_AVAILABLE", IWLAN, AVAILABILITY, EQUAL, AVAIL),
IWLAN_UNAVAILABLE("IWLAN_UNAVAILABLE", IWLAN, AVAILABILITY, EQUAL, UNAVAIL),
IWLAN_RSSI_GOOD("IWLAN_RSSI_GOOD", IWLAN, RSSI, LARGER, GOOD),
IWLAN_RSSI_BAD("IWLAN_RSSI_BAD", IWLAN, RSSI, SMALLER, BAD),
NGRAN_AVAILABLE("NGRAN_AVAILABLE", NGRAN, AVAILABILITY, EQUAL, AVAIL),
NGRAN_UNAVAILABLE("NGRAN_UNAVAILABLE", NGRAN, AVAILABILITY, EQUAL, UNAVAIL),
NGRAN_SSRSRP_GOOD("NGRAN_SSRSRP_GOOD", NGRAN, SSRSRP, LARGER, GOOD),
NGRAN_SSRSRP_BAD("NGRAN_SSRSRP_BAD", NGRAN, SSRSRP, SMALLER, BAD),
NGRAN_SSRSRP_TOLERABLE("NGRAN_SSRSRP_TOLERABLE", NGRAN, SSRSRP, LARGER, TOLERABLE),
NGRAN_SSRSRQ_GOOD("NGRAN_SSRSRQ_GOOD", NGRAN, SSRSRQ, LARGER, GOOD),
NGRAN_SSRSRQ_BAD("NGRAN_SSRSRQ_BAD", NGRAN, SSRSRQ, SMALLER, BAD),
NGRAN_SSRSRQ_TOLERABLE("NGRAN_SSRSRQ_TOLERABLE", NGRAN, SSRSRQ, LARGER, TOLERABLE),
NGRAN_SSSINR_GOOD("NGRAN_SSSINR_GOOD", NGRAN, SSSINR, LARGER, GOOD),
NGRAN_SSSINR_BAD("NGRAN_SSSINR_BAD", NGRAN, SSSINR, SMALLER, BAD),
NGRAN_SSSINR_TOLERABLE("NGRAN_SSSINR_TOLERABLE", NGRAN, SSSINR, LARGER, TOLERABLE),
EUTRAN_AVAILABLE("EUTRAN_AVAILABLE", EUTRAN, AVAILABILITY, EQUAL, AVAIL),
EUTRAN_UNAVAILABLE("EUTRAN_UNAVAILABLE", EUTRAN, AVAILABILITY, EQUAL, UNAVAIL),
EUTRAN_RSRP_GOOD("EUTRAN_RSRP_GOOD", EUTRAN, RSRP, LARGER, GOOD),
EUTRAN_RSRP_BAD("EUTRAN_RSRP_BAD", EUTRAN, RSRP, SMALLER, BAD),
EUTRAN_RSRP_TOLERABLE("EUTRAN_RSRP_TOLERABLE", EUTRAN, RSRP, LARGER, TOLERABLE),
EUTRAN_RSRQ_GOOD("EUTRAN_RSRQ_GOOD", EUTRAN, RSRQ, LARGER, GOOD),
EUTRAN_RSRQ_BAD("EUTRAN_RSRQ_BAD", EUTRAN, RSRQ, SMALLER, BAD),
EUTRAN_RSRQ_TOLERABLE("EUTRAN_RSRQ_TOLERABLE", EUTRAN, RSRQ, LARGER, TOLERABLE),
EUTRAN_RSSNR_GOOD("EUTRAN_RSSNR_GOOD", EUTRAN, RSSNR, LARGER, GOOD),
EUTRAN_RSSNR_BAD("EUTRAN_RSSNR_BAD", EUTRAN, RSSNR, SMALLER, BAD),
EUTRAN_RSSNR_TOLERABLE("EUTRAN_RSSNR_TOLERABLE", EUTRAN, RSSNR, LARGER, TOLERABLE),
UTRAN_AVAILABLE("UTRAN_AVAILABLE", UTRAN, AVAILABILITY, EQUAL, AVAIL),
UTRAN_UNAVAILABLE("UTRAN_UNAVAILABLE", UTRAN, AVAILABILITY, EQUAL, UNAVAIL),
UTRAN_RSCP_GOOD("UTRAN_RSCP_GOOD", UTRAN, RSCP, LARGER, GOOD),
UTRAN_RSCP_BAD("UTRAN_RSCP_BAD", UTRAN, RSCP, SMALLER, BAD),
UTRAN_RSCP_TOLERABLE("UTRAN_RSCP_TOLERABLE", UTRAN, RSCP, LARGER, TOLERABLE),
UTRAN_ECNO_GOOD("UTRAN_ECNO_GOOD", UTRAN, ECNO, LARGER, GOOD),
UTRAN_ECNO_BAD("UTRAN_ECNO_BAD", UTRAN, ECNO, SMALLER, BAD),
UTRAN_ECNO_TOLERABLE("UTRAN_ECNO_TOLERABLE", UTRAN, ECNO, LARGER, TOLERABLE),
GERAN_AVAILABLE("GERAN_AVAILABLE", GERAN, AVAILABILITY, EQUAL, AVAIL),
GERAN_UNAVAILABLE("GERAN_UNAVAILABLE", GERAN, AVAILABILITY, EQUAL, UNAVAIL),
GERAN_RSSI_GOOD("GERAN_RSSI_GOOD", GERAN, RSSI, LARGER, GOOD),
GERAN_RSSI_BAD("GERAN_RSSI_BAD", GERAN, RSSI, SMALLER, BAD),
GERAN_RSSI_TOLERABLE("GERAN_RSSI_TOLERABLE", GERAN, RSSI, LARGER, TOLERABLE),
IWLAN_GOOD("IWLAN_GOOD", new AnspItem[] {IWLAN_RSSI_GOOD}),
IWLAN_BAD("IWLAN_BAD", new AnspItem[] {IWLAN_RSSI_BAD}),
WIFI_AVAILABLE("WIFI_AVAILABLE", new AnspItem[] {IWLAN_AVAILABLE}),
WIFI_UNAVAILABLE("WIFI_UNAVAILABLE", new AnspItem[] {IWLAN_UNAVAILABLE}),
WIFI_GOOD("WIFI_GOOD", new AnspItem[] {IWLAN_GOOD}),
WIFI_BAD("WIFI_BAD", new AnspItem[] {IWLAN_BAD}),
NGRAN_GOOD(
"NGRAN_GOOD",
new AnspItem[] {NGRAN_SSRSRP_GOOD, NGRAN_SSRSRQ_GOOD, NGRAN_SSSINR_GOOD}),
NGRAN_BAD(
"NGRAN_BAD",
new AnspItem[] {NGRAN_SSRSRP_BAD, NGRAN_SSRSRQ_BAD, NGRAN_SSSINR_BAD}),
NGRAN_TOLERABLE(
"NGRAN_TOLERABLE",
new AnspItem[] {
NGRAN_SSRSRP_TOLERABLE, NGRAN_SSRSRQ_TOLERABLE, NGRAN_SSSINR_TOLERABLE
}),
EUTRAN_GOOD(
"EUTRAN_GOOD",
new AnspItem[] {EUTRAN_RSRP_GOOD, EUTRAN_RSRQ_GOOD, EUTRAN_RSSNR_GOOD}),
EUTRAN_BAD(
"EUTRAN_BAD",
new AnspItem[] {EUTRAN_RSRP_BAD, EUTRAN_RSRQ_BAD, EUTRAN_RSSNR_BAD}),
EUTRAN_TOLERABLE(
"EUTRAN_TOLERABLE",
new AnspItem[] {
EUTRAN_RSRP_TOLERABLE, EUTRAN_RSRQ_TOLERABLE, EUTRAN_RSSNR_TOLERABLE
}),
UTRAN_GOOD(
"UTRAN_GOOD",
new AnspItem[] {UTRAN_RSCP_GOOD, UTRAN_ECNO_GOOD}),
UTRAN_BAD(
"UTRAN_BAD",
new AnspItem[] {UTRAN_RSCP_BAD, UTRAN_ECNO_BAD}),
UTRAN_TOLERABLE(
"UTRAN_TOLERABLE",
new AnspItem[] {UTRAN_RSCP_TOLERABLE, UTRAN_ECNO_TOLERABLE}),
GERAN_GOOD("GERAN_GOOD", new AnspItem[] {GERAN_RSSI_GOOD}),
GERAN_BAD("GERAN_BAD", new AnspItem[] {GERAN_RSSI_BAD}),
GERAN_TOLERABLE("GERAN_TOLERABLE", new AnspItem[] {GERAN_RSSI_TOLERABLE}),
CELLULAR_AVAILABLE(
"CELLULAR_AVAILABLE",
new AnspItem[] {
NGRAN_AVAILABLE, EUTRAN_AVAILABLE, UTRAN_AVAILABLE, GERAN_AVAILABLE
}),
CELLULAR_UNAVAILABLE(
"CELLULAR_UNAVAILABLE",
new AnspItem[] {
NGRAN_UNAVAILABLE, EUTRAN_UNAVAILABLE, UTRAN_UNAVAILABLE, GERAN_UNAVAILABLE
}),
CELLULAR_GOOD(
"CELLULAR_GOOD",
new AnspItem[] {NGRAN_GOOD, EUTRAN_GOOD, UTRAN_GOOD, GERAN_GOOD}),
CELLULAR_BAD(
"CELLULAR_BAD",
new AnspItem[] {NGRAN_BAD, EUTRAN_BAD, UTRAN_BAD, GERAN_BAD}),
CELLULAR_TOLERABLE(
"CELLULAR_TOLERABLE",
new AnspItem[] {
NGRAN_TOLERABLE, EUTRAN_TOLERABLE, UTRAN_TOLERABLE, GERAN_TOLERABLE
}),
;
private static final Map<String, AnspItem> sAnspItemMap;
static {
sAnspItemMap =
Collections.unmodifiableMap(
Arrays.stream(values())
.collect(
Collectors.toMap(
AnspItem::getName,
anspItem -> anspItem,
(a, b) -> b)));
}
private final String mName;
private final int mAccessNetwork;
private final int mMeasurementType;
private final int mMatchType;
private final int mQualityType;
private final AnspItem[] mAnspItems;
AnspItem(String name, AnspItem[] items) {
mName = name;
mAnspItems = items;
mAccessNetwork = -1;
mMeasurementType = -1;
mMatchType = -1;
mQualityType = -1;
}
AnspItem(
String name,
int accessNetwork,
int measurementType,
int matchType,
int qualityType) {
mName = name;
mAnspItems = null;
mAccessNetwork = accessNetwork;
mMeasurementType = measurementType;
mMatchType = matchType;
mQualityType = qualityType;
}
private String getName() {
return mName;
}
public static AnspItem find(String item) {
return sAnspItemMap.get(item);
}
public static List<AnspItem> parseToPrimitives(String condition) {
List<AnspItem> primitives = new ArrayList<>();
if (condition == null) {
return primitives;
}
if (condition.startsWith("Condition:")) {
StringTokenizer st = new StringTokenizer(condition, ":,");
st.nextToken();
while (st.hasMoreTokens()) {
String token = st.nextToken();
AnspItem anspItem = AnspItem.find(token);
primitives.addAll(anspItem.toPrimitives());
}
}
return primitives;
}
private Collection<AnspItem> toPrimitives() {
if (isPrimitive()) {
return List.of(this);
}
List<AnspItem> primitives = new ArrayList<>();
for (AnspItem item : mAnspItems) {
primitives.addAll(item.toPrimitives());
}
return primitives;
}
public boolean isPrimitive() {
return mAnspItems == null;
}
public int getAccessNetwork() {
return mAccessNetwork;
}
public int getMeasurementType() {
return mMeasurementType;
}
public int getMatchType() {
return mMatchType;
}
public int getQualityType() {
return mQualityType;
}
}
/**
* The class AnspKey is the AccessNetworkSelectionPolicy inner class that is used to store or
* load policies in a hashmap.
*/
static class AnspKey {
private static final int INVALID = 0xFFFF;
public int mKey1;
public int mKey2;
public int mKey3;
public int mKey4;
public AnspKey(int k1, int k2) {
this.mKey1 = k1;
this.mKey2 = k2;
this.mKey3 = INVALID;
this.mKey4 = INVALID;
}
public AnspKey(int k1, int k2, int k3) {
this.mKey1 = k1;
this.mKey2 = k2;
this.mKey3 = k3;
this.mKey4 = INVALID;
}
public AnspKey(int k1, int k2, int k3, int k4) {
this.mKey1 = k1;
this.mKey2 = k2;
this.mKey3 = k3;
this.mKey4 = k4;
}
@Override
public String toString() {
return "MultiKey{"
+ "mKey1="
+ mKey1
+ ", mKey2="
+ mKey2
+ ", mKey3="
+ mKey3
+ ", mKey4="
+ mKey4
+ '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof AnspKey)) return false;
AnspKey ak = (AnspKey) o;
return mKey1 == ak.mKey1 && mKey2 == ak.mKey2 && mKey3 == ak.mKey3 && mKey4 == ak.mKey4;
}
@Override
public int hashCode() {
return Objects.hash(mKey1, mKey2, mKey3, mKey4);
}
}
}