1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.telephony.qns; 18 19 import android.telephony.AccessNetworkConstants; 20 import android.telephony.AccessNetworkConstants.AccessNetworkType; 21 import android.telephony.SignalThresholdInfo; 22 import android.util.Log; 23 24 import com.android.telephony.qns.AccessNetworkSelectionPolicy.PreCondition; 25 import com.android.telephony.qns.QnsCarrierConfigManager.QnsConfigArray; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.Collection; 30 import java.util.Collections; 31 import java.util.HashMap; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Objects; 35 import java.util.StringTokenizer; 36 import java.util.stream.Collectors; 37 38 class AccessNetworkSelectionPolicyBuilder { 39 40 static final int WLAN = AccessNetworkConstants.TRANSPORT_TYPE_WLAN; 41 static final int WWAN = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 42 static final int ROVE_IN = QnsConstants.ROVE_IN; 43 static final int ROVE_OUT = QnsConstants.ROVE_OUT; 44 static final int IDLE = QnsConstants.CALL_TYPE_IDLE; 45 static final int VOICE = QnsConstants.CALL_TYPE_VOICE; 46 static final int VIDEO = QnsConstants.CALL_TYPE_VIDEO; 47 static final int WIFI_PREF = QnsConstants.WIFI_PREF; 48 static final int CELL_PREF = QnsConstants.CELL_PREF; 49 static final int HOME = QnsConstants.COVERAGE_HOME; 50 static final int ROAM = QnsConstants.COVERAGE_ROAM; 51 static final int IWLAN = AccessNetworkConstants.AccessNetworkType.IWLAN; 52 static final int GUARDING_NONE = QnsConstants.GUARDING_NONE; 53 static final int GUARDING_CELL = QnsConstants.GUARDING_CELLULAR; 54 static final int GUARDING_WIFI = QnsConstants.GUARDING_WIFI; 55 56 static final HashMap<AnspKey, String[]> sPolicyMap; 57 58 static { 59 // Default policy map 60 sPolicyMap = new HashMap<>(); sPolicyMap.put(new AnspKey(ROVE_IN, WIFI_PREF), new String[] {"Condition:WIFI_GOOD"})61 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"})62 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"})63 sPolicyMap.put( 64 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"})65 sPolicyMap.put( 66 new AnspKey(ROVE_OUT, CELL_PREF), 67 new String[] {"Condition:CELLULAR_GOOD", "Condition:WIFI_BAD,CELLULAR_TOLERABLE"}); 68 } 69 getPolicyInMap( @nsConstants.RoveDirection int direction, PreCondition preCondition)70 protected String[] getPolicyInMap( 71 @QnsConstants.RoveDirection int direction, PreCondition preCondition) { 72 return sPolicyMap.get(new AnspKey(direction, preCondition.getPreference())); 73 } 74 getPolicyInInternal( @nsConstants.RoveDirection int direction, PreCondition preCondition)75 protected String[] getPolicyInInternal( 76 @QnsConstants.RoveDirection int direction, PreCondition preCondition) { 77 return mConfig.getPolicy(direction, preCondition); 78 } 79 getPolicy( @nsConstants.RoveDirection int direction, PreCondition preCondition)80 protected String[] getPolicy( 81 @QnsConstants.RoveDirection int direction, PreCondition preCondition) { 82 String[] internalPolicies = getPolicyInInternal(direction, preCondition); 83 if (internalPolicies != null) { 84 return internalPolicies; 85 } 86 87 if (mConfig.isTransportTypeSelWithoutSSInRoamSupported() 88 && preCondition.getCoverage() == QnsConstants.COVERAGE_ROAM) { 89 if (mConfig.allowImsOverIwlanCellularLimitedCase()) { 90 List<Integer> supportedAccessNetworks = getSupportAccessNetworkTypes(); 91 List<String> policyImsOverIwlan = new ArrayList<>(); 92 for (int accessNetwork : supportedAccessNetworks) { 93 if (accessNetwork == IWLAN) { 94 continue; 95 } 96 if (mConfig.isAccessNetworkAllowed(accessNetwork, mNetCapability)) { 97 if (preCondition.getPreference() == QnsConstants.CELL_PREF 98 && direction == QnsConstants.ROVE_OUT) { 99 String name = 100 QnsConstants.accessNetworkTypeToString(accessNetwork) 101 + "_AVAILABLE"; 102 policyImsOverIwlan.add("Condition:WIFI_AVAILABLE," + name); 103 } else if (preCondition.getPreference() == QnsConstants.WIFI_PREF 104 && direction == QnsConstants.ROVE_IN) { 105 String name = 106 QnsConstants.accessNetworkTypeToString(accessNetwork) 107 + "_AVAILABLE"; 108 policyImsOverIwlan.add("Condition:WIFI_AVAILABLE," + name); 109 } 110 } else { 111 if (preCondition.getPreference() == QnsConstants.CELL_PREF 112 && direction == QnsConstants.ROVE_IN) { 113 String name = 114 QnsConstants.accessNetworkTypeToString(accessNetwork) 115 + "_AVAILABLE"; 116 policyImsOverIwlan.add("Condition:WIFI_AVAILABLE," + name); 117 } else if (preCondition.getPreference() == QnsConstants.WIFI_PREF 118 && direction == QnsConstants.ROVE_IN) { 119 String name = 120 QnsConstants.accessNetworkTypeToString(accessNetwork) 121 + "_AVAILABLE"; 122 policyImsOverIwlan.add("Condition:WIFI_AVAILABLE," + name); 123 } 124 } 125 } 126 return policyImsOverIwlan.toArray(String[]::new); 127 } else { 128 if (preCondition.getPreference() == QnsConstants.CELL_PREF 129 && direction == QnsConstants.ROVE_OUT) { 130 return new String[] {"Condition:WIFI_AVAILABLE"}; 131 } else if (preCondition.getPreference() == QnsConstants.WIFI_PREF 132 && direction == QnsConstants.ROVE_IN) { 133 return new String[] {"Condition:WIFI_AVAILABLE"}; 134 } else { 135 return new String[] {"Condition:"}; 136 } 137 } 138 } 139 if (mConfig.isCurrentTransportTypeInVoiceCallSupported() 140 && direction == QnsConstants.ROVE_OUT 141 && preCondition.getCallType() == QnsConstants.CALL_TYPE_VOICE 142 && preCondition.getPreference() == QnsConstants.CELL_PREF) { 143 return new String[] {"Condition:WIFI_BAD"}; 144 } 145 if (mConfig.isChooseWfcPreferredTransportInBothBadCondition(preCondition.getPreference())) { 146 if (direction == QnsConstants.ROVE_OUT 147 && preCondition.getPreference() == QnsConstants.CELL_PREF) { 148 return new String[] {"Condition:WIFI_BAD", "Condition:CELLULAR_GOOD"}; 149 } else if (direction == QnsConstants.ROVE_IN 150 && preCondition.getPreference() == QnsConstants.WIFI_PREF) { 151 return new String[] {"Condition:WIFI_GOOD", "Condition:CELLULAR_BAD"}; 152 } 153 } 154 155 return getPolicyInMap(direction, preCondition); 156 } 157 getSupportAccessNetworkTypes()158 protected List<Integer> getSupportAccessNetworkTypes() { 159 return List.of( 160 AccessNetworkType.NGRAN, 161 AccessNetworkType.EUTRAN, 162 AccessNetworkType.UTRAN, 163 AccessNetworkType.GERAN, 164 AccessNetworkType.IWLAN); 165 } 166 build( QnsCarrierConfigManager configManager, int netCapability)167 public static synchronized Map<PreCondition, List<AccessNetworkSelectionPolicy>> build( 168 QnsCarrierConfigManager configManager, int netCapability) { 169 AccessNetworkSelectionPolicyBuilder builder; 170 if (configManager.isOverrideImsPreferenceSupported()) { 171 builder = new AnspImsPreferModePolicyBuilder(configManager, netCapability); 172 } else { 173 builder = new AccessNetworkSelectionPolicyBuilder(configManager, netCapability); 174 } 175 return builder.buildAnsp(); 176 } 177 log(String log)178 protected void log(String log) { 179 Log.d(mLogTag, log); 180 } 181 182 protected String mLogTag = "QnsAnspBuilder"; 183 protected final QnsCarrierConfigManager mConfig; 184 protected final int mNetCapability; 185 AccessNetworkSelectionPolicyBuilder(QnsCarrierConfigManager configManager, int netCapability)186 AccessNetworkSelectionPolicyBuilder(QnsCarrierConfigManager configManager, int netCapability) { 187 mConfig = configManager; 188 mNetCapability = netCapability; 189 } 190 buildAnsp()191 protected Map<PreCondition, List<AccessNetworkSelectionPolicy>> buildAnsp() { 192 List<Integer> directionList = List.of(ROVE_IN, ROVE_OUT); 193 List<Integer> callTypeList = List.of(IDLE, VOICE, VIDEO); 194 List<Integer> preferenceList = List.of(WIFI_PREF, CELL_PREF); 195 List<Integer> coverageList = List.of(HOME, ROAM); 196 List<Integer> guardingList = List.of(GUARDING_NONE, GUARDING_CELL, GUARDING_WIFI); 197 198 Map<PreCondition, List<AccessNetworkSelectionPolicy>> allPolicies = new HashMap<>(); 199 boolean enabledGuardingPreCondition = mConfig.hasThresholdGapWithGuardTimer(); 200 for (int coverage : coverageList) { 201 for (int preference : preferenceList) { 202 for (int callType : callTypeList) { 203 for (int direction : directionList) { 204 if (enabledGuardingPreCondition) { 205 for (int guarding : guardingList) { 206 if (direction == ROVE_IN && guarding == GUARDING_CELL) { 207 continue; 208 } 209 if (direction == ROVE_OUT && guarding == GUARDING_WIFI) { 210 continue; 211 } 212 PreCondition preCondition = 213 new AccessNetworkSelectionPolicy.GuardingPreCondition( 214 callType, preference, coverage, guarding); 215 AccessNetworkSelectionPolicy ansp = 216 buildAccessNetworkSelectionPolicy(direction, preCondition); 217 allPolicies.computeIfAbsent( 218 ansp.getPreCondition(), k -> new ArrayList<>()); 219 allPolicies.get(ansp.getPreCondition()).add(ansp); 220 } 221 } else { 222 PreCondition preCondition = 223 new PreCondition(callType, preference, coverage); 224 AccessNetworkSelectionPolicy ansp = 225 buildAccessNetworkSelectionPolicy(direction, preCondition); 226 allPolicies.computeIfAbsent( 227 ansp.getPreCondition(), k -> new ArrayList<>()); 228 allPolicies.get(ansp.getPreCondition()).add(ansp); 229 } 230 } 231 } 232 } 233 } 234 return allPolicies; 235 } 236 buildAccessNetworkSelectionPolicy( @nsConstants.RoveDirection int direction, PreCondition preCondition)237 protected AccessNetworkSelectionPolicy buildAccessNetworkSelectionPolicy( 238 @QnsConstants.RoveDirection int direction, PreCondition preCondition) { 239 int transportType = direction == ROVE_IN ? WLAN : WWAN; 240 return new AccessNetworkSelectionPolicy( 241 mNetCapability, 242 transportType, 243 preCondition, 244 makeThresholdGroups(direction, preCondition)); 245 } 246 makeThresholdGroups( @nsConstants.RoveDirection int direction, PreCondition preCondition)247 protected List<ThresholdGroup> makeThresholdGroups( 248 @QnsConstants.RoveDirection int direction, PreCondition preCondition) { 249 String[] policy = getPolicy(direction, preCondition); 250 List<ThresholdGroup> thresholdGroups = new ArrayList<>(); 251 if (policy == null) { 252 return thresholdGroups; 253 } 254 255 for (String condition : policy) { 256 List<AnspItem> anspItems = parseCondition(condition, preCondition); 257 addThresholdGroup(thresholdGroups, anspItems, direction, preCondition); 258 } 259 260 List<Threshold> wifiWithoutThs = makeThresholdsWifiWithoutCellular(direction, preCondition); 261 if (!wifiWithoutThs.isEmpty()) { 262 addThresholdGroup(thresholdGroups, wifiWithoutThs); 263 } 264 265 return thresholdGroups; 266 } 267 parseCondition(String condition, PreCondition preCondition)268 protected List<AnspItem> parseCondition(String condition, PreCondition preCondition) { 269 List<AnspItem> anspItems = AnspItem.parseToPrimitives(condition); 270 List<Integer> supportedAccessNetworkTypes = getSupportAccessNetworkTypes(); 271 List<AnspItem> wifiAnspItems = new ArrayList<>(); 272 List<AnspItem> cellAnspItems = new ArrayList<>(); 273 List<AnspItem> wifiAvailableAnspItems = new ArrayList<>(); 274 List<AnspItem> cellAvailableAnspItems = new ArrayList<>(); 275 for (int supportedAccessNetwork : supportedAccessNetworkTypes) { 276 boolean bHasThreshold = false; 277 boolean bAddAvailable = false; 278 for (AnspItem anspItem : anspItems) { 279 if (supportedAccessNetwork != anspItem.getAccessNetwork()) { 280 continue; 281 } 282 if (hasThreshold(anspItem, preCondition)) { 283 bHasThreshold = true; 284 if (supportedAccessNetwork == IWLAN) { 285 wifiAnspItems.add(anspItem); 286 } else { 287 cellAnspItems.add(anspItem); 288 } 289 } else { 290 bAddAvailable = true; 291 } 292 } 293 294 if (!bHasThreshold && bAddAvailable) { 295 String itemName = 296 QnsConstants.accessNetworkTypeToString(supportedAccessNetwork) 297 + "_AVAILABLE"; 298 if (supportedAccessNetwork == IWLAN) { 299 wifiAvailableAnspItems.add(AnspItem.find(itemName)); 300 } else { 301 cellAvailableAnspItems.add(AnspItem.find(itemName)); 302 } 303 } 304 } 305 if (!wifiAnspItems.isEmpty() && !cellAvailableAnspItems.isEmpty()) { 306 cellAnspItems.addAll(cellAvailableAnspItems); 307 } 308 if (!cellAnspItems.isEmpty() && !wifiAvailableAnspItems.isEmpty()) { 309 wifiAnspItems.addAll(wifiAvailableAnspItems); 310 } 311 312 wifiAnspItems.addAll(cellAnspItems); 313 return wifiAnspItems; 314 } 315 addThresholdGroup( List<ThresholdGroup> thresholdGroups, List<Threshold> thresholds)316 protected void addThresholdGroup( 317 List<ThresholdGroup> thresholdGroups, List<Threshold> thresholds) { 318 for (ThresholdGroup thresholdGroup : thresholdGroups) { 319 if (thresholdGroup.identicalThreshold(thresholds)) { 320 return; 321 } 322 } 323 thresholdGroups.add(new ThresholdGroup(thresholds)); 324 } 325 addThresholdGroup( List<ThresholdGroup> thresholdGroups, List<AnspItem> anspItems, @QnsConstants.RoveDirection int direction, PreCondition preCondition)326 protected void addThresholdGroup( 327 List<ThresholdGroup> thresholdGroups, 328 List<AnspItem> anspItems, 329 @QnsConstants.RoveDirection int direction, 330 PreCondition preCondition) { 331 if (anspItems == null || anspItems.isEmpty()) { 332 return; 333 } 334 335 List<AnspItem> wifiAnspItems = new ArrayList<>(); 336 List<AnspItem> cellAnspItems = new ArrayList<>(); 337 List<Integer> supportedAccessNetworkTypes = getSupportAccessNetworkTypes(); 338 for (AnspItem anspItem : anspItems) { 339 if (anspItem.getAccessNetwork() == IWLAN) { 340 wifiAnspItems.add(anspItem); 341 } else { 342 cellAnspItems.add(anspItem); 343 } 344 } 345 346 if (direction == QnsConstants.ROVE_IN) { 347 if (!wifiAnspItems.isEmpty() && !cellAnspItems.isEmpty()) { 348 for (AnspItem wifi : wifiAnspItems) { 349 for (AnspItem cell : cellAnspItems) { 350 Threshold wifiTh = makeThreshold(wifi, direction, preCondition); 351 Threshold cellTh = makeThreshold(cell, direction, preCondition); 352 addThresholdGroup(thresholdGroups, List.of(wifiTh, cellTh)); 353 } 354 } 355 } else { 356 for (AnspItem cell : cellAnspItems) { 357 Threshold cellTh = makeThreshold(cell, direction, preCondition); 358 addThresholdGroup(thresholdGroups, List.of(cellTh)); 359 } 360 for (AnspItem wifi : wifiAnspItems) { 361 Threshold wifiTh = makeThreshold(wifi, direction, preCondition); 362 addThresholdGroup(thresholdGroups, List.of(wifiTh)); 363 } 364 } 365 } else { // ROVE_OUT 366 for (int supportedAccessNetwork : supportedAccessNetworkTypes) { 367 if (supportedAccessNetwork == IWLAN) { 368 continue; 369 } 370 List<Threshold> thresholdList = new ArrayList<>(); 371 for (AnspItem wifi : wifiAnspItems) { 372 Threshold wifiTh = makeThreshold(wifi, direction, preCondition); 373 thresholdList.add(wifiTh); 374 } 375 if (!cellAnspItems.isEmpty()) { 376 boolean isAddedThreshold = false; 377 for (AnspItem cell : cellAnspItems) { 378 if (cell.getAccessNetwork() == supportedAccessNetwork) { 379 Threshold cellTh = makeThreshold(cell, direction, preCondition); 380 thresholdList.add(cellTh); 381 isAddedThreshold = true; 382 } 383 } 384 if (!isAddedThreshold) { 385 continue; 386 } 387 } 388 if (!thresholdList.isEmpty()) { 389 addThresholdGroup(thresholdGroups, thresholdList); 390 } 391 } 392 } 393 } 394 makeThreshold( AnspItem anspItem, @QnsConstants.RoveDirection int direction, PreCondition preCondition)395 private Threshold makeThreshold( 396 AnspItem anspItem, 397 @QnsConstants.RoveDirection int direction, 398 PreCondition preCondition) { 399 int adjustThreshold = 0; 400 if (preCondition instanceof AccessNetworkSelectionPolicy.GuardingPreCondition) { 401 AccessNetworkSelectionPolicy.GuardingPreCondition guardingPreCondition = 402 (AccessNetworkSelectionPolicy.GuardingPreCondition) preCondition; 403 if (direction == ROVE_IN && guardingPreCondition.getGuarding() == GUARDING_WIFI) { 404 adjustThreshold = 405 mConfig.getThresholdGapWithGuardTimer( 406 anspItem.getAccessNetwork(), anspItem.getMeasurementType()); 407 } 408 } 409 return new Threshold( 410 anspItem.getAccessNetwork(), 411 anspItem.getMeasurementType(), 412 getThreshold(anspItem, preCondition) + adjustThreshold, 413 anspItem.getMatchType(), 414 getBackHaulTimer(anspItem.getAccessNetwork())); 415 } 416 hasThreshold(AnspItem anspItem, PreCondition preCondition)417 protected boolean hasThreshold(AnspItem anspItem, PreCondition preCondition) { 418 return getThreshold(anspItem, preCondition) != QnsConfigArray.INVALID; 419 } 420 getThreshold(AnspItem anspItem, PreCondition preCondition)421 protected int getThreshold(AnspItem anspItem, PreCondition preCondition) { 422 if (anspItem.getMeasurementType() == AVAILABILITY) { 423 if (anspItem.getQualityType() == AVAIL || anspItem.getQualityType() == UNAVAIL) { 424 return anspItem.getQualityType(); 425 } 426 return QnsConfigArray.INVALID; 427 } 428 QnsConfigArray thresholds = 429 mConfig.getThresholdByPref( 430 anspItem.getAccessNetwork(), 431 preCondition.getCallType(), 432 anspItem.getMeasurementType(), 433 preCondition.getPreference()); 434 if (thresholds == null) { 435 return QnsConfigArray.INVALID; 436 } 437 switch (anspItem.getQualityType()) { 438 case GOOD: 439 return thresholds.mGood; 440 case BAD: 441 return thresholds.mBad; 442 case TOLERABLE: 443 if (thresholds.mWorst != QnsConfigArray.INVALID) { 444 return thresholds.mWorst; 445 } 446 return thresholds.mBad; 447 } 448 return QnsConfigArray.INVALID; 449 } 450 makeUnavailableThreshold( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork)451 protected Threshold makeUnavailableThreshold( 452 @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork) { 453 int backHaulTimer = getBackHaulTimer(accessNetwork); 454 return new Threshold( 455 accessNetwork, 456 QnsConstants.SIGNAL_MEASUREMENT_AVAILABILITY, 457 UNAVAIL, 458 QnsConstants.THRESHOLD_MATCH_TYPE_EQUAL_TO, 459 backHaulTimer); 460 } 461 makeThresholdsWifiWithoutCellular( @nsConstants.RoveDirection int direction, PreCondition preCondition)462 protected List<Threshold> makeThresholdsWifiWithoutCellular( 463 @QnsConstants.RoveDirection int direction, PreCondition preCondition) { 464 List<Threshold> thresholds = new ArrayList<>(); 465 int backHaulTimer = getBackHaulTimer(AccessNetworkConstants.AccessNetworkType.IWLAN); 466 467 QnsConfigArray threshold = 468 mConfig.getWifiRssiThresholdWithoutCellular(preCondition.getCallType()); 469 if (threshold == null) { 470 return thresholds; 471 } 472 if (threshold.mGood != QnsConfigArray.INVALID && direction == QnsConstants.ROVE_IN) { 473 thresholds.add( 474 new Threshold( 475 AccessNetworkConstants.AccessNetworkType.IWLAN, 476 SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, 477 threshold.mGood, 478 QnsConstants.THRESHOLD_EQUAL_OR_LARGER, 479 backHaulTimer)); 480 } 481 if (threshold.mBad != QnsConfigArray.INVALID && direction == QnsConstants.ROVE_OUT) { 482 thresholds.add( 483 new Threshold( 484 AccessNetworkConstants.AccessNetworkType.IWLAN, 485 SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, 486 threshold.mBad, 487 QnsConstants.THRESHOLD_EQUAL_OR_SMALLER, 488 backHaulTimer)); 489 } 490 if (!thresholds.isEmpty()) { 491 for (int an : getSupportAccessNetworkTypes()) { 492 if (an == IWLAN) { 493 continue; 494 } 495 thresholds.add(makeUnavailableThreshold(an)); 496 } 497 } 498 return thresholds; 499 } 500 getBackHaulTimer(int accessNetwork)501 private int getBackHaulTimer(int accessNetwork) { 502 if (accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN) { 503 return mConfig.getWIFIRssiBackHaulTimer(); 504 } 505 return mConfig.getCellularSSBackHaulTimer(); 506 } 507 508 static final int AVAILABILITY = QnsConstants.SIGNAL_MEASUREMENT_AVAILABILITY; 509 static final int EQUAL = QnsConstants.THRESHOLD_MATCH_TYPE_EQUAL_TO; 510 static final int LARGER = QnsConstants.THRESHOLD_EQUAL_OR_LARGER; 511 static final int SMALLER = QnsConstants.THRESHOLD_EQUAL_OR_SMALLER; 512 static final int NGRAN = AccessNetworkConstants.AccessNetworkType.NGRAN; 513 static final int EUTRAN = AccessNetworkConstants.AccessNetworkType.EUTRAN; 514 static final int UTRAN = AccessNetworkConstants.AccessNetworkType.UTRAN; 515 static final int GERAN = AccessNetworkConstants.AccessNetworkType.GERAN; 516 static final int RSSI = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI; 517 static final int SSRSRP = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP; 518 static final int SSRSRQ = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ; 519 static final int SSSINR = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR; 520 static final int RSRP = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP; 521 static final int RSRQ = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ; 522 static final int RSSNR = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR; 523 static final int RSCP = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP; 524 static final int ECNO = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO; 525 static final int AVAIL = QnsConstants.SIGNAL_AVAILABLE; 526 static final int UNAVAIL = QnsConstants.SIGNAL_UNAVAILABLE; 527 static final int GOOD = QnsConstants.POLICY_GOOD; 528 static final int BAD = QnsConstants.POLICY_BAD; 529 static final int TOLERABLE = QnsConstants.POLICY_TOLERABLE; 530 531 enum AnspItem { 532 IWLAN_AVAILABLE("IWLAN_AVAILABLE", IWLAN, AVAILABILITY, EQUAL, AVAIL), 533 IWLAN_UNAVAILABLE("IWLAN_UNAVAILABLE", IWLAN, AVAILABILITY, EQUAL, UNAVAIL), 534 IWLAN_RSSI_GOOD("IWLAN_RSSI_GOOD", IWLAN, RSSI, LARGER, GOOD), 535 IWLAN_RSSI_BAD("IWLAN_RSSI_BAD", IWLAN, RSSI, SMALLER, BAD), 536 537 NGRAN_AVAILABLE("NGRAN_AVAILABLE", NGRAN, AVAILABILITY, EQUAL, AVAIL), 538 NGRAN_UNAVAILABLE("NGRAN_UNAVAILABLE", NGRAN, AVAILABILITY, EQUAL, UNAVAIL), 539 NGRAN_SSRSRP_GOOD("NGRAN_SSRSRP_GOOD", NGRAN, SSRSRP, LARGER, GOOD), 540 NGRAN_SSRSRP_BAD("NGRAN_SSRSRP_BAD", NGRAN, SSRSRP, SMALLER, BAD), 541 NGRAN_SSRSRP_TOLERABLE("NGRAN_SSRSRP_TOLERABLE", NGRAN, SSRSRP, LARGER, TOLERABLE), 542 NGRAN_SSRSRQ_GOOD("NGRAN_SSRSRQ_GOOD", NGRAN, SSRSRQ, LARGER, GOOD), 543 NGRAN_SSRSRQ_BAD("NGRAN_SSRSRQ_BAD", NGRAN, SSRSRQ, SMALLER, BAD), 544 NGRAN_SSRSRQ_TOLERABLE("NGRAN_SSRSRQ_TOLERABLE", NGRAN, SSRSRQ, LARGER, TOLERABLE), 545 NGRAN_SSSINR_GOOD("NGRAN_SSSINR_GOOD", NGRAN, SSSINR, LARGER, GOOD), 546 NGRAN_SSSINR_BAD("NGRAN_SSSINR_BAD", NGRAN, SSSINR, SMALLER, BAD), 547 NGRAN_SSSINR_TOLERABLE("NGRAN_SSSINR_TOLERABLE", NGRAN, SSSINR, LARGER, TOLERABLE), 548 549 EUTRAN_AVAILABLE("EUTRAN_AVAILABLE", EUTRAN, AVAILABILITY, EQUAL, AVAIL), 550 EUTRAN_UNAVAILABLE("EUTRAN_UNAVAILABLE", EUTRAN, AVAILABILITY, EQUAL, UNAVAIL), 551 EUTRAN_RSRP_GOOD("EUTRAN_RSRP_GOOD", EUTRAN, RSRP, LARGER, GOOD), 552 EUTRAN_RSRP_BAD("EUTRAN_RSRP_BAD", EUTRAN, RSRP, SMALLER, BAD), 553 EUTRAN_RSRP_TOLERABLE("EUTRAN_RSRP_TOLERABLE", EUTRAN, RSRP, LARGER, TOLERABLE), 554 EUTRAN_RSRQ_GOOD("EUTRAN_RSRQ_GOOD", EUTRAN, RSRQ, LARGER, GOOD), 555 EUTRAN_RSRQ_BAD("EUTRAN_RSRQ_BAD", EUTRAN, RSRQ, SMALLER, BAD), 556 EUTRAN_RSRQ_TOLERABLE("EUTRAN_RSRQ_TOLERABLE", EUTRAN, RSRQ, LARGER, TOLERABLE), 557 EUTRAN_RSSNR_GOOD("EUTRAN_RSSNR_GOOD", EUTRAN, RSSNR, LARGER, GOOD), 558 EUTRAN_RSSNR_BAD("EUTRAN_RSSNR_BAD", EUTRAN, RSSNR, SMALLER, BAD), 559 EUTRAN_RSSNR_TOLERABLE("EUTRAN_RSSNR_TOLERABLE", EUTRAN, RSSNR, LARGER, TOLERABLE), 560 561 UTRAN_AVAILABLE("UTRAN_AVAILABLE", UTRAN, AVAILABILITY, EQUAL, AVAIL), 562 UTRAN_UNAVAILABLE("UTRAN_UNAVAILABLE", UTRAN, AVAILABILITY, EQUAL, UNAVAIL), 563 UTRAN_RSCP_GOOD("UTRAN_RSCP_GOOD", UTRAN, RSCP, LARGER, GOOD), 564 UTRAN_RSCP_BAD("UTRAN_RSCP_BAD", UTRAN, RSCP, SMALLER, BAD), 565 UTRAN_RSCP_TOLERABLE("UTRAN_RSCP_TOLERABLE", UTRAN, RSCP, LARGER, TOLERABLE), 566 UTRAN_ECNO_GOOD("UTRAN_ECNO_GOOD", UTRAN, ECNO, LARGER, GOOD), 567 UTRAN_ECNO_BAD("UTRAN_ECNO_BAD", UTRAN, ECNO, SMALLER, BAD), 568 UTRAN_ECNO_TOLERABLE("UTRAN_ECNO_TOLERABLE", UTRAN, ECNO, LARGER, TOLERABLE), 569 570 GERAN_AVAILABLE("GERAN_AVAILABLE", GERAN, AVAILABILITY, EQUAL, AVAIL), 571 GERAN_UNAVAILABLE("GERAN_UNAVAILABLE", GERAN, AVAILABILITY, EQUAL, UNAVAIL), 572 GERAN_RSSI_GOOD("GERAN_RSSI_GOOD", GERAN, RSSI, LARGER, GOOD), 573 GERAN_RSSI_BAD("GERAN_RSSI_BAD", GERAN, RSSI, SMALLER, BAD), 574 GERAN_RSSI_TOLERABLE("GERAN_RSSI_TOLERABLE", GERAN, RSSI, LARGER, TOLERABLE), 575 576 IWLAN_GOOD("IWLAN_GOOD", new AnspItem[] {IWLAN_RSSI_GOOD}), 577 IWLAN_BAD("IWLAN_BAD", new AnspItem[] {IWLAN_RSSI_BAD}), 578 WIFI_AVAILABLE("WIFI_AVAILABLE", new AnspItem[] {IWLAN_AVAILABLE}), 579 WIFI_UNAVAILABLE("WIFI_UNAVAILABLE", new AnspItem[] {IWLAN_UNAVAILABLE}), 580 WIFI_GOOD("WIFI_GOOD", new AnspItem[] {IWLAN_GOOD}), 581 WIFI_BAD("WIFI_BAD", new AnspItem[] {IWLAN_BAD}), 582 583 NGRAN_GOOD( 584 "NGRAN_GOOD", 585 new AnspItem[] {NGRAN_SSRSRP_GOOD, NGRAN_SSRSRQ_GOOD, NGRAN_SSSINR_GOOD}), 586 NGRAN_BAD( 587 "NGRAN_BAD", new AnspItem[] {NGRAN_SSRSRP_BAD, NGRAN_SSRSRQ_BAD, NGRAN_SSSINR_BAD}), 588 NGRAN_TOLERABLE( 589 "NGRAN_TOLERABLE", 590 new AnspItem[] { 591 NGRAN_SSRSRP_TOLERABLE, NGRAN_SSRSRQ_TOLERABLE, NGRAN_SSSINR_TOLERABLE 592 }), 593 594 EUTRAN_GOOD( 595 "EUTRAN_GOOD", 596 new AnspItem[] {EUTRAN_RSRP_GOOD, EUTRAN_RSRQ_GOOD, EUTRAN_RSSNR_GOOD}), 597 EUTRAN_BAD( 598 "EUTRAN_BAD", new AnspItem[] {EUTRAN_RSRP_BAD, EUTRAN_RSRQ_BAD, EUTRAN_RSSNR_BAD}), 599 EUTRAN_TOLERABLE( 600 "EUTRAN_TOLERABLE", 601 new AnspItem[] { 602 EUTRAN_RSRP_TOLERABLE, EUTRAN_RSRQ_TOLERABLE, EUTRAN_RSSNR_TOLERABLE 603 }), 604 605 UTRAN_GOOD("UTRAN_GOOD", new AnspItem[] {UTRAN_RSCP_GOOD, UTRAN_ECNO_GOOD}), 606 UTRAN_BAD("UTRAN_BAD", new AnspItem[] {UTRAN_RSCP_BAD, UTRAN_ECNO_BAD}), 607 UTRAN_TOLERABLE( 608 "UTRAN_TOLERABLE", new AnspItem[] {UTRAN_RSCP_TOLERABLE, UTRAN_ECNO_TOLERABLE}), 609 610 GERAN_GOOD("GERAN_GOOD", new AnspItem[] {GERAN_RSSI_GOOD}), 611 GERAN_BAD("GERAN_BAD", new AnspItem[] {GERAN_RSSI_BAD}), 612 GERAN_TOLERABLE("GERAN_TOLERABLE", new AnspItem[] {GERAN_RSSI_TOLERABLE}), 613 614 CELLULAR_AVAILABLE( 615 "CELLULAR_AVAILABLE", 616 new AnspItem[] { 617 NGRAN_AVAILABLE, EUTRAN_AVAILABLE, UTRAN_AVAILABLE, GERAN_AVAILABLE 618 }), 619 CELLULAR_UNAVAILABLE( 620 "CELLULAR_UNAVAILABLE", 621 new AnspItem[] { 622 NGRAN_UNAVAILABLE, EUTRAN_UNAVAILABLE, UTRAN_UNAVAILABLE, GERAN_UNAVAILABLE 623 }), 624 CELLULAR_GOOD( 625 "CELLULAR_GOOD", new AnspItem[] {NGRAN_GOOD, EUTRAN_GOOD, UTRAN_GOOD, GERAN_GOOD}), 626 CELLULAR_BAD("CELLULAR_BAD", new AnspItem[] {NGRAN_BAD, EUTRAN_BAD, UTRAN_BAD, GERAN_BAD}), 627 CELLULAR_TOLERABLE( 628 "CELLULAR_TOLERABLE", 629 new AnspItem[] { 630 NGRAN_TOLERABLE, EUTRAN_TOLERABLE, UTRAN_TOLERABLE, GERAN_TOLERABLE 631 }), 632 ; 633 private static final Map<String, AnspItem> sAnspItemMap; 634 635 static { 636 sAnspItemMap = 637 Collections.unmodifiableMap( 638 Arrays.stream(values()) 639 .collect( 640 Collectors.toMap( 641 AnspItem::getName, 642 anspItem -> anspItem, 643 (a, b) -> b))); 644 } 645 646 private final String mName; 647 private final int mAccessNetwork; 648 private final int mMeasurementType; 649 private final int mMatchType; 650 private final int mQualityType; 651 private final AnspItem[] mAnspItems; 652 AnspItem(String name, AnspItem[] items)653 AnspItem(String name, AnspItem[] items) { 654 mName = name; 655 mAnspItems = items; 656 mAccessNetwork = -1; 657 mMeasurementType = -1; 658 mMatchType = -1; 659 mQualityType = -1; 660 } 661 AnspItem( String name, int accessNetwork, int measurementType, int matchType, int qualityType)662 AnspItem( 663 String name, 664 int accessNetwork, 665 int measurementType, 666 int matchType, 667 int qualityType) { 668 mName = name; 669 mAnspItems = null; 670 mAccessNetwork = accessNetwork; 671 mMeasurementType = measurementType; 672 mMatchType = matchType; 673 mQualityType = qualityType; 674 } 675 getName()676 private String getName() { 677 return mName; 678 } 679 find(String item)680 static AnspItem find(String item) { 681 return sAnspItemMap.get(item); 682 } 683 parseToPrimitives(String condition)684 static List<AnspItem> parseToPrimitives(String condition) { 685 List<AnspItem> primitives = new ArrayList<>(); 686 if (condition == null) { 687 return primitives; 688 } 689 690 if (condition.startsWith("Condition:")) { 691 StringTokenizer st = new StringTokenizer(condition, ":,"); 692 st.nextToken(); 693 while (st.hasMoreTokens()) { 694 String token = st.nextToken(); 695 AnspItem anspItem = AnspItem.find(token); 696 primitives.addAll(anspItem.toPrimitives()); 697 } 698 } 699 return primitives; 700 } 701 toPrimitives()702 private Collection<AnspItem> toPrimitives() { 703 if (isPrimitive()) { 704 return List.of(this); 705 } 706 List<AnspItem> primitives = new ArrayList<>(); 707 for (AnspItem item : mAnspItems) { 708 primitives.addAll(item.toPrimitives()); 709 } 710 return primitives; 711 } 712 isPrimitive()713 boolean isPrimitive() { 714 return mAnspItems == null; 715 } 716 getAccessNetwork()717 int getAccessNetwork() { 718 return mAccessNetwork; 719 } 720 getMeasurementType()721 int getMeasurementType() { 722 return mMeasurementType; 723 } 724 getMatchType()725 int getMatchType() { 726 return mMatchType; 727 } 728 getQualityType()729 int getQualityType() { 730 return mQualityType; 731 } 732 } 733 734 /** 735 * The class AnspKey is the AccessNetworkSelectionPolicy inner class that is used to store or 736 * load policies in a hashmap. 737 */ 738 static class AnspKey { 739 private static final int INVALID = 0xFFFF; 740 int mKey1; 741 int mKey2; 742 int mKey3; 743 int mKey4; 744 AnspKey(int k1, int k2)745 AnspKey(int k1, int k2) { 746 this.mKey1 = k1; 747 this.mKey2 = k2; 748 this.mKey3 = INVALID; 749 this.mKey4 = INVALID; 750 } 751 AnspKey(int k1, int k2, int k3)752 AnspKey(int k1, int k2, int k3) { 753 this.mKey1 = k1; 754 this.mKey2 = k2; 755 this.mKey3 = k3; 756 this.mKey4 = INVALID; 757 } 758 AnspKey(int k1, int k2, int k3, int k4)759 AnspKey(int k1, int k2, int k3, int k4) { 760 this.mKey1 = k1; 761 this.mKey2 = k2; 762 this.mKey3 = k3; 763 this.mKey4 = k4; 764 } 765 766 @Override toString()767 public String toString() { 768 return "MultiKey{" 769 + "mKey1=" 770 + mKey1 771 + ", mKey2=" 772 + mKey2 773 + ", mKey3=" 774 + mKey3 775 + ", mKey4=" 776 + mKey4 777 + '}'; 778 } 779 780 @Override equals(Object o)781 public boolean equals(Object o) { 782 if (this == o) return true; 783 if (!(o instanceof AnspKey)) return false; 784 AnspKey ak = (AnspKey) o; 785 return mKey1 == ak.mKey1 && mKey2 == ak.mKey2 && mKey3 == ak.mKey3 && mKey4 == ak.mKey4; 786 } 787 788 @Override hashCode()789 public int hashCode() { 790 return Objects.hash(mKey1, mKey2, mKey3, mKey4); 791 } 792 } 793 } 794