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 static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
20 import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
21 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO;
22 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP;
23 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP;
24 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ;
25 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI;
26 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR;
27 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP;
28 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ;
29 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR;
30 import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_UNKNOWN;
31 import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
32 
33 import static com.android.telephony.qns.QnsConstants.FALLBACK_REASON_INVALID;
34 import static com.android.telephony.qns.QnsConstants.MAX_COUNT_INVALID;
35 import static com.android.telephony.qns.wfc.WfcCarrierConfigManager.KEY_QNS_VOWIFI_REGISTATION_TIMER_FOR_VOWIFI_ACTIVATION_INT;
36 
37 import android.annotation.IntDef;
38 import android.annotation.NonNull;
39 import android.content.Context;
40 import android.net.NetworkCapabilities;
41 import android.os.Handler;
42 import android.os.HandlerThread;
43 import android.os.Looper;
44 import android.os.Message;
45 import android.os.PersistableBundle;
46 import android.telephony.AccessNetworkConstants;
47 import android.telephony.Annotation.NetCapability;
48 import android.telephony.CarrierConfigManager;
49 import android.telephony.SignalThresholdInfo;
50 import android.telephony.SubscriptionManager;
51 import android.telephony.TelephonyManager;
52 import android.telephony.ims.ImsMmTelManager;
53 import android.telephony.ims.ProvisioningManager;
54 import android.text.TextUtils;
55 import android.util.ArraySet;
56 import android.util.Log;
57 
58 import com.android.internal.annotations.VisibleForTesting;
59 
60 import java.lang.annotation.Retention;
61 import java.lang.annotation.RetentionPolicy;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Collections;
65 import java.util.HashSet;
66 import java.util.List;
67 import java.util.Locale;
68 import java.util.Map;
69 import java.util.Set;
70 import java.util.stream.Collectors;
71 
72 /**
73  * This class supports loading Ansp(Access Network Selection Policy , Thresholds , Handover Polices
74  * & Other Supporting Carrier configurations , to support ANE to decide on the HO decision
75  * management & listing related Access Network to pass to Telephony
76  */
77 class QnsCarrierConfigManager {
78     /**
79      * Boolean indicating the WFC services in QNS Side is enabled, when airplane mode is On
80      *
81      * <p>{@code true}: QNS is enabled for WFC services in airplane mode on. {@code false}: QNS is
82      * disabled for WFC services in airplane mode on. The default value for this key is {@code true}
83      */
84     static final String KEY_QNS_SUPPORT_WFC_DURING_AIRPLANE_MODE_BOOL =
85             "qns.support_wfc_during_airplane_mode_bool";
86 
87     /**
88      * Boolean indicating if in-call handover decision from WLAN to WWAN should consider VoPS
89      * status.
90      *
91      * <p>{@code true}: In-call handover decision from WLAN to WWAN won't consider VoPS status, for
92      * example, UE can perform handover from WLAN to LTE even if LTE network does not support VoPS.
93      * {@code false}: In-call handover decision from WLAN to WWAN will consider VoPS status, for
94      * example, UE should not perform handover from WLAN to LTE if LTE network does not support
95      * VoPS.
96      * The default value for this key is {@code false}
97      */
98     static final String KEY_IN_CALL_HO_DECISION_WLAN_TO_WWAN_WITHOUT_VOPS_CONDITION_BOOL =
99             "qns.in_call_ho_decision_wlan_to_wwan_without_vops_condition_bool";
100 
101     /**
102      * Boolean indicating Iwlan TransportType priority is enabled , when VOPS(Voice Over PS Session)
103      * flag from NW is false .
104      *
105      * <p>{@code true}: Iwlan TransportType selection priority is enabled, when VOPS(Voice Over PS
106      * Session) is false. {@code false}: Iwlan TransportType selection priority is disabled, when
107      * VOPS (Voice Over PS Session) is false. The default value for this key is {@code true}
108      */
109     static final String KEY_QNS_VOPS_NOTAVAILABLE_PRIORITY_IWLAN_BOOL =
110             "qns.support_vops_notavailable_priority_iwlan_bool";
111 
112     /**
113      * Boolean indicating when disabled , supporting of Guard Timer applied to both TransportType
114      * WWAN (Cellular) & WLAN ( Wifi)
115      *
116      * <p>{@code false}: Whe Disabled , Guard timer (To avoid Ping Pong) is executed for both the
117      * direction ( ie Cellular to Wifi & Wifi to Cellular) {@code true}: when enabled , Guard timer
118      * (To avoid Ping Pong) is executed only based on the preference set. The default value for this
119      * key is {@code false}
120      */
121     static final String KEY_QNS_HO_GUARDING_BY_PREFERENCE_BOOL =
122             "qns.ho_guarding_by_preference_bool";
123     /**
124      * Boolean indicating the Service Barring check is disabled, when making HO decision from
125      * transport type WWAN (Cellular) to Transport type WLAN Wifi
126      *
127      * <p>{@code false}: Service Barring check is disabled , when making HO decision from transport
128      * type WWAN (Cellular) to Transport type WLAN Wifi {@code true}: Service Barring check is
129      * enabled , when making HO decision from transport type WWAN (Cellular) to Transport type WLAN
130      * Wifi The default value for this key is {@code false}
131      */
132     static final String KEY_QNS_SUPPORT_SERVICE_BARRING_CHECK_BOOL =
133             "qns.support_service_barring_check_bool";
134 
135     /**
136      * Boolean indicating the transport type selection without Signal Strength is disabled, during
137      * roaming condition
138      *
139      * <p>{@code false}: when disabled , transport type selection is based on RAT existence & signal
140      * quality during roaming.. {@code true}: when enabled , transport type selection is based on
141      * RAT availability during roaming. (not depends on Signal Strength) The default value for this
142      * key is {@code false}
143      */
144     static final String KEY_ROAM_TRANSPORT_TYPE_SELECTION_WITHOUT_SIGNAL_STRENGTH_BOOL =
145             "qns.roam_transport_type_selection_without_signal_strength_bool";
146 
147     /**
148      * Boolean indicating the preference to select/continue call in current Transport Type is
149      * disabled.
150      *
151      * <p>{@code false}: When disabled , preference to select/continue call in current Transport
152      * Type is not allowed {@code true}: When enabled , preference to select/continue call in
153      * current Transport Type is allowed The default value for this key is {@code false}
154      */
155     static final String KEY_PREFER_CURRENT_TRANSPORT_TYPE_IN_VOICE_CALL_BOOL =
156             "qns.prefer_current_transport_type_in_voice_call_bool";
157 
158     /**
159      * Boolean to override IMS Mode Preference from cellular preference.
160      *
161      * <p>{@code false}: When disabled , no ims override preference. {@code true}: When enabled ,
162      * load ims mode preference instead of cellular mode preference at home network. The default
163      * value for this key is {@code false}
164      */
165     static final String KEY_POLICY_OVERRIDE_CELL_PREF_TO_IMS_PREF_HOME_BOOL =
166             "qns.override_cell_pref_to_ims_pref_home";
167 
168     /**
169      * Boolean indicating allowing video call over wifi is disabled , when cellular limited case
170      * meets.(ie no LTE home network is available, or if an LTE home network is available but VoPS
171      * is disabled or has 100% SSAC voice barring)
172      *
173      * <p>{@code false}: When disabled , preference to allow video call on meeting cellular limited
174      * case conditions over Wifi is not allowed. {@code true}: When enabled , preference to move
175      * video call on meeting cellular limited case conditions over Wifi is allowed. The default
176      * value for this key is {@code false}
177      */
178     static final String KEY_QNS_ALLOW_VIDEO_OVER_IWLAN_WITH_CELLULAR_LIMITED_CASE_BOOL =
179             "qns.allow_video_over_iwlan_with_cellular_limited_case_bool";
180 
181     /**
182      * Boolean indicating cellular2WiFi-hysteresis Scenario rove out policies of WIth WIfi Bad
183      * criteria check with Guard TImer conditions is disabled.
184      *
185      * <p>{@code false}: When disabled , cellular2WiFi-hysteresis Scenario rove out policies during
186      * guard timer conditions(Running/Expired state) is not available {@code true}: When enabled ,
187      * cellular2WiFi-hysteresis Scenario rove out policies during guard timer
188      * conditions(Running/Expired state) is available The default value for this key is {@code
189      * false}
190      */
191     static final String KEY_QNS_ROVE_OUT_POLICY_WITH_WIFI_BAD_GUARDTIMER_CONDITIONS_BOOL =
192             "qns.rove_out_policy_with_wifi_bad_guardtimer_conditions_bool";
193 
194     /**
195      * Boolean indicating enabling of Wi-Fi call when in a call state idle with a cellular network
196      * that does not support ims pdn.
197      *
198      * <p>{@code false}: When disabled , There is no action to enable Wi-Fi Calling. {@code true}:
199      * When enabled , Enable Wi-Fi calling, if the call state is idle and the cellular network the
200      * UE is staying on does not allow ims pdn. The default value for this key is {@code false}
201      */
202     static final String KEY_QNS_ALLOW_IMS_OVER_IWLAN_CELLULAR_LIMITED_CASE_BOOL =
203             "qns.allow_ims_over_iwlan_cellular_limited_case_bool";
204 
205     /**
206      * Boolean indicating if to block IWLAN when UE is in no WWAN coverage and the last stored
207      * country code is outside the home country.
208      * By default this value is {@code false}.
209      */
210     static final String KEY_BLOCK_IWLAN_IN_INTERNATIONAL_ROAMING_WITHOUT_WWAN_BOOL =
211             "qns.block_iwlan_in_international_roaming_without_wwan_bool";
212 
213     /**
214      * Boolean indicating if to block IWLAN when UE is connected to IPv6 only WiFi AP. The setting
215      * may only apply on Android T. For Android U onwards, we may support a carrier config at IWLAN
216      * if we still encounter any issues for IPv6 WFC. By default this value is {@code true}.
217      */
218     static final String KEY_BLOCK_IPV6_ONLY_WIFI_BOOL = "qns.block_ipv6_only_wifi_bool";
219 
220     /**
221      * Specifies the Rat Preference for the XCAP network capability. Boolean indicating adding the
222      * IMS Registration condition to the Wi-Fi Rove in condition.
223      *
224      * <ul>
225      *   <li>{@code QnsConstants#RAT_PREFERENCE_DEFAULT}: Default, Follow the system preference.
226      *   <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_ONLY}: If set , choose Wi-Fi always
227      *   <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE}: If set , choose Wi-Fi when
228      *       the Wi-Fi Calling is available.(when IMS is registered through the Wi-Fi)
229      *   <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR}: If set , choose Wi-Fi when
230      *       no cellular
231      *   <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE}: If set , choose
232      *       Wi-Fi when cellular is available at home network.
233      * </ul>
234      */
235     static final String KEY_QNS_XCAP_RAT_PREFERENCE_INT = "qns.xcap_rat_preference_int";
236 
237     /**
238      * Specifies the Rat Preference for the SOS network capability. Boolean indicating adding the
239      * IMS Registration condition to the Wi-Fi Rove in condition.
240      *
241      * <ul>
242      *   <li>{@code QnsConstants#RAT_PREFERENCE_DEFAULT}: Default, Follow the system preference.
243      *   <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_ONLY}: If set , choose Wi-Fi always
244      *   <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE}: If set , choose Wi-Fi when
245      *       the Wi-Fi Calling is available.(when IMS is registered through the Wi-Fi)
246      *   <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR}: If set , choose Wi-Fi when
247      *       no cellular
248      *   <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE}: If set , choose
249      *       Wi-Fi when cellular is available at home network.
250      * </ul>
251      */
252     static final String KEY_QNS_SOS_RAT_PREFERENCE_INT = "qns.sos_rat_preference_int";
253 
254     /**
255      * Specifies the Rat Preference for the MMS network capability. Boolean indicating adding the
256      * IMS Registration condition to the Wi-Fi Rove in condition.
257      *
258      * <p>{@code QnsConstants#RAT_PREFERENCE_DEFAULT}: Default value , Follow the system preference.
259      * {@code QnsConstants#RAT_PREFERENCE_WIFI_ONLY}: If set , choose Wi-Fi always {@code
260      * QnsConstants#RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE}: If set , choose Wi-Fi when the Wi-Fi
261      * Calling is available.(when IMS is registered through the Wi-Fi) {@code
262      * QnsConstants#RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR}: If set , choose Wi-Fi when no cellular
263      * {@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE}: If set , choose Wi-Fi
264      * when cellular is available at home network. The default value for this key is {@code
265      * QnsConstants#RAT_PREFERENCE_DEFAULT}
266      */
267     static final String KEY_QNS_MMS_RAT_PREFERENCE_INT = "qns.mms_rat_preference_int";
268 
269     /**
270      * Specifies the Rat Preference for the CBS network capability. Boolean indicating adding the
271      * IMS Registration condition to the Wi-Fi Rove in condition.
272      *
273      * <p>{@code QnsConstants#RAT_PREFERENCE_DEFAULT}: Default value , Follow the system preference.
274      * {@code QnsConstants#RAT_PREFERENCE_WIFI_ONLY}: If set , choose Wi-Fi always {@code
275      * QnsConstants#RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE}: If set , choose Wi-Fi when the Wi-Fi
276      * Calling is available.(when IMS is registered through the Wi-Fi) {@code
277      * QnsConstants#RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR}: If set , choose Wi-Fi when no cellular
278      * {@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE}: If set , choose Wi-Fi
279      * when cellular is available at home network. The default value for this key is {@code
280      * QnsConstants#RAT_PREFERENCE_DEFAULT}
281      */
282     static final String KEY_QNS_CBS_RAT_PREFERENCE_INT = "qns.cbs_rat_preference_int";
283 
284     /**
285      * Specifies the interval at which the Wifi Backhaul timer in milli seconds, for threshold Wifi
286      * rssi signal strength fluctuation in case, on meeting the criteria in Rove In Scenario (Moving
287      * to Cellular to Wifi) {@link QnsConstants}. The values are set as below:
288      *
289      * <ul>
290      *   <li>0: {@link QnsConstants#DEFAULT_WIFI_BACKHAUL_TIMER}
291      *   <li>1: {@link QnsConstants#KEY_DEFAULT_VALUE}
292      * </ul>
293      *
294      * &As per operator Requirements.
295      *
296      * <p>{@code QnsConstants#DEFAULT_WIFI_BACKHAUL_TIMER}: If set , specifies interval of 3secs
297      * running the backhaul check(To avoid Wifi Fluctuation) on meeting the criteria in Rove in case
298      * {@code QnsConstants#KEY_DEFAULT_VALUE}: If set , this feature to be disabled <As per Operator
299      * requirement configurable>: If this value set , specifies interval in milli seconds running
300      * the backhaul check. The default value for this key is {@link
301      * QnsConstants#DEFAULT_WIFI_BACKHAUL_TIMER}
302      */
303     static final String KEY_QNS_WIFI_RSSI_THRESHOLDBACKHAUL_TIMER_MS_INT =
304             "qns.wifi_rssi_thresholdbackhaul_timer_int";
305 
306     /**
307      * Specifies the interval at which the Cellular Backhaul timer in milli seconds for cellular
308      * signal strengths fluctuation in case, on meeting the criteria in Rove out Scenario (Moving to
309      * Wifi from Cellular) The values are set as below:
310      *
311      * <ul>
312      *   <li>0: {@link QnsConstants#KEY_DEFAULT_VALUE}
313      * </ul>
314      *
315      * &As per operator Requirements.
316      *
317      * <p>{@code QnsConstants#KEY_DEFAULT_VALUE}: If set , this feature to be disabled <As per
318      * Operator requirement configurable>: If this value set , specifies interval in milli seconds
319      * running the backhaul check over Cellular in Rove Out The default value for this key is {@link
320      * QnsConstants#KEY_DEFAULT_VALUE}
321      */
322     static final String KEY_QNS_CELLULAR_SS_THRESHOLDBACKHAUL_TIMER_MS_INT =
323             "qns.cellular_ss_thresholdbackhaul_timer_int";
324 
325     /**
326      * Specifies the Transport type UE supports with QNS services for IMS network capability. {@link
327      * QnsConstants}. The values are set as below:
328      *
329      * <ul>
330      *   <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}
331      *   <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}
332      *   <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}
333      * </ul>
334      *
335      * {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is
336      * cellular for IMS network capability. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If
337      * this value set , Transport type UE supports is Wifi for IMS network capability. {@code
338      * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is
339      * both Cellular & Wifi for IMS network capability The default value for this key is {@link
340      * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}
341      */
342     static final String KEY_QNS_IMS_TRANSPORT_TYPE_INT = "qns.ims_transport_type_int";
343 
344     /**
345      * Specifies the Transport type UE supports with QNS services for SOS network capability. {@link
346      * QnsConstants}. The values are set as below:
347      *
348      * <ul>
349      *   <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}
350      *   <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}
351      *   <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}
352      * </ul>
353      *
354      * {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is
355      * cellular for SOS network capability. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If
356      * this value set , Transport type UE supports is Wifi for SOS network capability. {@code
357      * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is
358      * both Cellular & Wifi for SOS network capability. The default value for this key is {@link
359      * QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}
360      */
361     static final String KEY_QNS_SOS_TRANSPORT_TYPE_INT = "qns.sos_transport_type_int";
362 
363     /**
364      * Specifies the Transport type UE supports with QNS services for MMS network capability. {@link
365      * QnsConstants}. The values are set as below:
366      *
367      * <ul>
368      *   <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}
369      *   <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}
370      *   <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}
371      * </ul>
372      *
373      * {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is
374      * cellular for MMS network capability. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If
375      * this value set , Transport type UE supports is Wifi for MMS network capability. {@code
376      * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is
377      * both Cellular & Wifi for MMS network capability. The default value for this key is {@link
378      * QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}
379      */
380     static final String KEY_QNS_MMS_TRANSPORT_TYPE_INT = "qns.mms_transport_type_int";
381 
382     /**
383      * Specifies the Transport type UE supports with QNS services for CBS network capability. {@link
384      * QnsConstants}. The values are set as below:
385      *
386      * <ul>
387      *   <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}
388      *   <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}
389      *   <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}
390      * </ul>
391      *
392      * {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is
393      * cellular for CBS network capability. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If
394      * this value set , Transport type UE supports is Wifi for CBS network capability. {@code
395      * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is
396      * both Cellular & Wifi for CBS network capability. The default value for this key is {@link
397      * QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}
398      */
399     static final String KEY_QNS_CBS_TRANSPORT_TYPE_INT = "qns.cbs_transport_type_int";
400 
401     /**
402      * For IMS PDN, specify a list of the hysteresis timer(millisecond) for handover from WLAN and
403      * WWAN to avoid ping-pong effect.
404      *
405      * <ul>
406      *   <li>Index 0: The hysteresis timer for handover from WLAN and WWAN in idle state.
407      *   <li>Index 1: The hysteresis timer for handover from WLAN and WWAN in voice call state.
408      *   <li>Index 2: The hysteresis timer for handover from WLAN and WWAN in video call state.
409      * </ul>
410      *
411      * <p>The default values are {@link QnsConstants#KEY_DEFAULT_HYST_TIMER}
412      */
413     static final String KEY_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY =
414             "qns.ims_wwan_hysteresis_timer_ms_int_array";
415 
416     /**
417      * For IMS PDN, specify a list of the hysteresis timer(millisecond) for handover from WWAN and
418      * WLAN to avoid ping-pong effect.
419      *
420      * <ul>
421      *   <li>Index 0: The hysteresis timer for handover from WWAN and WLAN in idle state.
422      *   <li>Index 1: The hysteresis timer for handover from WWAN and WLAN in voice call state.
423      *   <li>Index 2: The hysteresis timer for handover from WWAN and WLAN in video call state.
424      * </ul>
425      *
426      * <p>The default values are {@link QnsConstants#KEY_DEFAULT_HYST_TIMER}
427      */
428     static final String KEY_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY =
429             "qns.ims_wlan_hysteresis_timer_ms_int_array";
430 
431     /**
432      * Location(HOME/ROAM) of using handover hysteresis timer
433      * <li>0: {@link QnsConstants#COVERAGE_HOME}
434      * <li>1: {@link QnsConstants#COVERAGE_ROAM}
435      * <li>2: {@link QnsConstants#COVERAGE_BOTH} The default value for this key is {@link
436      * QnsConstants#COVERAGE_BOTH}
437      */
438     static final String KEY_QNS_IMS_NETWORK_ENABLE_HO_HYSTERESIS_TIMER_INT =
439             "qns.ims_network_enable_hysteresis_timer_int";
440 
441     /**
442      * For MMS, XCAP and CBS PDNs, specify a list of the hysteresis timer(millisecond) for handover
443      * from WLAN and WWAN to avoid ping-pong effect.
444      *
445      * <ul>
446      *   <li>Index 0: The hysteresis timer for handover from WLAN to WWAN in idle state.
447      *   <li>Index 1: The hysteresis timer for handover from WLAN to WWAN in call state.
448      * </ul>
449      *
450      * <p>The default values are {@link QnsConstants#KEY_DEFAULT_VALUE}
451      */
452     static final String KEY_NON_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY =
453             "qns.non_ims_wwan_hysteresis_timer_ms_int_array";
454 
455     /**
456      * For MMS, XCAP and CBS PDNs, specify a list of the hysteresis timer(millisecond) for handover
457      * from WWAN and WLAN to avoid ping-pong effect.
458      *
459      * <ul>
460      *   <li>Index 0: The hysteresis timer for handover from WWAN and WLAN in idle state.
461      *   <li>Index 1: The hysteresis timer for handover from WWAN and WLAN in call state.
462      * </ul>
463      *
464      * <p>The default values are {@link QnsConstants#KEY_DEFAULT_VALUE}
465      */
466     static final String KEY_NON_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY =
467             "qns.non_ims_wlan_hysteresis_timer_ms_int_array";
468 
469     /**
470      * This item is the minimum handover guarding timer value when there is no guarding time for
471      * handover.
472      * Note:
473      * If this value is set to less than or equal to 0, minimum guarding action is disabled.
474      * if this value is set to greater than or equal to
475      * {@code QnsConstants#CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER_LIMIT},
476      * {@code QnsConstants#CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER_LIMIT} value is set.
477      * If no value set at asset or paris , QnsConstants#CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER
478      * value at code is set.
479      *
480      * <p>{@code QnsConstants#CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER} : default value of timer.
481      * {@code QnsConstants#CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER_LIMIT} : maximum allowable
482      * value.
483      */
484     static final String KEY_MINIMUM_HANDOVER_GUARDING_TIMER_MS_INT =
485             "qns.minimum_handover_guarding_timer_ms_int";
486 
487     /**
488      * This indicates time duration for packet loss rate sustained.
489      *
490      * <p/> The default value for this key is {@code
491      * QnsConstants#KEY_DEFAULT_PACKET_LOSS_TIME_MILLIS}
492      */
493     static final String KEY_QNS_MEDIA_THRESHOLD_RTP_PACKET_LOSS_TIME_MILLIS_INT =
494             "qns.media_threshold_rtp_packet_loss_time_millis";
495 
496     /**
497      * Specify a list of the waiting time(millisecond) for the preferred transport type when power
498      * up.
499      *
500      * <ul>
501      *   <li>Index 0: The waiting time for WWAN in cellular preferred mode.
502      *   <li>Index 1: The waiting time for WLAN in WiFi preferred mode.
503      * </ul>
504      *
505      * <p>The default values are all {@link QnsConstants#KEY_DEFAULT_VALUE}
506      *
507      * <p>For example, if set 45000ms in the index 0 of this list, WLAN will be restricted 45000ms
508      * in cellular preferred mode when power up, and the timer will be canceled if IMS PDN is
509      * connected on WWAN within 45000ms.
510      */
511     static final String KEY_WAITING_TIME_FOR_PREFERRED_TRANSPORT_WHEN_POWER_ON_INT_ARRAY =
512             "qns.waiting_time_for_preferred_transport_when_power_on_int_array";
513 
514     /**
515      * Specifies the number of count allowed IWLAN on HO to cellular during call due to fallback
516      * reason such as Wifi bad or RTP Low Quality Criteria
517      *
518      * <p>The Possible values are set as below: <rovein_count_allowed,rove_outfallback_reason
519      *
520      * <ul>
521      *   <li><-1,-1></-1,-1>:{@link QnsConstants#MAX_COUNT_INVALID,QnsConstants#MAX_COUNT_INVALID}
522      * </ul>
523      *
524      * & As per operator Requirements (Ex: 3,1 or 1,2)
525      *
526      * <p>The default value for this key is {@link QnsConstants#MAX_COUNT_INVALID,
527      * QnsConstants#FALLBACK_REASON_INVALID}
528      */
529     static final String KEY_QNS_IN_CALL_ROVEIN_ALLOWED_COUNT_AND_FALLBACK_REASON_INT_ARRAY =
530             "qns.in_call_rovein_allowed_and_fallback_reason_int_array";
531 
532     /**
533      * Specifies the number of count allowed IWLAN on HO to cellular during call due to fallback
534      * reason such as Wifi bad or RTP Low Quality Criteria
535      *
536      * <p>The Possible values are set as below:
537      *
538      * <ul>
539      *   <li>Index 0: The waiting time for WLAN //If set to 0 , feature is disabled for WLAN-WWAN
540      *   <li>Index 1: The waiting time for WWAN //If set to 0 , feature is disabled for WWAN-WLAN
541      * </ul>
542      *
543      * The default value for this key is {@link
544      * QnsConstants#KEY_DEFAULT_IWLAN_AVOID_TIME_LOW_RTP_QUALITY_MILLIS,
545      * QnsConstants#KEY_DEFAULT_VALUE}
546      */
547     static final String KEY_QNS_HO_RESTRICT_TIME_WITH_LOW_RTP_QUALITY_MILLIS_INT_ARRAY =
548             "qns.ho_restrict_time_with_low_rtp_quality_int_array";
549 
550     /**
551      * Specify if choosing the transport type based on WFC preference mode when both WWAN and WLAN
552      * are not able to meet service requirements.
553      *
554      * <p>The possible values are set as below:
555      *
556      * <ul>
557      *   <li>1: {@link ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}
558      *   <li>2: {@link ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}
559      * </ul>
560      *
561      * {@code ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}: Only apply the design when WFC
562      * preference mode is cellular preferred. Choose WWAN when cellular preferred and both WWAN and
563      * WLAN are in bad condition. {@code ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}: Only apply the
564      * design when WFC preference mode is WiFi preferred. Choose WLAN when WiFi preferred and both
565      * WWAN and WLAN are in bad condition.
566      *
567      * <p>If set to {ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED,
568      * ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}, the design will apply on both cellular and WiFi
569      * preference mode.
570      *
571      * <p>The default value for this key is empty. An empty array indicates staying on the current
572      * transport when both WWAN and WLAN are not able to meet service requirements.
573      */
574     static final String KEY_CHOOSE_WFC_PREFERRED_TRANSPORT_IN_BOTH_BAD_CONDITION_INT_ARRAY =
575             "qns.choose_wfc_preferred_transport_in_both_bad_condition_int_array";
576 
577     /**
578      * String indicating parameters for RTT(round trip time) check using ICMP PING on IWLAN.
579      *
580      * <p>We recommend to use a server on IWLAN path for RTT check. A server which is not reached
581      * via IWLAN connection may give inadequate result.
582      *
583      * <p>format:“<server_address>,<ping_count>,<intra_ping_interval>,<packet_size>,<rtt_criteria>,
584      * <rtt_check_Interval>,<hyst_fallback_timer>” For Ex:
585      * "epdg.epc.mnc001.mcc001.pub.3gppnetwork.org,5,100,32,100,1800000,600000"
586      *
587      * <p>The default value for this key is null indicating not enabled by default for round trip
588      * time check.
589      */
590     static final String KEY_QNS_WLAN_RTT_BACKHAUL_CHECK_ON_ICMP_PING_STRING =
591             "qns.wlan_rtt_backhaul_check_on_icmp_ping_string";
592 
593     /**
594      * List of Array items indicating network capabilities with fallback support based on retry
595      * count or retry timer or either of them with fallback guard timer to be set
596      *
597      * <p><string-array name="qns.fallback_on_initial_connection_failure_string_array" num="2" <item
598      * value="<network_capability>:<retry_count>:<retry_timer>:<fallback_guard_timer>
599      * :<max_fallback_count>"/> Note: All Timer Values to be in millis Example: <item
600      * value="ims:3:60000:10000:2"/> <item value="mms:1:10000:60000:2"/>
601      *
602      * <p>The default value for this key is null indicating not enabled by default for fallback in
603      * case of initial connection failure
604      */
605     static final String KEY_QNS_FALLBACK_ON_INITIAL_CONNECTION_FAILURE_STRING_ARRAY =
606             "qns.fallback_on_initial_connection_failure_string_array";
607 
608     /**
609      * List of Array items indicating the Access Network Allowed For IMS network capability. The
610      * values are set as below: "LTE" "NR" "3G" "2G" The default value for this key is {@Code
611      * "LTE","NR"}
612      */
613     static final String KEY_IMS_CELLULAR_ALLOWED_RAT_STRING_ARRAY =
614             "qns.ims_cellular_allowed_rat_string_array";
615 
616     /**
617      * List of Array items indicating the Access Network Allowed For IMS network capability. The
618      * values are set as below: Format "<accessNetwork>:<meas_type>:<gap>" "eutran:rsrp:-2"
619      * "ngran:ssrsrp:2" Note: Similar format followed across different accessNetwork & Measurement
620      * Types. The default value for this key is "".
621      */
622     static final String KEY_QNS_ROVEIN_THRESHOLD_GAP_WITH_GUARD_TIMER_STRING_ARRAY =
623             "qns.rove_in_threshold_gap_with_guard_timer_string_array";
624 
625     /**
626      * List of Array items indicating IMS unregistered cause & time(millis) for fallback (to WWAN).
627      *
628      * <p><string-array name="qns.fallback_wwan_ims_unregistration_reason_string_array" num="2">
629      * <!-- fallback WWAN with ImsReason 321~378,1503 during 60sec at cellular prefer mode -->
630      * <item value="cause=321~378|1503, time=60000, preference=cell"/>
631      * <!-- fallback WWAN with ImsReason 240,243,323~350 during 90sec -->
632      * <item value="cause=240|243|323~350, time=90000"/> </string-array>
633      *
634      * <p>The default value for this key is "".
635      */
636     static final String KEY_QNS_FALLBACK_WWAN_IMS_UNREGISTRATION_REASON_STRING_ARRAY =
637             "qns.fallback_wwan_ims_unregistration_reason_string_array";
638 
639     /**
640      * List of Array items indicating IMS HO registration fail cause & time(millis) for fallback (to
641      * WWAN).
642      *
643      * <p><string-array name="qns.fallback_wwan_ims_ho_reigster_fail_reason_string_array" num="2">
644      * <!-- fallback WWAN with ImsReason 321~378,1503 during 60sec at cellular prefer mode -->
645      * <item value="cause=321~378|1503, time=60000, preference=cell"/>
646      * <!-- fallback WWAN with ImsReason 240,243,323~350 during 90sec -->
647      * <item value="cause=240|243|323~350, time=90000"/> </string-array>
648      *
649      * <p>The default value for this key is "".
650      */
651     static final String KEY_QNS_FALLBACK_WWAN_IMS_HO_REGISTER_FAIL_REASON_STRING_ARRAY =
652             "qns.fallback_wwan_ims_ho_register_fail_reason_string_array";
653 
654     /**
655      * Specifies override the call precondition policy of AccessNetworkSelectionPolicy when the
656      * Sip Dialog Session is active.
657      * This Sip Dialog Session policy is applied when there is no calling in the subscription, and
658      * when the device is in a calling state, the calling policy is used first.
659      *
660      * <p> If the Sip Dialog Session is active, the AccessNetworkSelectionPolicy is applied as one
661      * of three policies: none, follow policy as voice call or as video call.
662      * <li>0: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_NONE} not Applied. The default value
663      * for this key.
664      * <li>1: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_FOLLOW_VOICE_CALL} apply voice call
665      * policy.
666      * <li>2: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_FOLLOW_VIDEO_CALL}  apply video call
667      * policy.
668      */
669     static final String KEY_SIP_DIALOG_SESSION_POLICY_INT = "qns.sip_dialog_session_policy_int";
670 
671     /**
672      * List of Array items indicating hysteresis db levels based on access network and measurement
673      * type , whose value to be used at api
674      * {@link SignalThresholdInfo#Builder().setHysteresisDb(int)}
675      * The values are set as Format "<accessNetwork>:<meas_type>:<hysteresisDb>"
676      * Ex: "eutran:rsrp:2","ngran:ssrsrp:1"
677      *
678      * The default value or if value set is less than zero,
679      * for this key is {@link QnsConstants#KEY_DEFAULT_VALUE}
680      *
681      */
682     public static final String KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY =
683             "qns.cellular_signal_strength_hysteresis_db_string_array";
684 
685     private static final Map<Integer, String> sAccessNetworkMap = Map.of(
686             AccessNetworkConstants.AccessNetworkType.EUTRAN, "eutran",
687             AccessNetworkConstants.AccessNetworkType.UTRAN, "utran",
688             AccessNetworkConstants.AccessNetworkType.NGRAN, "ngran",
689             AccessNetworkConstants.AccessNetworkType.GERAN, "geran",
690             AccessNetworkConstants.AccessNetworkType.IWLAN, "wifi"
691     );
692 
693     private static final Map<Integer, String> sMeasTypeMap = Map.of(
694             SIGNAL_MEASUREMENT_TYPE_RSRP, "rsrp",
695             SIGNAL_MEASUREMENT_TYPE_RSRQ, "rsrq",
696             SIGNAL_MEASUREMENT_TYPE_RSSNR, "rssnr",
697             SIGNAL_MEASUREMENT_TYPE_SSRSRP, "ssrsrp",
698             SIGNAL_MEASUREMENT_TYPE_SSRSRQ, "ssrsrq",
699             SIGNAL_MEASUREMENT_TYPE_SSSINR, "sssinr",
700             SIGNAL_MEASUREMENT_TYPE_RSCP, "rscp",
701             SIGNAL_MEASUREMENT_TYPE_RSSI, "rssi",
702             SIGNAL_MEASUREMENT_TYPE_ECNO, "ecno"
703     );
704 
705     private static final Map<Integer, String> sCallTypeMap = Map.of(
706             QnsConstants.CALL_TYPE_IDLE, "idle",
707             QnsConstants.CALL_TYPE_VOICE, "voice",
708             QnsConstants.CALL_TYPE_VIDEO, "video"
709     );
710 
711     private final String mLogTag;
712     private final int mSlotIndex;
713     private final Context mContext;
714     private boolean mIsConfigLoaded = false;
715     protected int mSubId;
716     protected int mCurrCarrierId;
717     private final QnsEventDispatcher mQnsEventDispatcher;
718     private final QnsCarrierAnspSupportConfig mAnspConfigMgr;
719     @VisibleForTesting final Handler mHandler;
720 
721     private boolean mIsWfcInAirplaneModeOnSupport;
722     private boolean mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported;
723     private boolean mIsHoGuardOnPreferenceSupport;
724     private boolean mIsServiceBarringCheckSupport;
725     private boolean mIsVideoOverIWLANWithCellularCheckSupport;
726     private boolean mIsRoveOutWifiBadGuardTimerConditionsSupported;
727     private boolean mIsAllowImsOverIwlanCellularLimitedCase;
728     private boolean mIsBlockIwlanInInternationalRoamWithoutWwan;
729     private boolean mIsBlockIpv6OnlyWifi;
730     private boolean mIsVolteRoamingSupported;
731     private final boolean[] mAnspSupportConfigArray = new boolean[3];
732 
733     private int mWifiThresBackHaulTimer;
734     private int mCellularThresBackHaulTimer;
735     private int mQnsImsTransportType;
736     private int mQnsSosTransportType;
737     private int mQnsMmsTransportType;
738     private int[] mQnsXcapSupportedAccessNetworkTypes;
739     private int mQnsCbsTransportType;
740     private int mXcapRatPreference;
741     private int mSosRatPreference;
742     private int mMmsRatPreference;
743     private int mCbsRatPreference;
744     private int mNetworkEnableHysteresisTimer;
745     private int mMinimumHandoverGuardingTimer;
746     private int mVowifiRegistrationTimerForVowifiActivation;
747     private int mSipDialogSessionPolicy;
748 
749     private int[] mWwanHysteresisTimer;
750     private int[] mWlanHysteresisTimer;
751     private int[] mNonImsWwanHysteresisTimer;
752     private int[] mNonImsWlanHysteresisTimer;
753     private int[] mRTPMetricsData = new int[4];
754     private int[] mWaitingTimerForPreferredTransport;
755     private int[] mAllowMaxIwlanHoCountOnReason;
756     private int[] mHoRestrictTimeOnRtpQuality;
757     private int[] mIsMmtelCapabilityRequired;
758     private int[] mIsWfcPreferredTransportRequired;
759 
760     private String mWlanRttBackhaulCheckConfigsOnPing;
761     private String[] mImsAllowedRats;
762     private String[] mRoveInGuardTimerConditionThresholdGaps;
763     private String[] mFallbackOnInitialConnectionFailure;
764     private String[] mAccessNetworkMeasurementHysteresisDb;
765 
766     @NonNull
767     private final List<FallbackRule> mFallbackWwanRuleWithImsUnregistered = new ArrayList<>();
768 
769     @NonNull
770     private final List<FallbackRule> mFallbackWwanRuleWithImsHoRegisterFail = new ArrayList<>();
771 
772     /** Rules for handover between IWLAN and cellular network. */
773     @NonNull private List<HandoverRule> mHandoverRuleList = new ArrayList<>();
774 
775     protected QnsRegistrantList mQnsCarrierConfigLoadedRegistrants = new QnsRegistrantList();
776     protected QnsRegistrantList mQnsCarrierConfigChangedRegistrants = new QnsRegistrantList();
777 
778     protected QnsProvisioningListener.QnsProvisioningInfo mQnsProvisioningInfo =
779             new QnsProvisioningListener.QnsProvisioningInfo();
780 
setQnsProvisioningInfo(QnsProvisioningListener.QnsProvisioningInfo info)781     void setQnsProvisioningInfo(QnsProvisioningListener.QnsProvisioningInfo info) {
782         mQnsProvisioningInfo = info;
783     }
784 
applyProvisioningInfo( QnsConfigArray thresholds, int accessNetwork, int measurementType, int callType)785     private QnsConfigArray applyProvisioningInfo(
786             QnsConfigArray thresholds, int accessNetwork, int measurementType, int callType) {
787 
788         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_1)
789                 && thresholds.mBad != QnsConfigArray.INVALID
790                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN
791                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) {
792             int bad = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_1);
793             Log.d(mLogTag, "provisioning bad THLTE1 old:" + thresholds.mBad + " new:" + bad);
794             thresholds.mBad = bad;
795         }
796         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_2)
797                 && thresholds.mWorst != QnsConfigArray.INVALID
798                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN
799                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) {
800             int worst =
801                     mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_2);
802             Log.d(mLogTag, "provisioning worst THLTE2 old:" + thresholds.mWorst + " new:" + worst);
803             thresholds.mWorst = worst;
804         }
805         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_3)
806                 && thresholds.mGood != QnsConfigArray.INVALID
807                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN
808                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) {
809             int good = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_3);
810             Log.d(mLogTag, "provisioning good THLTE3 old:" + thresholds.mGood + " new:" + good);
811             thresholds.mGood = good;
812         }
813         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_THRESHOLD_A)
814                 && thresholds.mGood != QnsConfigArray.INVALID
815                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN
816                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSSI) {
817             int good =
818                     mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_THRESHOLD_A);
819             Log.d(mLogTag, "provisioning good VOWT_A old:" + thresholds.mGood + " new:" + good);
820             thresholds.mGood = good;
821         }
822         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_THRESHOLD_B)
823                 && thresholds.mBad != QnsConfigArray.INVALID
824                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN
825                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSSI) {
826             int bad = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_THRESHOLD_B);
827             Log.d(mLogTag, "provisioning bad VOWT_B old:" + thresholds.mBad + " new:" + bad);
828             thresholds.mBad = bad;
829             // TODO : make video threshold gap config, and move in getThreshold...()
830             if (getCarrierId() == 1839 && callType == QnsConstants.CALL_TYPE_VIDEO) {
831                 thresholds.mBad = bad + 5;
832             }
833         }
834 
835         return thresholds;
836     }
837 
838     static class FallbackRule {
839         /** Key : IMS registration fail reason, value : fallback time in millis */
840         final Set<Integer> mReasons;
841 
842         final int mBackoffTimeMillis;
843         final int mPreferenceMode;
844 
FallbackRule(Set<Integer> reasons, int backoffTimeMillis, int preferenceMode)845         FallbackRule(Set<Integer> reasons, int backoffTimeMillis, int preferenceMode) {
846             mReasons = reasons;
847             mBackoffTimeMillis = backoffTimeMillis;
848             mPreferenceMode = preferenceMode;
849         }
850 
getFallBackTime(int reason)851         int getFallBackTime(int reason) {
852             if (mReasons.contains(reason)) {
853                 return mBackoffTimeMillis;
854             } else {
855                 return 0;
856             }
857         }
858 
859         @Override
toString()860         public String toString() {
861             StringBuilder builder = new StringBuilder();
862             builder.append("FallbackRule time:").append(mBackoffTimeMillis);
863             if (mPreferenceMode == -1) {
864                 builder.append(" ");
865             } else if (mPreferenceMode == QnsConstants.CELL_PREF) {
866                 builder.append(" " + "CELL_PREF_MODE");
867             } else if (mPreferenceMode == QnsConstants.WIFI_PREF) {
868                 builder.append(" " + "WIFI_PREF_MODE");
869             }
870             builder.append(" reasons:");
871             for (Integer i : mReasons) {
872                 builder.append(i).append(" ");
873             }
874             return builder.toString();
875         }
876     }
877 
878     static class HandoverRule {
879         @Retention(RetentionPolicy.SOURCE)
880         @IntDef(
881                 prefix = {"RULE_TYPE_"},
882                 value = {
883                     RULE_TYPE_ALLOWED,
884                     RULE_TYPE_DISALLOWED,
885                 })
886         @interface HandoverRuleType {}
887 
888         /** Indicating this rule is for allowing handover. */
889         static final int RULE_TYPE_ALLOWED = 1;
890 
891         /** Indicating this rule is for disallowing handover. */
892         static final int RULE_TYPE_DISALLOWED = 2;
893 
894         private static final String RULE_TAG_SOURCE_ACCESS_NETWORKS = "source";
895 
896         private static final String RULE_TAG_TARGET_ACCESS_NETWORKS = "target";
897 
898         private static final String RULE_TAG_TYPE = "type";
899 
900         private static final String RULE_TAG_CAPABILITIES = "capabilities";
901 
902         private static final String RULE_TAG_ROAMING = "roaming";
903 
904         /** Handover rule type. */
905         @HandoverRuleType final int mHandoverRuleType;
906 
907         /** The applicable source access networks for handover. */
908         @NonNull @AccessNetworkConstants.RadioAccessNetworkType
909         final Set<Integer> mSourceAccessNetworks;
910 
911         /** The applicable target access networks for handover. */
912         @NonNull @AccessNetworkConstants.RadioAccessNetworkType
913         final Set<Integer> mTargetAccessNetworks;
914 
915         /**
916          * The network capabilities to any of which this handover rule applies. If is empty, then
917          * capability is ignored as a rule matcher.
918          */
919         @NonNull @NetCapability final Set<Integer> mNetworkCapabilities;
920 
921         /** {@code true} indicates this policy is only applicable when the device is roaming. */
922         final boolean mIsOnlyForRoaming;
923 
924         /**
925          * Constructor
926          *
927          * @param ruleString The rule in string format.
928          * @see CarrierConfigManager#KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY
929          */
HandoverRule(@onNull String ruleString)930         HandoverRule(@NonNull String ruleString) {
931             if (TextUtils.isEmpty(ruleString)) {
932                 throw new IllegalArgumentException("illegal rule " + ruleString);
933             }
934 
935             Set<Integer> source = null, target = null, capabilities = Collections.emptySet();
936             int type = 0;
937             boolean roaming = false;
938 
939             ruleString = ruleString.trim().toLowerCase(Locale.ROOT);
940             String[] expressions = ruleString.split("\\s*,\\s*");
941             for (String expression : expressions) {
942                 String[] tokens = expression.trim().split("\\s*=\\s*");
943                 if (tokens.length != 2) {
944                     throw new IllegalArgumentException(
945                             "illegal rule " + ruleString + ", tokens=" + Arrays.toString(tokens));
946                 }
947                 String key = tokens[0].trim();
948                 String value = tokens[1].trim();
949                 try {
950                     switch (key) {
951                         case RULE_TAG_SOURCE_ACCESS_NETWORKS:
952                             source =
953                                     Arrays.stream(value.split("\\s*\\|\\s*"))
954                                             .map(String::trim)
955                                             .map(QnsConstants::accessNetworkTypeFromString)
956                                             .collect(Collectors.toSet());
957                             break;
958                         case RULE_TAG_TARGET_ACCESS_NETWORKS:
959                             target =
960                                     Arrays.stream(value.split("\\s*\\|\\s*"))
961                                             .map(String::trim)
962                                             .map(QnsConstants::accessNetworkTypeFromString)
963                                             .collect(Collectors.toSet());
964                             break;
965                         case RULE_TAG_TYPE:
966                             if (value.toLowerCase(Locale.ROOT).equals("allowed")) {
967                                 type = RULE_TYPE_ALLOWED;
968                             } else if (value.toLowerCase(Locale.ROOT).equals("disallowed")) {
969                                 type = RULE_TYPE_DISALLOWED;
970                             } else {
971                                 throw new IllegalArgumentException("unexpected rule type " + value);
972                             }
973                             break;
974                         case RULE_TAG_CAPABILITIES:
975                             capabilities = QnsUtils.getNetworkCapabilitiesFromString(value);
976                             break;
977                         case RULE_TAG_ROAMING:
978                             roaming = Boolean.parseBoolean(value);
979                             break;
980                         default:
981                             throw new IllegalArgumentException("unexpected key " + key);
982                     }
983                 } catch (Exception e) {
984                     e.printStackTrace();
985                     throw new IllegalArgumentException(
986                             "illegal rule \"" + ruleString + "\", e=" + e);
987                 }
988             }
989 
990             if (source == null || target == null || source.isEmpty() || target.isEmpty()) {
991                 throw new IllegalArgumentException(
992                         "Need to specify both source and target. " + "\"" + ruleString + "\"");
993             }
994 
995             if (source.contains(AccessNetworkConstants.AccessNetworkType.UNKNOWN)
996                     && type != RULE_TYPE_DISALLOWED) {
997                 throw new IllegalArgumentException("Unknown access network can be only specified in"
998                         + " the disallowed rule. \"" + ruleString + "\"");
999             }
1000 
1001             if (target.contains(AccessNetworkConstants.AccessNetworkType.UNKNOWN)) {
1002                 throw new IllegalArgumentException(
1003                         "Target access networks contains unknown. " + "\"" + ruleString + "\"");
1004             }
1005 
1006             if (type == 0) {
1007                 throw new IllegalArgumentException(
1008                         "Rule type is not specified correctly. " + "\"" + ruleString + "\"");
1009             }
1010 
1011             if (capabilities != null && capabilities.contains(-1)) {
1012                 throw new IllegalArgumentException(
1013                         "Network capabilities contains unknown. " + "\"" + ruleString + "\"");
1014             }
1015 
1016             if (!source.contains(AccessNetworkConstants.AccessNetworkType.IWLAN)
1017                     && !target.contains(AccessNetworkConstants.AccessNetworkType.IWLAN)) {
1018                 throw new IllegalArgumentException(
1019                         "IWLAN must be specified in either source or "
1020                                 + "target access networks.\""
1021                                 + ruleString
1022                                 + "\"");
1023             }
1024 
1025             mSourceAccessNetworks = source;
1026             mTargetAccessNetworks = target;
1027             this.mHandoverRuleType = type;
1028             mNetworkCapabilities = capabilities;
1029             mIsOnlyForRoaming = roaming;
1030         }
1031 
1032         @Override
toString()1033         public String toString() {
1034             return "[HandoverRule: type="
1035                     + (mHandoverRuleType == RULE_TYPE_ALLOWED ? "allowed" : "disallowed")
1036                     + ", source="
1037                     + mSourceAccessNetworks.stream()
1038                             .map(QnsConstants::accessNetworkTypeToString)
1039                             .collect(Collectors.joining("|"))
1040                     + ", target="
1041                     + mTargetAccessNetworks.stream()
1042                             .map(QnsConstants::accessNetworkTypeToString)
1043                             .collect(Collectors.joining("|"))
1044                     + ", isRoaming="
1045                     + mIsOnlyForRoaming
1046                     + ", capabilities="
1047                     + QnsUtils.networkCapabilitiesToString(mNetworkCapabilities)
1048                     + "]";
1049         }
1050     }
1051 
1052     private class QnsCarrierConfigChangeHandler extends Handler {
QnsCarrierConfigChangeHandler(Looper looper)1053         QnsCarrierConfigChangeHandler(Looper looper) {
1054             super(looper);
1055         }
1056 
1057         @Override
handleMessage(Message message)1058         public void handleMessage(Message message) {
1059             switch (message.what) {
1060                 case QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED:
1061                     Log.d(mLogTag, "Event received QNS_EVENT_CARRIER_CONFIG_CHANGED");
1062                     if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1063                         int newCarrierID = getCarrierId();
1064                         Log.d(
1065                                 mLogTag,
1066                                 "Carrier Id: current=" + mCurrCarrierId + ", new=" + newCarrierID);
1067                         if (newCarrierID != 0 && newCarrierID != UNKNOWN_CARRIER_ID) {
1068                             if (mCurrCarrierId != newCarrierID) {
1069                                 mCurrCarrierId = newCarrierID;
1070                                 loadQnsConfigurations();
1071                                 mIsConfigLoaded = true;
1072                                 notifyLoadQnsConfigurationsCompleted();
1073                             } else {
1074                                 if (isQnsConfigChanged()) {
1075                                     Log.d(mLogTag, "Qns Carrier config updated found");
1076                                     notifyQnsConfigurationsChanged();
1077                                 }
1078                             }
1079                         }
1080                     }
1081                     break;
1082                 default:
1083                     break;
1084             }
1085         }
1086     }
1087 
1088     /**
1089      * Constructor to Initial Slot and Context whose carrier config ID needs to be loaded along with
1090      * initialising the Action Intent on which Carrier Config ID to be loaded.
1091      */
QnsCarrierConfigManager(Context context, QnsEventDispatcher dispatcher, int slotIndex)1092     QnsCarrierConfigManager(Context context, QnsEventDispatcher dispatcher, int slotIndex) {
1093         mSlotIndex = slotIndex;
1094         mContext = context;
1095         mLogTag =
1096                 QnsConstants.QNS_TAG
1097                         + "_"
1098                         + QnsCarrierConfigManager.class.getSimpleName()
1099                         + "_"
1100                         + mSlotIndex;
1101         mQnsEventDispatcher = dispatcher;
1102         mAnspConfigMgr = new QnsCarrierAnspSupportConfig(slotIndex);
1103 
1104         HandlerThread handlerThread = new HandlerThread(mLogTag);
1105         handlerThread.start();
1106         mHandler =
1107                 new QnsCarrierConfigManager.QnsCarrierConfigChangeHandler(
1108                         handlerThread.getLooper());
1109 
1110         List<Integer> events = new ArrayList<>();
1111         events.add(QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED);
1112         mQnsEventDispatcher.registerEvent(events, mHandler);
1113 
1114         // sending empty message when new object created; as actual event will not be received in
1115         // case QNS restarts.
1116         // This EVENT will not be processed in bootup case since carrier id will be invalid until
1117         // actual event received from QnsEventDispatcher.
1118         mHandler.sendEmptyMessage(QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED);
1119 
1120         // To do : Update based on xml version Changes handling
1121         // To do : Operator Update on Threshold changes handling
1122     }
1123 
1124     /** Below API clears the current Access Network selection Policies */
close()1125     void close() {
1126         if (mHandler != null) mQnsEventDispatcher.unregisterEvent(mHandler);
1127     }
1128 
readFromCarrierConfigManager(Context context)1129     synchronized PersistableBundle readFromCarrierConfigManager(Context context) {
1130         PersistableBundle carrierConfigBundle;
1131         CarrierConfigManager carrierConfigManager =
1132                 context.getSystemService(CarrierConfigManager.class);
1133 
1134         if (carrierConfigManager == null) {
1135             throw new IllegalStateException("Carrier config manager is null.");
1136         }
1137         carrierConfigBundle = carrierConfigManager.getConfigForSubId(getSubId());
1138 
1139         return carrierConfigBundle;
1140     }
1141 
readFromAssets(Context context)1142     synchronized PersistableBundle readFromAssets(Context context) {
1143         PersistableBundle assetBundle;
1144 
1145         assetBundle = QnsUtils.readQnsDefaultConfigFromAssets(context, mCurrCarrierId);
1146 
1147         if (assetBundle == null) {
1148             throw new IllegalStateException("Carrier config manager is null.");
1149         }
1150 
1151         return assetBundle;
1152     }
1153 
1154     /** Below API is used for Loading the carrier configurations based on Current Carrier ID */
loadQnsConfigurations()1155     void loadQnsConfigurations() {
1156 
1157         PersistableBundle carrierConfigBundle = readFromCarrierConfigManager(mContext);
1158         Log.d(mLogTag, "CarrierConfig Bundle for Slot: " + mSlotIndex + carrierConfigBundle);
1159 
1160         PersistableBundle assetConfigBundle = readFromAssets(mContext);
1161         Log.d(mLogTag, "AssetConfig Bundle for Slot: " + mSlotIndex + assetConfigBundle);
1162 
1163         // load configurations supporting ANE
1164         loadQnsAneSupportConfigurations(carrierConfigBundle, assetConfigBundle);
1165 
1166         // load qns Ansp (Access Network Selection Policy) carrier Support Configurations
1167         // for building Internal ANSP Policies
1168         loadAnspCarrierSupportConfigs(carrierConfigBundle, assetConfigBundle);
1169 
1170         mAnspConfigMgr.loadQnsAnspSupportArray(carrierConfigBundle, assetConfigBundle);
1171 
1172         // Load configs using Carrier Config Manager Keys
1173         loadDirectFromCarrierConfigManagerKey(carrierConfigBundle);
1174 
1175         loadWfcConfigurations(carrierConfigBundle, assetConfigBundle);
1176 
1177         loadMediaThreshold(carrierConfigBundle, assetConfigBundle);
1178     }
1179 
1180     /**
1181      * Below API takes care of loading the configuration based on the carrier config Manager
1182      * available for given carrier config manager keys.
1183      */
loadDirectFromCarrierConfigManagerKey(PersistableBundle bundleCarrier)1184     void loadDirectFromCarrierConfigManagerKey(PersistableBundle bundleCarrier) {
1185         loadHandoverRules(
1186                 bundleCarrier, null, CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY);
1187         loadCarrierConfig(bundleCarrier);
1188     }
1189 
1190     /**
1191      * Below API takes care of validating the configs (Threshold & HO rules) Updates after loading
1192      * Qns configurations, for the current operator in use, in case of config update scenario
1193      *
1194      * @return : true/false
1195      */
isQnsConfigChanged()1196     synchronized boolean isQnsConfigChanged() {
1197         PersistableBundle carrierConfigBundle = readFromCarrierConfigManager(mContext);
1198         Log.d(
1199                 mLogTag,
1200                 "Check carrier config for Qns item changefor_slot: "
1201                         + mSlotIndex
1202                         + "_"
1203                         + carrierConfigBundle);
1204         PersistableBundle assetConfigBundle = readFromAssets(mContext);
1205         Log.d(
1206                 mLogTag,
1207                 "Check Asset config for Qns item changefor_slot: "
1208                         + mSlotIndex
1209                         + "_"
1210                         + assetConfigBundle);
1211 
1212         boolean isThresholdConfigChanged =
1213                 checkThresholdConfigChange(carrierConfigBundle, assetConfigBundle);
1214         boolean isHandoverRulesChanged =
1215                 checkHandoverRuleConfigChange(
1216                         carrierConfigBundle,
1217                         null,
1218                         CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY);
1219         Log.d(
1220                 mLogTag,
1221                 "Threshold config changed = "
1222                         + isThresholdConfigChanged
1223                         + ", IMS handover rule changed = "
1224                         + isHandoverRulesChanged);
1225 
1226         return (isThresholdConfigChanged || isHandoverRulesChanged);
1227     }
1228 
1229     /**
1230      * Below API takes to check if current HO rules as any difference with existing HO rules Updated
1231      * based on Event Carrier config change event received after initial loading @Param
1232      * PersistableBundle : configBundle
1233      *
1234      * @return true/false
1235      */
checkHandoverRuleConfigChange( PersistableBundle carrierConfigBundle, PersistableBundle assetConfigBundle, String key)1236     synchronized boolean checkHandoverRuleConfigChange(
1237             PersistableBundle carrierConfigBundle,
1238             PersistableBundle assetConfigBundle,
1239             String key) {
1240         List<HandoverRule> handoverUpdateRuleList =
1241                 updateHandoverRules(carrierConfigBundle, assetConfigBundle, key);
1242 
1243         Log.d(mLogTag, "New rule:" + handoverUpdateRuleList.toString());
1244         Log.d(mLogTag, "Existing rule:" + mHandoverRuleList.toString());
1245 
1246         if (mHandoverRuleList.toString().equals(handoverUpdateRuleList.toString())
1247                 || handoverUpdateRuleList.isEmpty()
1248                 || mHandoverRuleList.isEmpty()) {
1249             handoverUpdateRuleList.clear();
1250             return false;
1251         } else {
1252             mHandoverRuleList = new ArrayList<>(handoverUpdateRuleList);
1253             Log.d(mLogTag, "New rule Updated:" + mHandoverRuleList);
1254             handoverUpdateRuleList.clear();
1255             return true;
1256         }
1257     }
1258 
1259     /**
1260      * Below API takes to check if ANSP threshold configs was Updated based on Event Carrier config
1261      * change event received after initial Qns configuration loading is completed
1262      */
checkThresholdConfigChange( PersistableBundle carrierConfigBundle, PersistableBundle assetConfigBundle)1263     synchronized boolean checkThresholdConfigChange(
1264             PersistableBundle carrierConfigBundle, PersistableBundle assetConfigBundle) {
1265 
1266         return mAnspConfigMgr.checkQnsAnspConfigChange(carrierConfigBundle, assetConfigBundle);
1267     }
1268 
1269     /**
1270      * Below API takes care of loading the configuration based on the Bundle data built based on
1271      * asset folder xml file . (Except reading Key item of threshold & ANSP
1272      */
loadQnsAneSupportConfigurations( PersistableBundle bundleCarrier, PersistableBundle bundleAsset)1273     void loadQnsAneSupportConfigurations(
1274             PersistableBundle bundleCarrier, PersistableBundle bundleAsset) {
1275 
1276         mIsWfcInAirplaneModeOnSupport =
1277                 getConfig(
1278                         bundleCarrier, bundleAsset, KEY_QNS_SUPPORT_WFC_DURING_AIRPLANE_MODE_BOOL);
1279         mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported =
1280                 getConfig(
1281                         bundleCarrier,
1282                         bundleAsset,
1283                         KEY_IN_CALL_HO_DECISION_WLAN_TO_WWAN_WITHOUT_VOPS_CONDITION_BOOL);
1284         mIsHoGuardOnPreferenceSupport =
1285                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_HO_GUARDING_BY_PREFERENCE_BOOL);
1286         mIsServiceBarringCheckSupport =
1287                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_SUPPORT_SERVICE_BARRING_CHECK_BOOL);
1288         mIsVideoOverIWLANWithCellularCheckSupport =
1289                 getConfig(
1290                         bundleCarrier,
1291                         bundleAsset,
1292                         KEY_QNS_ALLOW_VIDEO_OVER_IWLAN_WITH_CELLULAR_LIMITED_CASE_BOOL);
1293         mIsRoveOutWifiBadGuardTimerConditionsSupported =
1294                 getConfig(
1295                         bundleCarrier,
1296                         bundleAsset,
1297                         KEY_QNS_ROVE_OUT_POLICY_WITH_WIFI_BAD_GUARDTIMER_CONDITIONS_BOOL);
1298         mIsAllowImsOverIwlanCellularLimitedCase =
1299                 getConfig(
1300                         bundleCarrier,
1301                         bundleAsset,
1302                         KEY_QNS_ALLOW_IMS_OVER_IWLAN_CELLULAR_LIMITED_CASE_BOOL);
1303         mIsBlockIwlanInInternationalRoamWithoutWwan =
1304                 getConfig(
1305                         bundleCarrier,
1306                         bundleAsset,
1307                         KEY_BLOCK_IWLAN_IN_INTERNATIONAL_ROAMING_WITHOUT_WWAN_BOOL);
1308         mIsBlockIpv6OnlyWifi = getConfig(bundleCarrier, bundleAsset, KEY_BLOCK_IPV6_ONLY_WIFI_BOOL);
1309 
1310         mWifiThresBackHaulTimer =
1311                 getConfig(
1312                         bundleCarrier,
1313                         bundleAsset,
1314                         KEY_QNS_WIFI_RSSI_THRESHOLDBACKHAUL_TIMER_MS_INT);
1315         mCellularThresBackHaulTimer =
1316                 getConfig(
1317                         bundleCarrier,
1318                         bundleAsset,
1319                         KEY_QNS_CELLULAR_SS_THRESHOLDBACKHAUL_TIMER_MS_INT);
1320         mQnsImsTransportType =
1321                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_IMS_TRANSPORT_TYPE_INT);
1322         mQnsSosTransportType =
1323                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_SOS_TRANSPORT_TYPE_INT);
1324         mQnsMmsTransportType =
1325                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_MMS_TRANSPORT_TYPE_INT);
1326         mQnsXcapSupportedAccessNetworkTypes =
1327                 getConfig(
1328                         bundleCarrier,
1329                         bundleAsset,
1330                         CarrierConfigManager.ImsSs.KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY);
1331         mQnsCbsTransportType =
1332                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_TRANSPORT_TYPE_INT);
1333         mQnsCbsTransportType =
1334                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_TRANSPORT_TYPE_INT);
1335         mXcapRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_XCAP_RAT_PREFERENCE_INT);
1336         mSosRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_SOS_RAT_PREFERENCE_INT);
1337         mMmsRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_MMS_RAT_PREFERENCE_INT);
1338         mCbsRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_RAT_PREFERENCE_INT);
1339         mNetworkEnableHysteresisTimer =
1340                 getConfig(
1341                         bundleCarrier,
1342                         bundleAsset,
1343                         KEY_QNS_IMS_NETWORK_ENABLE_HO_HYSTERESIS_TIMER_INT);
1344 
1345         mWwanHysteresisTimer =
1346                 getConfig(bundleCarrier, bundleAsset, KEY_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY);
1347         mWlanHysteresisTimer =
1348                 getConfig(bundleCarrier, bundleAsset, KEY_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY);
1349         mNonImsWwanHysteresisTimer =
1350                 getConfig(
1351                         bundleCarrier, bundleAsset, KEY_NON_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY);
1352         mNonImsWlanHysteresisTimer =
1353                 getConfig(
1354                         bundleCarrier, bundleAsset, KEY_NON_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY);
1355         mMinimumHandoverGuardingTimer =
1356                 getConfig(bundleCarrier, bundleAsset, KEY_MINIMUM_HANDOVER_GUARDING_TIMER_MS_INT);
1357         mWaitingTimerForPreferredTransport =
1358                 getConfig(
1359                         bundleCarrier,
1360                         bundleAsset,
1361                         KEY_WAITING_TIME_FOR_PREFERRED_TRANSPORT_WHEN_POWER_ON_INT_ARRAY);
1362         mAllowMaxIwlanHoCountOnReason =
1363                 getConfig(
1364                         bundleCarrier,
1365                         bundleAsset,
1366                         KEY_QNS_IN_CALL_ROVEIN_ALLOWED_COUNT_AND_FALLBACK_REASON_INT_ARRAY);
1367         mHoRestrictTimeOnRtpQuality =
1368                 getConfig(
1369                         bundleCarrier,
1370                         bundleAsset,
1371                         KEY_QNS_HO_RESTRICT_TIME_WITH_LOW_RTP_QUALITY_MILLIS_INT_ARRAY);
1372         mWlanRttBackhaulCheckConfigsOnPing =
1373                 getConfig(
1374                         bundleCarrier,
1375                         bundleAsset,
1376                         KEY_QNS_WLAN_RTT_BACKHAUL_CHECK_ON_ICMP_PING_STRING);
1377 
1378         mFallbackOnInitialConnectionFailure =
1379                 getConfig(
1380                         bundleCarrier,
1381                         bundleAsset,
1382                         KEY_QNS_FALLBACK_ON_INITIAL_CONNECTION_FAILURE_STRING_ARRAY);
1383         mImsAllowedRats =
1384                 getConfig(bundleCarrier, bundleAsset, KEY_IMS_CELLULAR_ALLOWED_RAT_STRING_ARRAY);
1385         mRoveInGuardTimerConditionThresholdGaps =
1386                 getConfig(
1387                         bundleCarrier,
1388                         bundleAsset,
1389                         KEY_QNS_ROVEIN_THRESHOLD_GAP_WITH_GUARD_TIMER_STRING_ARRAY);
1390         mSipDialogSessionPolicy =
1391                 getConfig(bundleCarrier, bundleAsset, KEY_SIP_DIALOG_SESSION_POLICY_INT);
1392         mAccessNetworkMeasurementHysteresisDb =
1393                 getConfig(
1394                         bundleCarrier,
1395                         bundleAsset,
1396                         KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY);
1397 
1398         loadFallbackPolicyWithImsRegiFail(bundleCarrier, bundleAsset);
1399     }
1400 
1401     @VisibleForTesting
loadWfcConfigurations(PersistableBundle bundleCarrier, PersistableBundle bundleAsset)1402     void loadWfcConfigurations(PersistableBundle bundleCarrier, PersistableBundle bundleAsset) {
1403 
1404         mVowifiRegistrationTimerForVowifiActivation =
1405                 getConfig(
1406                         bundleCarrier,
1407                         bundleAsset,
1408                         KEY_QNS_VOWIFI_REGISTATION_TIMER_FOR_VOWIFI_ACTIVATION_INT);
1409     }
1410 
1411     @VisibleForTesting
loadFallbackPolicyWithImsRegiFail(PersistableBundle carrier, PersistableBundle asset)1412     void loadFallbackPolicyWithImsRegiFail(PersistableBundle carrier, PersistableBundle asset) {
1413         synchronized (this) {
1414             mFallbackWwanRuleWithImsUnregistered.clear();
1415             String[] fallbackRulesStrings =
1416                     getConfig(
1417                             carrier,
1418                             asset,
1419                             KEY_QNS_FALLBACK_WWAN_IMS_UNREGISTRATION_REASON_STRING_ARRAY);
1420             if (fallbackRulesStrings != null) {
1421                 Log.d(mLogTag, "loadFallbackPolicyWithImsRegiFail" + fallbackRulesStrings.length);
1422                 for (String ruleString : fallbackRulesStrings) {
1423                     Log.d(mLogTag, " ruleString1:" + ruleString);
1424                     FallbackRule rule = parseFallbackRule(ruleString);
1425                     if (rule != null) {
1426                         mFallbackWwanRuleWithImsUnregistered.add(rule);
1427                     }
1428                 }
1429             } else {
1430                 Log.d(mLogTag, "Config FallbackWwanRuleWithImsUnregistered is null");
1431             }
1432             mFallbackWwanRuleWithImsHoRegisterFail.clear();
1433             fallbackRulesStrings =
1434                     getConfig(
1435                             carrier,
1436                             asset,
1437                             KEY_QNS_FALLBACK_WWAN_IMS_HO_REGISTER_FAIL_REASON_STRING_ARRAY);
1438             if (fallbackRulesStrings != null) {
1439                 Log.d(mLogTag, "loadFallbackPolicyWithImsRegiFail2:" + fallbackRulesStrings.length);
1440                 for (String ruleString : fallbackRulesStrings) {
1441                     Log.d(mLogTag, " ruleString2:" + ruleString);
1442                     FallbackRule rule = parseFallbackRule(ruleString);
1443                     if (rule != null) {
1444                         mFallbackWwanRuleWithImsHoRegisterFail.add(rule);
1445                     }
1446                 }
1447             } else {
1448                 Log.d(mLogTag, "Config mFallbackWwanRuleWithImsHoRegisterFail is null");
1449             }
1450         }
1451     }
1452 
parseFallbackRule(String ruleString)1453     private FallbackRule parseFallbackRule(String ruleString) {
1454         if (TextUtils.isEmpty(ruleString)) {
1455             throw new IllegalArgumentException("illegal rule " + ruleString);
1456         }
1457         Set<Integer> reasons = new ArraySet<>();
1458         int time = 0;
1459         int preferenceMode = -1;
1460         ruleString = ruleString.trim().toLowerCase(Locale.ROOT);
1461         String[] expressions = ruleString.split("\\s*,\\s*");
1462         for (String expression : expressions) {
1463             String[] tokens = expression.trim().split("\\s*=\\s*");
1464             if (tokens.length != 2) {
1465                 throw new IllegalArgumentException(
1466                         "illegal rule " + ruleString + ", tokens=" + Arrays.toString(tokens));
1467             }
1468             String key = tokens[0].trim();
1469             String value = tokens[1].trim();
1470 
1471             try {
1472                 switch (key) {
1473                     case "cause":
1474                         String[] cause = value.trim().split("\\s*\\|\\s*");
1475                         for (String c : cause) {
1476                             if (!c.contains("~")) {
1477                                 reasons.add(Integer.parseInt(c));
1478                             } else {
1479                                 String[] tok = c.trim().split("\\s*~\\s*");
1480                                 int start = Integer.parseInt(tok[0]);
1481                                 int end = Integer.parseInt(tok[1]);
1482                                 for (int i = start; i <= end; i++) {
1483                                     reasons.add(i);
1484                                 }
1485                             }
1486                         }
1487                         break;
1488                     case "time":
1489                         time = Integer.parseInt(value);
1490                         break;
1491                     case "preference":
1492                         if (value.equals("cell")) {
1493                             preferenceMode = QnsConstants.CELL_PREF;
1494                         } else if (value.equals("wifi")) {
1495                             preferenceMode = QnsConstants.WIFI_PREF;
1496                         }
1497                         break;
1498 
1499                     default:
1500                         throw new IllegalArgumentException("unexpected key " + key);
1501                 }
1502 
1503             } catch (Exception e) {
1504                 e.printStackTrace();
1505                 throw new IllegalArgumentException("illegal rule \"" + ruleString + "\", e=" + e);
1506             }
1507         }
1508         if (reasons.size() > 0) {
1509             return new FallbackRule(reasons, time, preferenceMode);
1510         } else {
1511             return null;
1512         }
1513     }
1514 
getConfig( PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String configKey)1515     private synchronized <T> T getConfig(
1516             PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String configKey) {
1517         return QnsUtils.getConfig(bundleCarrier, bundleAsset, configKey);
1518     }
1519 
1520     /** Load handover rules from carrier config. */
1521     @VisibleForTesting
loadHandoverRules( PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key)1522     void loadHandoverRules(
1523             PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key) {
1524         synchronized (this) {
1525             mHandoverRuleList.clear();
1526             String[] handoverRulesStrings = getConfig(bundleCarrier, bundleAsset, key);
1527             if (handoverRulesStrings != null) {
1528                 for (String ruleString : handoverRulesStrings) {
1529                     Log.d(mLogTag, "loadHandoverRules: " + ruleString);
1530                     try {
1531                         mHandoverRuleList.add(new HandoverRule(ruleString));
1532                     } catch (IllegalArgumentException e) {
1533                         Log.d(mLogTag, "loadHandoverRules: " + e.getMessage());
1534                     }
1535                 }
1536             }
1537         }
1538     }
1539 
loadMediaThreshold(PersistableBundle bundleCarrier, PersistableBundle assetConfigBundle)1540     void loadMediaThreshold(PersistableBundle bundleCarrier, PersistableBundle assetConfigBundle) {
1541         //read Jitter
1542         mRTPMetricsData[0] = getConfig(
1543                 bundleCarrier, null,
1544                 CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_JITTER_THRESHOLD_MILLIS_INT);
1545         //read Packet Loss Rate
1546         mRTPMetricsData[1] = getConfig(
1547                 bundleCarrier, null,
1548                 CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT);
1549         //read Inactivity Time
1550         long inactivityTime = getConfig(
1551                 bundleCarrier, null,
1552                 CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG);
1553         mRTPMetricsData[3] = (int) inactivityTime;
1554         //read Packet Loss Duration
1555         mRTPMetricsData[2] = getConfig(
1556                 bundleCarrier, assetConfigBundle,
1557                 KEY_QNS_MEDIA_THRESHOLD_RTP_PACKET_LOSS_TIME_MILLIS_INT);
1558     }
1559 
1560     /** Updated handover rules from carrier config. */
1561     @VisibleForTesting
updateHandoverRules( PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key)1562     List<HandoverRule> updateHandoverRules(
1563             PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key) {
1564         List<HandoverRule> readNewHandoverRuleList = new ArrayList<>();
1565         synchronized (this) {
1566             String[] handoverRulesStrings = getConfig(bundleCarrier, bundleAsset, key);
1567             if (handoverRulesStrings != null) {
1568                 for (String ruleString : handoverRulesStrings) {
1569                     Log.d(mLogTag, "UpdateHandoverRules: " + ruleString);
1570                     try {
1571                         Log.d(mLogTag, "Rule Updated");
1572                         readNewHandoverRuleList.add(new HandoverRule(ruleString));
1573                     } catch (IllegalArgumentException e) {
1574                         Log.d(mLogTag, "UpdateHandoverRules: " + e.getMessage());
1575                     }
1576                 }
1577             }
1578         }
1579         return readNewHandoverRuleList;
1580     }
1581 
1582     /** Load carrier config. */
1583     @VisibleForTesting
loadCarrierConfig(PersistableBundle bundleCarrier)1584     void loadCarrierConfig(PersistableBundle bundleCarrier) {
1585         mIsMmtelCapabilityRequired =
1586                 getConfig(
1587                         bundleCarrier,
1588                         null,
1589                         CarrierConfigManager.Ims.KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY);
1590         mIsVolteRoamingSupported =
1591                 getConfig(
1592                         bundleCarrier,
1593                         null,
1594                         CarrierConfigManager.ImsVoice.KEY_CARRIER_VOLTE_ROAMING_AVAILABLE_BOOL);
1595     }
1596 
1597     /**
1598      * To read the current Carrier ID based on the Slot ID and Context info
1599      *
1600      * @return : Current Carrier ID
1601      */
getCarrierId()1602     int getCarrierId() {
1603         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1604         if (tm != null) {
1605             tm = tm.createForSubscriptionId(QnsUtils.getSubId(mContext, mSlotIndex));
1606             return tm.getSimCarrierId();
1607         }
1608         return 0;
1609     }
1610 
1611     /**
1612      * To read the current Subscription ID based on the Slot ID and Context info Output : Current
1613      * Carrier ID
1614      */
getSubId()1615     int getSubId() {
1616         mSubId = QnsUtils.getSubId(mContext, mSlotIndex);
1617         return mSubId;
1618     }
1619 
1620     /** Notify all the registrants of the Slot loaded after carrier config loading is Completed */
notifyLoadQnsConfigurationsCompleted()1621     protected void notifyLoadQnsConfigurationsCompleted() {
1622         if (mQnsCarrierConfigLoadedRegistrants != null) {
1623             mQnsCarrierConfigLoadedRegistrants.notifyRegistrants();
1624         } else {
1625             Log.d(mLogTag, "notifyLoadQnsConfigurationsCompleted. no Registrant.");
1626         }
1627     }
1628 
1629     /** Notify all the registrants of the Slot loaded after carrier config loading is Completed */
notifyQnsConfigurationsChanged()1630     protected void notifyQnsConfigurationsChanged() {
1631 
1632         if (mQnsCarrierConfigChangedRegistrants != null) {
1633             mQnsCarrierConfigChangedRegistrants.notifyRegistrants();
1634         } else {
1635             Log.d(mLogTag, "notifyQnsConfigurationsChanged. no Registrant.");
1636         }
1637     }
1638 
1639     /**
1640      * API exposed for other classes to register for notification with handlers on Carrier
1641      * Configuration Loaded
1642      *
1643      * @param h    Handler to receive event
1644      * @param what Event on which to be handled
1645      */
registerForConfigurationLoaded(Handler h, int what)1646     void registerForConfigurationLoaded(Handler h, int what) {
1647         mQnsCarrierConfigLoadedRegistrants.addUnique(h, what, null);
1648         if (mIsConfigLoaded) {
1649             // notify the handler if config is already loaded.
1650             h.sendEmptyMessage(what);
1651         }
1652     }
1653 
1654     /**
1655      * API exposed for other classes to register for notification with handlers on Carrier
1656      * Configuration changed
1657      *
1658      * @param h    Handler to receive event
1659      * @param what Event on which to be handled
1660      */
registerForConfigurationChanged(Handler h, int what)1661     void registerForConfigurationChanged(Handler h, int what) {
1662         mQnsCarrierConfigChangedRegistrants.addUnique(h, what, null);
1663     }
1664 
1665     /**
1666      * API exposed for other classes to unregister for notification of QNS Configuration loaded with
1667      * handlers
1668      *
1669      * @param h Handler to Unregister receiving event Output : Void
1670      */
unregisterForConfigurationLoaded(Handler h)1671     void unregisterForConfigurationLoaded(Handler h) {
1672         mQnsCarrierConfigLoadedRegistrants.remove(h);
1673     }
1674 
1675     /**
1676      * API exposed for other classes to unregister for notification of QNS Configuration changed
1677      * with handlers
1678      *
1679      * @param h Handler to Unregister receiving event Output : Void
1680      */
unregisterForConfigurationChanged(Handler h)1681     void unregisterForConfigurationChanged(Handler h) {
1682         mQnsCarrierConfigChangedRegistrants.remove(h);
1683     }
1684 
1685     /**
1686      * This method returns if WFC is supported in Airplane Mode On
1687      *
1688      * @return : boolean (True/False)
1689      */
allowWFCOnAirplaneModeOn()1690     boolean allowWFCOnAirplaneModeOn() {
1691 
1692         return mIsWfcInAirplaneModeOnSupport;
1693     }
1694 
1695     /**
1696      * This method returns if in-call handover decision from WLAN to WWAN should not consider VoPS
1697      * status.
1698      *
1699      * @return True if in-call handover decision from WLAN to WWAN should not consider VoPS status,
1700      * otherwise false.
1701      */
isInCallHoDecisionWlanToWwanWithoutVopsCondition()1702     boolean isInCallHoDecisionWlanToWwanWithoutVopsCondition() {
1703         return mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported;
1704     }
1705 
1706     /**
1707      * This method returns VOPS/VONR bit is required for WWAN availability.
1708      *
1709      * @return : boolean (True/False)
1710      */
isMmtelCapabilityRequired(int coverage)1711     boolean isMmtelCapabilityRequired(int coverage) {
1712         if (mIsMmtelCapabilityRequired == null || mIsMmtelCapabilityRequired.length == 0) {
1713             return true;
1714         }
1715         for (int i : mIsMmtelCapabilityRequired) {
1716             if ((i == CarrierConfigManager.Ims.NETWORK_TYPE_HOME
1717                             && coverage == QnsConstants.COVERAGE_HOME)
1718                     || (i == CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING
1719                             && coverage == QnsConstants.COVERAGE_ROAM)) {
1720                 return false;
1721             }
1722         }
1723         return true;
1724     }
1725 
1726     /**
1727      * This method returns if VoLTE roaming is supported by a carrier.
1728      *
1729      * @return True if VoLTE roaming is supported or UE is in home network, otherwise false.
1730      */
isVolteRoamingSupported(@nsConstants.CellularCoverage int coverage)1731     boolean isVolteRoamingSupported(@QnsConstants.CellularCoverage int coverage) {
1732         if (coverage == QnsConstants.COVERAGE_ROAM) {
1733             return mIsVolteRoamingSupported;
1734         }
1735         return true;
1736     }
1737 
1738     /**
1739      * This method returns Video call over WFC with wfc off & LTE preconditions met
1740      *
1741      * @return : boolean (True/False)
1742      */
allowVideoOverIWLANWithCellularLimitedCase()1743     boolean allowVideoOverIWLANWithCellularLimitedCase() {
1744         return mIsVideoOverIWLANWithCellularCheckSupport;
1745     }
1746 
1747     /**
1748      * This method returns if handover is allowed by policy
1749      *
1750      * @return True if handover is allowed by policy, otherwise false.
1751      */
isHandoverAllowedByPolicy( int netCapability, int srcAn, int destAn, @QnsConstants.CellularCoverage int coverage)1752     boolean isHandoverAllowedByPolicy(
1753             int netCapability, int srcAn, int destAn, @QnsConstants.CellularCoverage int coverage) {
1754         Log.d(
1755                 mLogTag,
1756                 "isHandoverAllowedByPolicy netCapability: "
1757                         + QnsUtils.getNameOfNetCapability(netCapability)
1758                         + " srcAccessNetwork:"
1759                         + QnsConstants.accessNetworkTypeToString(srcAn)
1760                         + " destAccessNetwork:"
1761                         + QnsConstants.accessNetworkTypeToString(destAn)
1762                         + "  "
1763                         + QnsConstants.coverageToString(coverage));
1764         // check Telephony handover policy.
1765         // Matching the rules by the configured order. Bail out if find first matching rule.
1766         for (HandoverRule rule : mHandoverRuleList) {
1767             if (rule.mIsOnlyForRoaming && coverage != QnsConstants.COVERAGE_ROAM) continue;
1768 
1769             if (rule.mSourceAccessNetworks.contains(srcAn)
1770                     && rule.mTargetAccessNetworks.contains(destAn)) {
1771                 // if no capability rule specified, data network capability is considered matched.
1772                 // otherwise, any capabilities overlap is also considered matched.
1773                 if (rule.mNetworkCapabilities.isEmpty()
1774                         || rule.mNetworkCapabilities.contains(netCapability)) {
1775                     if (rule.mHandoverRuleType == HandoverRule.RULE_TYPE_DISALLOWED) {
1776                         Log.d(mLogTag, "isHandoverAllowedByPolicy:Not allowed by policy " + rule);
1777                         return false;
1778                     } else {
1779                         Log.d(mLogTag, "isHandoverAllowedByPolicy: allowed by policy " + rule);
1780                         return true;
1781                     }
1782                 }
1783             }
1784         }
1785 
1786         Log.d(mLogTag, "isHandoverAllowedByPolicy: Did not find matching rule. ");
1787         // Disallow handover for non-IMS network capability anyway if no rule is found.
1788         if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS) return false;
1789 
1790         // Allow handover for IMS network capability anyway if no rule is found.
1791         return true;
1792     }
1793 
1794     /**
1795      * This method returns if Service Barring Check for HO decision is Supported
1796      *
1797      * @return : boolean (True/False)
1798      */
isServiceBarringCheckSupported()1799     boolean isServiceBarringCheckSupported() {
1800 
1801         return mIsServiceBarringCheckSupport;
1802     }
1803 
1804     /**
1805      * This method returns if the Guard timer (Ping Pong) hysteresis is preference specific
1806      *
1807      * @return : Based on Carrier Config Settings based on operator requirement possible values:
1808      * True / False
1809      */
isGuardTimerHysteresisOnPrefSupported()1810     boolean isGuardTimerHysteresisOnPrefSupported() {
1811 
1812         return mIsHoGuardOnPreferenceSupport;
1813     }
1814 
1815     /**
1816      * This method returns if the network(HOME or ROAM) requires handover guard timer.
1817      *
1818      * @return : Based on Carrier Config Settings based on operator requirement possible values:
1819      * True / False
1820      */
isHysteresisTimerEnabled(int coverage)1821     boolean isHysteresisTimerEnabled(int coverage) {
1822         if (mNetworkEnableHysteresisTimer == QnsConstants.COVERAGE_BOTH
1823                 || mNetworkEnableHysteresisTimer == coverage) {
1824             return true;
1825         }
1826         return false;
1827     }
1828 
1829     /**
1830      * Get carrier config for the KEY_ROAM_TRANSPORT_TYPE_SELECTION_WITHOUT_SIGNAL_STRENGTH_BOOL if
1831      * true, It ignores all thresholds needed to only refer to availability.
1832      *
1833      * @return true for key value is true. False for otherwise.
1834      */
isTransportTypeSelWithoutSSInRoamSupported()1835     boolean isTransportTypeSelWithoutSSInRoamSupported() {
1836 
1837         return mAnspSupportConfigArray[0];
1838     }
1839 
1840     /*
1841      * get carrierconfig for KEY_PREFER_CURRENT_TRANSPORT_TYPE_IN_VOICE_CALL
1842      * true: Prefer current transport type during voice call.
1843      *
1844      * @return true for key value is true. False for otherwise.
1845      */
isCurrentTransportTypeInVoiceCallSupported()1846     boolean isCurrentTransportTypeInVoiceCallSupported() {
1847 
1848         return mAnspSupportConfigArray[1];
1849     }
1850 
1851     /**
1852      * Get carrierconfig for KEY_POLICY_OVERRIDE_CELL_PREF_TO_IMS_PREF_HOME_BOOL
1853      * true: Use IMS Preferred when WFC Mode is Cellular Preferred at Home Network.
1854      *
1855      * @return true for key value is true. False for otherwise.
1856      */
isOverrideImsPreferenceSupported()1857     boolean isOverrideImsPreferenceSupported() {
1858         return mAnspSupportConfigArray[2];
1859     }
1860 
1861     /**
1862      * The method is to return if choose WFC prferred transport in both WWAN and WLAN are bad
1863      * conditions. It is controlled by
1864      * KEY_CHOOSE_WFC_PREFERRED_TRANSPORT_IN_BOTH_BAD_CONDITION_INT_ARRAY.
1865      *
1866      * @return : boolean (True/False)
1867      */
isChooseWfcPreferredTransportInBothBadCondition(int wfcMode)1868     boolean isChooseWfcPreferredTransportInBothBadCondition(int wfcMode) {
1869         if (mIsWfcPreferredTransportRequired == null
1870                 || mIsWfcPreferredTransportRequired.length == 0) {
1871             return false;
1872         }
1873         for (int i : mIsWfcPreferredTransportRequired) {
1874             if (wfcMode == i) {
1875                 return true;
1876             }
1877         }
1878         return false;
1879     }
1880 
1881     /**
1882      * This method returns whether the rove out(to Cellular) policy includes a Wi-Fi bad condition
1883      * at handover guarding time.
1884      *
1885      * @return : Based on Carrier Config Settings based on operator requirement possible values:
1886      * True / False
1887      */
isRoveOutWithWiFiLowQualityAtGuardingTime()1888     boolean isRoveOutWithWiFiLowQualityAtGuardingTime() {
1889 
1890         return mIsRoveOutWifiBadGuardTimerConditionsSupported;
1891     }
1892 
1893     /**
1894      * This method returns the waiting time for the preferred transport type at power up.
1895      *
1896      * @return : A timer in millisecond
1897      */
getWaitingTimerForPreferredTransportOnPowerOn(int transportType)1898     int getWaitingTimerForPreferredTransportOnPowerOn(int transportType) {
1899         switch (transportType) {
1900             case TRANSPORT_TYPE_WWAN:
1901                 return mWaitingTimerForPreferredTransport[0];
1902             case TRANSPORT_TYPE_WLAN:
1903                 return mWaitingTimerForPreferredTransport[1];
1904             default:
1905                 Log.d(mLogTag, "Invalid transport type, return the default timer.");
1906                 return QnsConstants.KEY_DEFAULT_VALUE;
1907         }
1908     }
1909 
1910     /**
1911      * This method returns the Transport type Preference on Power On.
1912      *
1913      * @return : Based on Carrier Config Settings Possible values (3000msec:Default or operator
1914      * customisation.
1915      */
getWIFIRssiBackHaulTimer()1916     int getWIFIRssiBackHaulTimer() {
1917         return mWifiThresBackHaulTimer;
1918     }
1919 
1920     /**
1921      * This method returns Cellular SS Backhaul Timer.
1922      *
1923      * @return : Based on Carrier Config Settings based on operator requirement possible values ( 0
1924      * : Invalid or 320ms)
1925      */
getCellularSSBackHaulTimer()1926     int getCellularSSBackHaulTimer() {
1927 
1928         return mCellularThresBackHaulTimer;
1929     }
1930 
1931     /**
1932      * This method returns IWLAN HO Avoid time due to Low RTP Quality Backhaul Timer.
1933      *
1934      * @return : Based on Carrier Config Settings based on operator requirement possible values ( 0
1935      * : or operator requirement)
1936      */
getHoRestrictedTimeOnLowRTPQuality( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork)1937     int getHoRestrictedTimeOnLowRTPQuality(
1938             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork) {
1939 
1940         if (accessNetwork == TRANSPORT_TYPE_WLAN) {
1941             return mHoRestrictTimeOnRtpQuality[0];
1942         } else if (accessNetwork == TRANSPORT_TYPE_WWAN) {
1943             return mHoRestrictTimeOnRtpQuality[1];
1944         } else {
1945             return QnsConstants.KEY_DEFAULT_VALUE;
1946         }
1947     }
1948 
1949     /**
1950      * This method returns QNS preferred transport type for network capabilities / Services
1951      *
1952      * @return : Based on Carrier Config Settings based on operator requirement possible values:
1953      * TRANSPORT_TYPE_ALLOWED_WWAN = 0 TRANSPORT_TYPE_ALLOWED_IWLAN = 1
1954      * TRANSPORT_TYPE_ALLOWED_BOTH = 2
1955      */
getQnsSupportedTransportType(int netCapability)1956     int getQnsSupportedTransportType(int netCapability) {
1957         if (netCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
1958             return mQnsImsTransportType;
1959         } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
1960             return mQnsSosTransportType;
1961         } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_MMS) {
1962             return mQnsMmsTransportType;
1963         } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_XCAP) {
1964             HashSet<Integer> supportedTransportType = new HashSet<>();
1965             if (mQnsXcapSupportedAccessNetworkTypes != null) {
1966                 Arrays.stream(mQnsXcapSupportedAccessNetworkTypes)
1967                         .forEach(accessNetwork -> supportedTransportType.add(
1968                                 QnsUtils.getTransportTypeFromAccessNetwork(accessNetwork)));
1969             }
1970             if (supportedTransportType.contains(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)) {
1971                 if (supportedTransportType.contains(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) {
1972                     return QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH;
1973                 }
1974                 return QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN;
1975             }
1976             return QnsConstants.TRANSPORT_TYPE_ALLOWED_WWAN;
1977         } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_CBS) {
1978             return mQnsCbsTransportType;
1979         }
1980         return QnsConstants.INVALID_ID;
1981     }
1982 
1983     /**
1984      * This method returns the hysteresis timer when handover from WLAN to WWAN.
1985      *
1986      * @return : the hysteresis timer
1987      */
getWwanHysteresisTimer(int netCapability, @QnsConstants.QnsCallType int callType)1988     int getWwanHysteresisTimer(int netCapability, @QnsConstants.QnsCallType int callType) {
1989         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC)) {
1990             return mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC);
1991         }
1992         switch (netCapability) {
1993             case NetworkCapabilities.NET_CAPABILITY_IMS:
1994             case NetworkCapabilities.NET_CAPABILITY_EIMS:
1995                 if (callType == QnsConstants.CALL_TYPE_IDLE) {
1996                     return mWwanHysteresisTimer[0];
1997                 } else if (callType == QnsConstants.CALL_TYPE_VOICE) {
1998                     return mWwanHysteresisTimer[1];
1999                 } else if (callType == QnsConstants.CALL_TYPE_VIDEO) {
2000                     return mWwanHysteresisTimer[2];
2001                 } else {
2002                     return QnsConstants.KEY_DEFAULT_VALUE;
2003                 }
2004             case NetworkCapabilities.NET_CAPABILITY_MMS:
2005             case NetworkCapabilities.NET_CAPABILITY_XCAP:
2006             case NetworkCapabilities.NET_CAPABILITY_CBS:
2007                 if (callType == QnsConstants.CALL_TYPE_IDLE) {
2008                     return mNonImsWwanHysteresisTimer[0];
2009                 } else {
2010                     return mNonImsWwanHysteresisTimer[1];
2011                 }
2012             default:
2013                 return QnsConstants.KEY_DEFAULT_VALUE;
2014         }
2015     }
2016 
2017     /**
2018      * This method returns the hysteresis timer when handover from WWAN to WLAN.
2019      *
2020      * @return : the hysteresis timer
2021      */
getWlanHysteresisTimer(int netCapability, @QnsConstants.QnsCallType int callType)2022     int getWlanHysteresisTimer(int netCapability, @QnsConstants.QnsCallType int callType) {
2023         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC)) {
2024             return mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC);
2025         }
2026         switch (netCapability) {
2027             case NetworkCapabilities.NET_CAPABILITY_IMS:
2028             case NetworkCapabilities.NET_CAPABILITY_EIMS:
2029                 if (callType == QnsConstants.CALL_TYPE_IDLE) {
2030                     return mWlanHysteresisTimer[0];
2031                 } else if (callType == QnsConstants.CALL_TYPE_VOICE) {
2032                     return mWlanHysteresisTimer[1];
2033                 } else if (callType == QnsConstants.CALL_TYPE_VIDEO) {
2034                     return mWlanHysteresisTimer[2];
2035                 } else {
2036                     return QnsConstants.KEY_DEFAULT_VALUE;
2037                 }
2038             case NetworkCapabilities.NET_CAPABILITY_MMS:
2039             case NetworkCapabilities.NET_CAPABILITY_XCAP:
2040             case NetworkCapabilities.NET_CAPABILITY_CBS:
2041                 if (callType == QnsConstants.CALL_TYPE_IDLE) {
2042                     return mNonImsWlanHysteresisTimer[0];
2043                 } else {
2044                     return mNonImsWlanHysteresisTimer[1];
2045                 }
2046             default:
2047                 return QnsConstants.KEY_DEFAULT_VALUE;
2048         }
2049     }
2050 
2051     /**
2052      * This method returns the timer millis for the minimum guarding timer.
2053      *
2054      * @return the minimum guarding timer in millis. applies when handover guarding is disabled or
2055      * there is no guarding time.
2056      */
getMinimumHandoverGuardingTimer()2057     int getMinimumHandoverGuardingTimer() {
2058         int timer = mMinimumHandoverGuardingTimer;
2059         if (timer <= 0) {
2060             return 0;
2061         }
2062         if (timer >= QnsConstants.CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER_LIMIT) {
2063             timer = QnsConstants.CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER_LIMIT;
2064         }
2065         return timer;
2066     }
2067 
2068     /**
2069      * This method returns the Threshold gap offset based on which threshold to be registered during
2070      * Guard timer Running / Expired conditions from Evaluator
2071      *
2072      * @return : Based on Carrier Config Settings & operator requirement Default Value : 0 gap
2073      * offset (Means different threshold for Guard timer conditions not enabled)
2074      */
getThresholdGapWithGuardTimer( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType)2075     int getThresholdGapWithGuardTimer(
2076             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType) {
2077 
2078         return getValueForMeasurementType(
2079                 accessNetwork, measType, mRoveInGuardTimerConditionThresholdGaps);
2080 
2081     }
2082 
2083     /**
2084      *  This method returns hysteresis Dbm level for ran and measurement type configured.
2085      *
2086      * @return : Based on Carrier Config Settings & operator requirement Default Value.
2087      * Note: If configured value set is less than zero or not set,
2088      * {@link QnsConstants#KEY_DEFAULT_VALUE}
2089      */
getWwanHysteresisDbLevel( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType)2090     public int getWwanHysteresisDbLevel(
2091             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType) {
2092 
2093         int hysteresisDb = getValueForMeasurementType(
2094                 accessNetwork, measType, mAccessNetworkMeasurementHysteresisDb);
2095         return hysteresisDb >= 0 ? hysteresisDb : QnsConstants.KEY_DEFAULT_VALUE;
2096     }
2097 
getValueForMeasurementType( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType, String [] measurementValues)2098     private int getValueForMeasurementType(
2099             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType,
2100             String [] measurementValues) {
2101 
2102         if (measurementValues == null) {
2103             return QnsConstants.KEY_DEFAULT_VALUE;
2104         }
2105 
2106         for (String check_offset : measurementValues) {
2107             if (check_offset == null || check_offset.isEmpty()) continue;
2108             String[] value = check_offset.split(":");
2109             String access_network = sAccessNetworkMap.get(accessNetwork);
2110             String measurement_Type = sMeasTypeMap.get(measType);
2111             try {
2112                 if (value.length == 3 && value[0].equalsIgnoreCase(access_network)
2113                         && value[1].equalsIgnoreCase(measurement_Type)) {
2114                     return Integer.parseInt(value[2]);
2115                 }
2116             } catch (Exception e) {
2117                 e.printStackTrace();
2118             }
2119         }
2120         return QnsConstants.KEY_DEFAULT_VALUE;
2121     }
2122 
hasThresholdGapWithGuardTimer()2123     boolean hasThresholdGapWithGuardTimer() {
2124         if (mRoveInGuardTimerConditionThresholdGaps == null) {
2125             return false;
2126         }
2127         return true;
2128     }
2129 
2130     /**
2131      * This method returns Access Network Selection Policy based on network capability
2132      *
2133      * @param targetTransportType : WWAN/WLAN
2134      * @return : Target transport mapped to string
2135      */
transportNetworkToString(int targetTransportType)2136     static String transportNetworkToString(int targetTransportType) {
2137         switch (targetTransportType) {
2138             case TRANSPORT_TYPE_WWAN:
2139                 return "CELLULAR";
2140             case TRANSPORT_TYPE_WLAN:
2141                 return "WIFI";
2142         }
2143         return "";
2144     }
2145 
2146     /**
2147      * Finds and returns a threshold config that meets the given parameter condition.
2148      *
2149      * @param accessNetwork   (EUTRAN/UTRAN/NGRAN/GERAN/IWLAN)
2150      * @param callType        (IDLE/VOICE/VIDEO)
2151      * @param measurementType (RSRP/RSRQ/RSSNR/SSRSP/SSRSQ/RSCP/RSSI)
2152      * @return QnsConfigArray for good, bad and worst thresholds. If the value does not exist or is
2153      * not supported, it is filled with invalid (0x0000FFFF). Note, for the wifi case, the worst
2154      * in thresholds will be invalid. INVALID VALUE, if not found item or exceptions.
2155      */
getThreshold( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int callType, int measurementType)2156     QnsConfigArray getThreshold(
2157             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork,
2158             int callType,
2159             int measurementType) {
2160         int[] thresholdList = new int[] {0x0000FFFF, 0x0000FFFF, 0x0000FFFF};
2161         if (accessNetwork == AccessNetworkConstants.AccessNetworkType.UNKNOWN
2162                 || measurementType == SIGNAL_MEASUREMENT_TYPE_UNKNOWN) {
2163             return null;
2164         }
2165 
2166         String access_network = sAccessNetworkMap.get(accessNetwork);
2167         String measurement_Type = sMeasTypeMap.get(measurementType);
2168         String call_Type = sCallTypeMap.get(callType);
2169 
2170         if (access_network != null && measurement_Type != null && call_Type != null) {
2171             String key =
2172                     "qns."
2173                             + call_Type
2174                             + "_"
2175                             + access_network
2176                             + "_"
2177                             + measurement_Type
2178                             + "_"
2179                             + "int_array";
2180 
2181             thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key);
2182 
2183             if (thresholdList != null && thresholdList.length > 1) {
2184                 if (AccessNetworkConstants.AccessNetworkType.IWLAN == accessNetwork
2185                         || thresholdList.length == 2) {
2186                     return new QnsConfigArray(thresholdList[0], thresholdList[1]);
2187                 } else {
2188                     return new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]);
2189                 }
2190             } else {
2191                 thresholdList = new int[] {0x0000FFFF, 0x0000FFFF, 0x0000FFFF};
2192             }
2193         }
2194         return new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]);
2195     }
2196 
getThresholdByPref( int accessNetwork, int callType, int measurementType, int preference)2197     QnsConfigArray getThresholdByPref(
2198             int accessNetwork, int callType, int measurementType, int preference) {
2199         if (accessNetwork == AccessNetworkConstants.AccessNetworkType.UNKNOWN
2200                 || measurementType == SIGNAL_MEASUREMENT_TYPE_UNKNOWN) {
2201             return null;
2202         }
2203 
2204         int[] thresholdList = null;
2205         String access_network = sAccessNetworkMap.get(accessNetwork);
2206         String measurement_Type = sMeasTypeMap.get(measurementType);
2207         String call_Type = sCallTypeMap.get(callType);
2208 
2209         if (access_network == null || measurement_Type == null || call_Type == null) {
2210             return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF);
2211         }
2212 
2213         if (accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN
2214                 && preference == QnsConstants.WIFI_PREF) {
2215             String overrideKey =
2216                     "qns.override_wifi_pref_"
2217                             + call_Type
2218                             + "_"
2219                             + access_network
2220                             + "_"
2221                             + measurement_Type
2222                             + "_int_array";
2223             thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(overrideKey);
2224         }
2225 
2226         if (thresholdList == null || thresholdList.length < 2) {
2227             String key =
2228                     "qns."
2229                             + call_Type
2230                             + "_"
2231                             + access_network
2232                             + "_"
2233                             + measurement_Type
2234                             + "_int_array";
2235             thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key);
2236         }
2237         if (thresholdList == null || thresholdList.length < 2) {
2238             return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF);
2239         }
2240 
2241         if (AccessNetworkConstants.AccessNetworkType.IWLAN == accessNetwork
2242                 || thresholdList.length == 2) {
2243             QnsConfigArray qnsConfigArray = new QnsConfigArray(thresholdList[0], thresholdList[1]);
2244             return applyProvisioningInfo(qnsConfigArray, accessNetwork, measurementType, callType);
2245         }
2246 
2247         QnsConfigArray qnsConfigArray =
2248                 new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]);
2249         return applyProvisioningInfo(qnsConfigArray, accessNetwork, measurementType, callType);
2250     }
2251 
getWifiRssiThresholdWithoutCellular(int callType)2252     QnsConfigArray getWifiRssiThresholdWithoutCellular(int callType) {
2253         int[] thresholdList;
2254         String call_Type = sCallTypeMap.get(callType);
2255 
2256         if (call_Type == null) {
2257             return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF);
2258         }
2259 
2260         String key = "qns." + call_Type + "_wifi_rssi_without_cellular_int_array";
2261         thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key);
2262 
2263         if (thresholdList == null || thresholdList.length < 2) {
2264             return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF);
2265         }
2266 
2267         return new QnsConfigArray(thresholdList[0], thresholdList[1]);
2268     }
2269 
2270     /**
2271      * Finds and returns a policy config that meets the given parameter condition.
2272      *
2273      * @param direction    (ROVE_IN / ROVE_OUT)
2274      * @param preCondition (Types of CALL, PREFERENCE, COVERAGE and so on)
2275      * @return QnsConfigArray for good, bad and worst policy. If the value does not exist or is not
2276      * supported, it is filled with invalid. (0x0000FFFF). Note, for the wifi case, the worst in
2277      * thresholds will be invalid. null, if not found item or exceptions.
2278      */
getPolicy( @nsConstants.RoveDirection int direction, AccessNetworkSelectionPolicy.PreCondition preCondition)2279     String[] getPolicy(
2280             @QnsConstants.RoveDirection int direction,
2281             AccessNetworkSelectionPolicy.PreCondition preCondition) {
2282 
2283         String key =
2284                 "qns.condition_"
2285                         + QnsConstants.directionToString(direction).toLowerCase()
2286                         + "_"
2287                         + QnsConstants.callTypeToString(preCondition.getCallType()).toLowerCase()
2288                         + "_"
2289                         + QnsConstants.preferenceToString(preCondition.getPreference())
2290                                 .toLowerCase()
2291                         + "_"
2292                         + QnsConstants.coverageToString(preCondition.getCoverage()).toLowerCase()
2293                         + "_";
2294 
2295         if (preCondition instanceof AccessNetworkSelectionPolicy.GuardingPreCondition) {
2296             AccessNetworkSelectionPolicy.GuardingPreCondition guardingCondition =
2297                     (AccessNetworkSelectionPolicy.GuardingPreCondition) preCondition;
2298             String guardingKey =
2299                     key
2300                             + QnsConstants.guardingToString(guardingCondition.getGuarding())
2301                                     .toLowerCase()
2302                             + "_string_array";
2303             String[] guardingPolicy = mAnspConfigMgr.getAnspCarrierPolicy(guardingKey);
2304             if (guardingPolicy != null) {
2305                 return guardingPolicy;
2306             }
2307         }
2308         key = key + "string_array";
2309         return mAnspConfigMgr.getAnspCarrierPolicy(key);
2310     }
2311 
2312     /**
2313      * This method returns RTP Metrics data of Carrier for HO decision making
2314      *
2315      * @return config of RTP metrics. refer {@link RtpMetricsConfig}
2316      */
2317     @VisibleForTesting
getRTPMetricsData()2318     RtpMetricsConfig getRTPMetricsData() {
2319 
2320         return new RtpMetricsConfig(
2321                 mRTPMetricsData[0], mRTPMetricsData[1], mRTPMetricsData[2], mRTPMetricsData[3]);
2322     }
2323 
2324     /**
2325      * This retrieves fallback timer to WWAN with the reason of IMS unregistered.
2326      *
2327      * @return fallback time in millis.
2328      */
2329     @VisibleForTesting
getFallbackTimeImsUnregistered(int reason, int preferMode)2330     int getFallbackTimeImsUnregistered(int reason, int preferMode) {
2331         Log.d(
2332                 mLogTag,
2333                 "getFallbackTimeImsUnregistered reason:" + reason + " prefMode:" + preferMode);
2334         for (FallbackRule rule : mFallbackWwanRuleWithImsUnregistered) {
2335             Log.d(mLogTag, rule.toString());
2336             if (preferMode != QnsConstants.WIFI_ONLY
2337                     && (rule.mPreferenceMode == -1 || rule.mPreferenceMode == preferMode)) {
2338                 int time = rule.getFallBackTime(reason);
2339                 if (time > 0) {
2340                     Log.d(mLogTag, "getFallbackTimeImsUnregistered fallbackTime:" + time);
2341                     return time;
2342                 }
2343             }
2344         }
2345         Log.d(mLogTag, "getFallbackTimeImsUnregistered fallbackTime:" + 0);
2346         return 0;
2347     }
2348 
2349     /**
2350      * This retrieves fallback timer to WWAN with the reason of IMS HO register fail.
2351      *
2352      * @return fallback time in millis.
2353      */
2354     @VisibleForTesting
getFallbackTimeImsHoRegisterFailed(int reason, int preferMode)2355     int getFallbackTimeImsHoRegisterFailed(int reason, int preferMode) {
2356         Log.d(
2357                 mLogTag,
2358                 "getFallbackTimeImsHoRegisterFailed reason:" + reason + " prefMode:" + preferMode);
2359         for (FallbackRule rule : mFallbackWwanRuleWithImsHoRegisterFail) {
2360             if (preferMode != QnsConstants.WIFI_ONLY
2361                     && (rule.mPreferenceMode == -1 || rule.mPreferenceMode == preferMode)) {
2362                 Log.d(mLogTag, rule.toString());
2363                 int time = rule.getFallBackTime(reason);
2364                 Log.d(mLogTag, "getFallbackTimeImsHoRegisterFailed fallback time: " + time);
2365                 if (time > 0) return time;
2366             }
2367         }
2368         Log.d(mLogTag, "getFallbackTimeImsHoRegisterFailed fallback time: " + 0);
2369         return 0;
2370     }
2371 
2372     /**
2373      * This method returns Access Network Selection Policy Support configurations with boolean array
2374      * list type
2375      *
2376      */
loadAnspCarrierSupportConfigs( PersistableBundle bundleCarrier, PersistableBundle bundleAsset)2377     void loadAnspCarrierSupportConfigs(
2378             PersistableBundle bundleCarrier, PersistableBundle bundleAsset) {
2379         int i = 0;
2380         String[] anspConfigs = {
2381             KEY_ROAM_TRANSPORT_TYPE_SELECTION_WITHOUT_SIGNAL_STRENGTH_BOOL,
2382             KEY_PREFER_CURRENT_TRANSPORT_TYPE_IN_VOICE_CALL_BOOL,
2383             KEY_POLICY_OVERRIDE_CELL_PREF_TO_IMS_PREF_HOME_BOOL
2384         };
2385 
2386         for (String key : anspConfigs) {
2387             mAnspSupportConfigArray[i] = getConfig(bundleCarrier, bundleAsset, key);
2388             i += 1;
2389         }
2390 
2391         mIsWfcPreferredTransportRequired =
2392                 getConfig(
2393                         bundleCarrier,
2394                         bundleAsset,
2395                         KEY_CHOOSE_WFC_PREFERRED_TRANSPORT_IN_BOTH_BAD_CONDITION_INT_ARRAY);
2396     }
2397 
2398     /**
2399      * This method gives the network capabilities supported based on
2400      * KEY_QNS_<NetworkCapability></NetworkCapability>_TRANSPORT_TYPE_INT
2401      *
2402      * @return : Supported network capabilities
2403      */
getQnsSupportedNetCapabilities()2404     List<Integer> getQnsSupportedNetCapabilities() {
2405         List<Integer> netCapabilities = new ArrayList<>();
2406         if (mQnsImsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN
2407                 || mQnsImsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) {
2408             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_IMS);
2409         }
2410         if (mQnsSosTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN
2411                 || mQnsSosTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) {
2412             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_EIMS);
2413         }
2414         if (mQnsMmsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN
2415                 || mQnsMmsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) {
2416             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_MMS);
2417         }
2418         if (mQnsXcapSupportedAccessNetworkTypes != null
2419                 && Arrays.stream(mQnsXcapSupportedAccessNetworkTypes)
2420                         .anyMatch(accessNetwork -> QnsUtils.getTransportTypeFromAccessNetwork(
2421                                 accessNetwork) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN)) {
2422             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_XCAP);
2423         }
2424         if (mQnsCbsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN
2425                 || mQnsCbsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) {
2426             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_CBS);
2427         }
2428         return netCapabilities;
2429     }
2430 
2431     private static final Map<Integer, String> sRatStringMatcher = Map.of(
2432             AccessNetworkConstants.AccessNetworkType.EUTRAN, "LTE",
2433             AccessNetworkConstants.AccessNetworkType.NGRAN, "NR",
2434             AccessNetworkConstants.AccessNetworkType.UTRAN, "3G",
2435             AccessNetworkConstants.AccessNetworkType.GERAN, "2G"
2436     );
2437 
2438     /**
2439      * This method returns Allowed cellular RAT for IMS
2440      *
2441      * @param accessNetwork : (EUTRAN, NGRAN, UTRAN, GERAN)
2442      * @param netCapability : (ims, sos, mms, xcap, cbs)
2443      * @return : True or False based on configuration
2444      */
isAccessNetworkAllowed(int accessNetwork, int netCapability)2445     boolean isAccessNetworkAllowed(int accessNetwork, int netCapability) {
2446 
2447         switch (netCapability) {
2448             case NetworkCapabilities.NET_CAPABILITY_EIMS:
2449             case NetworkCapabilities.NET_CAPABILITY_IMS:
2450                 // cases to be enhanced for different key items when added
2451                 String ratName = sRatStringMatcher.get(accessNetwork);
2452                 if (mImsAllowedRats != null
2453                         && ratName != null
2454                         && Arrays.stream(mImsAllowedRats)
2455                                 .anyMatch(ratType -> TextUtils.equals(ratType, ratName))) {
2456                     return true;
2457                 }
2458                 break;
2459             case NetworkCapabilities.NET_CAPABILITY_XCAP:
2460                 return mQnsXcapSupportedAccessNetworkTypes != null
2461                         && Arrays.stream(mQnsXcapSupportedAccessNetworkTypes)
2462                                 .anyMatch(xcapAccessNetwork -> accessNetwork == xcapAccessNetwork);
2463             default:
2464                 return false;
2465         }
2466         return false;
2467     }
2468 
2469     /**
2470      * This method returns max HO Back to IWLAN count value with Fallback reason to Rove Out
2471      *
2472      * @return : int array (Ex: -1,-1 or 1,2 or 3,1 etc... )
2473      */
getQnsMaxIwlanHoCountDuringCall()2474     int getQnsMaxIwlanHoCountDuringCall() {
2475 
2476         if (mAllowMaxIwlanHoCountOnReason[0] <= 0) {
2477             mAllowMaxIwlanHoCountOnReason[0] = MAX_COUNT_INVALID;
2478         }
2479 
2480         return mAllowMaxIwlanHoCountOnReason[0];
2481     }
2482 
2483     /**
2484      * This method returns Supported Fallback reason to Rove Out from IWLAN
2485      *
2486      * @return : int array (Ex: -1,-1 or 1,2 or 3,1 etc... )
2487      */
getQnsIwlanHoRestrictReason()2488     int getQnsIwlanHoRestrictReason() {
2489         if (mAllowMaxIwlanHoCountOnReason[1] <= 0) {
2490             mAllowMaxIwlanHoCountOnReason[1] = FALLBACK_REASON_INVALID;
2491         }
2492         return mAllowMaxIwlanHoCountOnReason[1];
2493     }
2494 
2495     /**
2496      * This method returns to allow enabled Wi-Fi calling based on exceptional cellular state, even
2497      * when Wi-Fi calling is disabled.
2498      *
2499      * <p>Enable Wi-Fi calling If the call state is idle and the cellular network the UE is staying
2500      * on does not allow ims pdn.
2501      *
2502      * @return : Based on Carrier Config Settings based on operator requirement possible values:
2503      * True / False
2504      */
allowImsOverIwlanCellularLimitedCase()2505     boolean allowImsOverIwlanCellularLimitedCase() {
2506         return mIsAllowImsOverIwlanCellularLimitedCase;
2507     }
2508 
2509     /**
2510      * This method returns if Iwlan is not allowed when UE is in no WWAN coverage and the last
2511      * stored country code is outside the home country.
2512      *
2513      * @return True if need to block Iwlan, otherwise false.
2514      */
blockIwlanInInternationalRoamWithoutWwan()2515     boolean blockIwlanInInternationalRoamWithoutWwan() {
2516         return mIsBlockIwlanInInternationalRoamWithoutWwan;
2517     }
2518 
2519     /**
2520      * This method returns if IPv6 only WiFi is allowed
2521      *
2522      * @return True if need to block IPv6 only WiFi, otherwise false.
2523      */
blockIpv6OnlyWifi()2524     boolean blockIpv6OnlyWifi() {
2525         return mIsBlockIpv6OnlyWifi;
2526     }
2527 
2528     /**
2529      * This method returns the wait timer in milliseconds that VoWiFi registration in VoWiFi
2530      * activation process
2531      */
getVowifiRegistrationTimerForVowifiActivation()2532     int getVowifiRegistrationTimerForVowifiActivation() {
2533         return mVowifiRegistrationTimerForVowifiActivation;
2534     }
2535 
2536     /**
2537      * This method returns whether the IMS Registration state option is added when reporting a
2538      * qualified Wi-Fi network for network capabilities other than ims.
2539      *
2540      * @return : Based on Carrier Config Settings based on operator requirement possible values:
2541      * True / False
2542      */
getRatPreference(int netCapability)2543     int getRatPreference(int netCapability) {
2544         switch (netCapability) {
2545             case NetworkCapabilities.NET_CAPABILITY_XCAP:
2546                 return mXcapRatPreference;
2547             case NetworkCapabilities.NET_CAPABILITY_EIMS:
2548                 return mSosRatPreference;
2549             case NetworkCapabilities.NET_CAPABILITY_MMS:
2550                 return mMmsRatPreference;
2551             case NetworkCapabilities.NET_CAPABILITY_CBS:
2552                 return mCbsRatPreference;
2553         }
2554         return QnsConstants.RAT_PREFERENCE_DEFAULT;
2555     }
2556 
2557     /**
2558      * This method returns the rtt check server address config as per operator requirement
2559      *
2560      * @return Based on carrier config settings of operator. By default, to be made empty to
2561      * disable the feature.
2562      */
getWlanRttServerAddressConfig()2563     String getWlanRttServerAddressConfig() {
2564         String[] ping_address = getWlanRttPingConfigs();
2565 
2566         if (ping_address != null && ping_address[0] != null && !ping_address[0].isEmpty()) {
2567             return ping_address[0];
2568         } else {
2569             return null;
2570         }
2571     }
2572 
2573     /**
2574      * This method returns No of Pings, Intra Ping Interval, Size of the packet, RTT criteria RTT
2575      * retry timer
2576      *
2577      * @return : Based on carrier config settings as per operator requirement
2578      */
getWlanRttOtherConfigs()2579     int[] getWlanRttOtherConfigs() {
2580         int[] pingConfigs = new int[5];
2581         String[] rtt_ping_config = getWlanRttPingConfigs();
2582 
2583         if (rtt_ping_config != null && !rtt_ping_config[0].isEmpty()) {
2584             for (int i = 1; i < 6; i++) {
2585                 if (rtt_ping_config[i] != null) {
2586                     pingConfigs[i - 1] = Integer.parseInt(rtt_ping_config[i]);
2587                 }
2588             }
2589         }
2590         return pingConfigs;
2591     }
2592 
2593     /**
2594      * This method returns fallback Hysteresis timer on RTT Failure.
2595      *
2596      * @return : Based on carrier config settings as per operator requirement
2597      */
getWlanRttFallbackHystTimer()2598     int getWlanRttFallbackHystTimer() {
2599         String[] rtt_hyst_fallback_timer = getWlanRttPingConfigs();
2600 
2601         if (rtt_hyst_fallback_timer != null
2602                 && !rtt_hyst_fallback_timer[0].isEmpty()
2603                 && rtt_hyst_fallback_timer[6] != null) {
2604             return Integer.parseInt(rtt_hyst_fallback_timer[6]);
2605         } else {
2606             return 0;
2607         }
2608     }
2609 
getWlanRttPingConfigs()2610     private String[] getWlanRttPingConfigs() {
2611         if (mWlanRttBackhaulCheckConfigsOnPing == null) return null;
2612 
2613         return mWlanRttBackhaulCheckConfigsOnPing.split(",");
2614     }
2615 
2616     /**
2617      * If fallback for Initial connection failure for the network capability is met is supported ,
2618      * this method provides information about the failure retry count or retry timer or both if
2619      * supported until fallback to other transport.
2620      *
2621      * @param netCapability : (ims,sos,mms,xcap,cbs)
2622      * @return :
2623      * <NetworkCapability_SupportForFallback>:<retry_count>:<retry_timer>:<max_fallback_count>
2624      */
getInitialDataConnectionFallbackConfig(int netCapability)2625     int[] getInitialDataConnectionFallbackConfig(int netCapability) {
2626 
2627         int[] fallbackConfigOnDataFail = new int[4];
2628         String[] fallback_config = getFallbackConfigForNetCapability(netCapability);
2629 
2630         if (fallback_config != null
2631                 && fallback_config[0] != null
2632                 && fallback_config[0].length() > 0) {
2633             // netCapability Availability Status
2634             fallbackConfigOnDataFail[0] = 1;
2635 
2636             // Retry Count :  && fallback_config[1].length() > 0
2637             if (fallback_config.length > 1
2638                     && fallback_config[1] != null
2639                     && !fallback_config[1].isEmpty()) {
2640                 fallbackConfigOnDataFail[1] = Integer.parseInt(fallback_config[1]);
2641             }
2642 
2643             // Retry timer
2644             if (fallback_config.length > 2
2645                     && fallback_config[2] != null
2646                     && !fallback_config[2].isEmpty()) {
2647                 fallbackConfigOnDataFail[2] = Integer.parseInt(fallback_config[2]);
2648             }
2649 
2650             // Max fallback count
2651             if (fallback_config.length > 4
2652                     && fallback_config[4] != null
2653                     && !fallback_config[4].isEmpty()) {
2654                 fallbackConfigOnDataFail[3] = Integer.parseInt(fallback_config[4]);
2655             }
2656         }
2657         return fallbackConfigOnDataFail;
2658     }
2659 
2660     /**
2661      * This method returns the fall back timer to be starting the restriction , for no. of retries
2662      * when met with the pdn fail fallback causes
2663      *
2664      * @param netCapability : (ims,sos,mms,xcap,cbs)
2665      * @return : Fallback Guard timer to be set on starting the fallback restrict @ RestrictManager
2666      */
getFallbackGuardTimerOnInitialConnectionFail(int netCapability)2667     int getFallbackGuardTimerOnInitialConnectionFail(int netCapability) {
2668         String[] fallback_guard_timer = getFallbackConfigForNetCapability(netCapability);
2669 
2670         if (fallback_guard_timer != null
2671                 && fallback_guard_timer[0] != null
2672                 && fallback_guard_timer[0].length() > 0
2673                 && ((fallback_guard_timer.length > 1
2674                                 && fallback_guard_timer[1] != null
2675                                 && !fallback_guard_timer[1].isEmpty())
2676                         || (fallback_guard_timer.length > 2
2677                                 && fallback_guard_timer[2] != null
2678                                 && !fallback_guard_timer[2].isEmpty()))
2679                 && (fallback_guard_timer.length > 3
2680                         && fallback_guard_timer[3] != null
2681                         && !fallback_guard_timer[3].isEmpty())) {
2682             return Integer.parseInt(fallback_guard_timer[3]);
2683         } else {
2684             return 0;
2685         }
2686     }
2687 
2688     /**
2689      * To support find the right Initial Pdn connection failure fallback config based on network
2690      * capability
2691      */
getFallbackConfigForNetCapability(int netCapability)2692     private String[] getFallbackConfigForNetCapability(int netCapability) {
2693         if (mFallbackOnInitialConnectionFailure != null
2694                 && mFallbackOnInitialConnectionFailure.length > 0) {
2695             String netCapabilityName = QnsUtils.getNameOfNetCapability(netCapability);
2696             for (String config : mFallbackOnInitialConnectionFailure) {
2697                 Log.d(mLogTag, "Fallback On Initial Failure enabled for " + config);
2698                 if (config.contains(netCapabilityName)) {
2699                     return config.split(":");
2700                 }
2701             }
2702         }
2703         return null;
2704     }
2705 
2706     /**
2707      * Get the Sip Dialog Session policy when the Sip Dialog State is active. This Sip Dialog
2708      * Session policy is applied when there is no calling in the subscription, and when the device
2709      * is in a calling state, the calling policy is used first.
2710      *
2711      * @return 0: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_NONE} not Applied. The default value
2712      * for this key. 1: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_FOLLOW_VOICE_CALL} apply voice
2713      * call policy. 2: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_FOLLOW_VIDEO_CALL}  apply video
2714      * call policy.
2715      */
getSipDialogSessionPolicy()2716     @QnsConstants.QnsSipDialogSessionPolicy int getSipDialogSessionPolicy() {
2717         return mSipDialogSessionPolicy;
2718     }
2719 
2720     static class QnsConfigArray {
2721 
2722         /*
2723          * static invalid
2724          */
2725         static final int INVALID = 0x0000FFFF;
2726         /*
2727          * Thresholds, A signal value of good strength to enter.
2728          */
2729         int mGood = INVALID;
2730         /*
2731          * Thresholds, A signal value of bad strength to leave.
2732          */
2733         int mBad = INVALID;
2734         /*
2735          * Thresholds, A signal value of worst strength to enter.
2736          * The worst strength is only applicable for cellular.
2737          */
2738         int mWorst = INVALID;
2739 
QnsConfigArray(int good, int bad, int worst)2740         QnsConfigArray(int good, int bad, int worst) {
2741             set(good, bad, worst);
2742         }
2743 
QnsConfigArray(int good, int bad)2744         QnsConfigArray(int good, int bad) {
2745             set(good, bad, INVALID);
2746         }
2747 
set(int good, int bad, int worst)2748         void set(int good, int bad, int worst) {
2749             mGood = good;
2750             mBad = bad;
2751             mWorst = worst;
2752         }
2753 
2754         @Override
toString()2755         public String toString() {
2756             return "QnsConfigArray{"
2757                     + "Good="
2758                     + mGood
2759                     + ", Bad="
2760                     + mBad
2761                     + ", Worst="
2762                     + mWorst
2763                     + '}';
2764         }
2765     }
2766 
2767     @VisibleForTesting
2768     static class RtpMetricsConfig {
2769         /** Maximum jitter */
2770         final int mJitter;
2771 
2772         /** RTP packet loss rate in percentage */
2773         final int mPktLossRate;
2774 
2775         /** Time interval(milliseconds) of RTP packet loss rate */
2776         final int mPktLossTime;
2777 
2778         /** No RTP interval in milliseconds */
2779         final int mNoRtpInterval;
2780 
RtpMetricsConfig(int jitter, int pktLossRate, int pktLossTime, int noRtpInterval)2781         RtpMetricsConfig(int jitter, int pktLossRate, int pktLossTime, int noRtpInterval) {
2782             this.mJitter = jitter;
2783             this.mPktLossRate = pktLossRate;
2784             this.mPktLossTime = pktLossTime;
2785             this.mNoRtpInterval = noRtpInterval;
2786         }
2787 
2788         @Override
toString()2789         public String toString() {
2790             return "RtpMetricsConfig{"
2791                     + "mJitter="
2792                     + mJitter
2793                     + ", mPktLossRate="
2794                     + mPktLossRate
2795                     + ", mPktLossTime="
2796                     + mPktLossTime
2797                     + ", mNoRtpInterval="
2798                     + mNoRtpInterval
2799                     + '}';
2800         }
2801     }
2802 
2803     @VisibleForTesting
getQnsCarrierAnspSupportConfig()2804     QnsCarrierAnspSupportConfig getQnsCarrierAnspSupportConfig() {
2805         return mAnspConfigMgr;
2806     }
2807 }
2808