• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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