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.HashMap;
66 import java.util.HashSet;
67 import java.util.List;
68 import java.util.Locale;
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     static HashMap<Integer, String> sAccessNetworkMap =
686             new HashMap<>() {
687                 {
688                     put(AccessNetworkConstants.AccessNetworkType.EUTRAN, "eutran");
689                     put(AccessNetworkConstants.AccessNetworkType.UTRAN, "utran");
690                     put(AccessNetworkConstants.AccessNetworkType.NGRAN, "ngran");
691                     put(AccessNetworkConstants.AccessNetworkType.GERAN, "geran");
692                     put(AccessNetworkConstants.AccessNetworkType.IWLAN, "wifi");
693                 }
694             };
695 
696     static HashMap<Integer, String> sMeasTypeMap =
697             new HashMap<>() {
698                 {
699                     put(SIGNAL_MEASUREMENT_TYPE_RSRP, "rsrp");
700                     put(SIGNAL_MEASUREMENT_TYPE_RSRQ, "rsrq");
701                     put(SIGNAL_MEASUREMENT_TYPE_RSSNR, "rssnr");
702                     put(SIGNAL_MEASUREMENT_TYPE_SSRSRP, "ssrsrp");
703                     put(SIGNAL_MEASUREMENT_TYPE_SSRSRQ, "ssrsrq");
704                     put(SIGNAL_MEASUREMENT_TYPE_SSSINR, "sssinr");
705                     put(SIGNAL_MEASUREMENT_TYPE_RSCP, "rscp");
706                     put(SIGNAL_MEASUREMENT_TYPE_RSSI, "rssi");
707                     put(SIGNAL_MEASUREMENT_TYPE_ECNO, "ecno");
708                 }
709             };
710 
711     static HashMap<Integer, String> sCallTypeMap =
712             new HashMap<>() {
713                 {
714                     put(QnsConstants.CALL_TYPE_IDLE, "idle");
715                     put(QnsConstants.CALL_TYPE_VOICE, "voice");
716                     put(QnsConstants.CALL_TYPE_VIDEO, "video");
717                 }
718             };
719 
720     private final String mLogTag;
721     private final int mSlotIndex;
722     private final Context mContext;
723     private boolean mIsConfigLoaded = false;
724     protected int mSubId;
725     protected int mCurrCarrierId;
726     private final QnsEventDispatcher mQnsEventDispatcher;
727     private final QnsCarrierAnspSupportConfig mAnspConfigMgr;
728     @VisibleForTesting final Handler mHandler;
729 
730     private boolean mIsWfcInAirplaneModeOnSupport;
731     private boolean mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported;
732     private boolean mIsHoGuardOnPreferenceSupport;
733     private boolean mIsServiceBarringCheckSupport;
734     private boolean mIsVideoOverIWLANWithCellularCheckSupport;
735     private boolean mIsRoveOutWifiBadGuardTimerConditionsSupported;
736     private boolean mIsAllowImsOverIwlanCellularLimitedCase;
737     private boolean mIsBlockIwlanInInternationalRoamWithoutWwan;
738     private boolean mIsBlockIpv6OnlyWifi;
739     private boolean mIsVolteRoamingSupported;
740     private final boolean[] mAnspSupportConfigArray = new boolean[3];
741 
742     private int mWifiThresBackHaulTimer;
743     private int mCellularThresBackHaulTimer;
744     private int mQnsImsTransportType;
745     private int mQnsSosTransportType;
746     private int mQnsMmsTransportType;
747     private int[] mQnsXcapSupportedAccessNetworkTypes;
748     private int mQnsCbsTransportType;
749     private int mXcapRatPreference;
750     private int mSosRatPreference;
751     private int mMmsRatPreference;
752     private int mCbsRatPreference;
753     private int mNetworkEnableHysteresisTimer;
754     private int mMinimumHandoverGuardingTimer;
755     private int mVowifiRegistrationTimerForVowifiActivation;
756     private int mSipDialogSessionPolicy;
757 
758     private int[] mWwanHysteresisTimer;
759     private int[] mWlanHysteresisTimer;
760     private int[] mNonImsWwanHysteresisTimer;
761     private int[] mNonImsWlanHysteresisTimer;
762     private int[] mRTPMetricsData = new int[4];
763     private int[] mWaitingTimerForPreferredTransport;
764     private int[] mAllowMaxIwlanHoCountOnReason;
765     private int[] mHoRestrictTimeOnRtpQuality;
766     private int[] mIsMmtelCapabilityRequired;
767     private int[] mIsWfcPreferredTransportRequired;
768 
769     private String mWlanRttBackhaulCheckConfigsOnPing;
770     private String[] mImsAllowedRats;
771     private String[] mRoveInGuardTimerConditionThresholdGaps;
772     private String[] mFallbackOnInitialConnectionFailure;
773     private String[] mAccessNetworkMeasurementHysteresisDb;
774 
775     @NonNull
776     private final List<FallbackRule> mFallbackWwanRuleWithImsUnregistered = new ArrayList<>();
777 
778     @NonNull
779     private final List<FallbackRule> mFallbackWwanRuleWithImsHoRegisterFail = new ArrayList<>();
780 
781     /** Rules for handover between IWLAN and cellular network. */
782     @NonNull private List<HandoverRule> mHandoverRuleList = new ArrayList<>();
783 
784     protected QnsRegistrantList mQnsCarrierConfigLoadedRegistrants = new QnsRegistrantList();
785     protected QnsRegistrantList mQnsCarrierConfigChangedRegistrants = new QnsRegistrantList();
786 
787     protected QnsProvisioningListener.QnsProvisioningInfo mQnsProvisioningInfo =
788             new QnsProvisioningListener.QnsProvisioningInfo();
789 
setQnsProvisioningInfo(QnsProvisioningListener.QnsProvisioningInfo info)790     void setQnsProvisioningInfo(QnsProvisioningListener.QnsProvisioningInfo info) {
791         mQnsProvisioningInfo = info;
792     }
793 
applyProvisioningInfo( QnsConfigArray thresholds, int accessNetwork, int measurementType, int callType)794     private QnsConfigArray applyProvisioningInfo(
795             QnsConfigArray thresholds, int accessNetwork, int measurementType, int callType) {
796 
797         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_1)
798                 && thresholds.mBad != QnsConfigArray.INVALID
799                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN
800                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) {
801             int bad = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_1);
802             Log.d(mLogTag, "provisioning bad THLTE1 old:" + thresholds.mBad + " new:" + bad);
803             thresholds.mBad = bad;
804         }
805         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_2)
806                 && thresholds.mWorst != QnsConfigArray.INVALID
807                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN
808                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) {
809             int worst =
810                     mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_2);
811             Log.d(mLogTag, "provisioning worst THLTE2 old:" + thresholds.mWorst + " new:" + worst);
812             thresholds.mWorst = worst;
813         }
814         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_3)
815                 && thresholds.mGood != QnsConfigArray.INVALID
816                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN
817                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) {
818             int good = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_3);
819             Log.d(mLogTag, "provisioning good THLTE3 old:" + thresholds.mGood + " new:" + good);
820             thresholds.mGood = good;
821         }
822         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_THRESHOLD_A)
823                 && thresholds.mGood != QnsConfigArray.INVALID
824                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN
825                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSSI) {
826             int good =
827                     mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_THRESHOLD_A);
828             Log.d(mLogTag, "provisioning good VOWT_A old:" + thresholds.mGood + " new:" + good);
829             thresholds.mGood = good;
830         }
831         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_THRESHOLD_B)
832                 && thresholds.mBad != QnsConfigArray.INVALID
833                 && accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN
834                 && measurementType == SIGNAL_MEASUREMENT_TYPE_RSSI) {
835             int bad = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_THRESHOLD_B);
836             Log.d(mLogTag, "provisioning bad VOWT_B old:" + thresholds.mBad + " new:" + bad);
837             thresholds.mBad = bad;
838             // TODO : make video threshold gap config, and move in getThreshold...()
839             if (getCarrierId() == 1839 && callType == QnsConstants.CALL_TYPE_VIDEO) {
840                 thresholds.mBad = bad + 5;
841             }
842         }
843 
844         return thresholds;
845     }
846 
847     static class FallbackRule {
848         /** Key : IMS registration fail reason, value : fallback time in millis */
849         final Set<Integer> mReasons;
850 
851         final int mBackoffTimeMillis;
852         final int mPreferenceMode;
853 
FallbackRule(Set<Integer> reasons, int backoffTimeMillis, int preferenceMode)854         FallbackRule(Set<Integer> reasons, int backoffTimeMillis, int preferenceMode) {
855             mReasons = reasons;
856             mBackoffTimeMillis = backoffTimeMillis;
857             mPreferenceMode = preferenceMode;
858         }
859 
getFallBackTime(int reason)860         int getFallBackTime(int reason) {
861             if (mReasons.contains(reason)) {
862                 return mBackoffTimeMillis;
863             } else {
864                 return 0;
865             }
866         }
867 
868         @Override
toString()869         public String toString() {
870             StringBuilder builder = new StringBuilder();
871             builder.append("FallbackRule time:").append(mBackoffTimeMillis);
872             if (mPreferenceMode == -1) {
873                 builder.append(" ");
874             } else if (mPreferenceMode == QnsConstants.CELL_PREF) {
875                 builder.append(" " + "CELL_PREF_MODE");
876             } else if (mPreferenceMode == QnsConstants.WIFI_PREF) {
877                 builder.append(" " + "WIFI_PREF_MODE");
878             }
879             builder.append(" reasons:");
880             for (Integer i : mReasons) {
881                 builder.append(i).append(" ");
882             }
883             return builder.toString();
884         }
885     }
886 
887     static class HandoverRule {
888         @Retention(RetentionPolicy.SOURCE)
889         @IntDef(
890                 prefix = {"RULE_TYPE_"},
891                 value = {
892                     RULE_TYPE_ALLOWED,
893                     RULE_TYPE_DISALLOWED,
894                 })
895         @interface HandoverRuleType {}
896 
897         /** Indicating this rule is for allowing handover. */
898         static final int RULE_TYPE_ALLOWED = 1;
899 
900         /** Indicating this rule is for disallowing handover. */
901         static final int RULE_TYPE_DISALLOWED = 2;
902 
903         private static final String RULE_TAG_SOURCE_ACCESS_NETWORKS = "source";
904 
905         private static final String RULE_TAG_TARGET_ACCESS_NETWORKS = "target";
906 
907         private static final String RULE_TAG_TYPE = "type";
908 
909         private static final String RULE_TAG_CAPABILITIES = "capabilities";
910 
911         private static final String RULE_TAG_ROAMING = "roaming";
912 
913         /** Handover rule type. */
914         @HandoverRuleType final int mHandoverRuleType;
915 
916         /** The applicable source access networks for handover. */
917         @NonNull @AccessNetworkConstants.RadioAccessNetworkType
918         final Set<Integer> mSourceAccessNetworks;
919 
920         /** The applicable target access networks for handover. */
921         @NonNull @AccessNetworkConstants.RadioAccessNetworkType
922         final Set<Integer> mTargetAccessNetworks;
923 
924         /**
925          * The network capabilities to any of which this handover rule applies. If is empty, then
926          * capability is ignored as a rule matcher.
927          */
928         @NonNull @NetCapability final Set<Integer> mNetworkCapabilities;
929 
930         /** {@code true} indicates this policy is only applicable when the device is roaming. */
931         final boolean mIsOnlyForRoaming;
932 
933         /**
934          * Constructor
935          *
936          * @param ruleString The rule in string format.
937          * @see CarrierConfigManager#KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY
938          */
HandoverRule(@onNull String ruleString)939         HandoverRule(@NonNull String ruleString) {
940             if (TextUtils.isEmpty(ruleString)) {
941                 throw new IllegalArgumentException("illegal rule " + ruleString);
942             }
943 
944             Set<Integer> source = null, target = null, capabilities = Collections.emptySet();
945             int type = 0;
946             boolean roaming = false;
947 
948             ruleString = ruleString.trim().toLowerCase(Locale.ROOT);
949             String[] expressions = ruleString.split("\\s*,\\s*");
950             for (String expression : expressions) {
951                 String[] tokens = expression.trim().split("\\s*=\\s*");
952                 if (tokens.length != 2) {
953                     throw new IllegalArgumentException(
954                             "illegal rule " + ruleString + ", tokens=" + Arrays.toString(tokens));
955                 }
956                 String key = tokens[0].trim();
957                 String value = tokens[1].trim();
958                 try {
959                     switch (key) {
960                         case RULE_TAG_SOURCE_ACCESS_NETWORKS:
961                             source =
962                                     Arrays.stream(value.split("\\s*\\|\\s*"))
963                                             .map(String::trim)
964                                             .map(QnsConstants::accessNetworkTypeFromString)
965                                             .collect(Collectors.toSet());
966                             break;
967                         case RULE_TAG_TARGET_ACCESS_NETWORKS:
968                             target =
969                                     Arrays.stream(value.split("\\s*\\|\\s*"))
970                                             .map(String::trim)
971                                             .map(QnsConstants::accessNetworkTypeFromString)
972                                             .collect(Collectors.toSet());
973                             break;
974                         case RULE_TAG_TYPE:
975                             if (value.toLowerCase(Locale.ROOT).equals("allowed")) {
976                                 type = RULE_TYPE_ALLOWED;
977                             } else if (value.toLowerCase(Locale.ROOT).equals("disallowed")) {
978                                 type = RULE_TYPE_DISALLOWED;
979                             } else {
980                                 throw new IllegalArgumentException("unexpected rule type " + value);
981                             }
982                             break;
983                         case RULE_TAG_CAPABILITIES:
984                             capabilities = QnsUtils.getNetworkCapabilitiesFromString(value);
985                             break;
986                         case RULE_TAG_ROAMING:
987                             roaming = Boolean.parseBoolean(value);
988                             break;
989                         default:
990                             throw new IllegalArgumentException("unexpected key " + key);
991                     }
992                 } catch (Exception e) {
993                     e.printStackTrace();
994                     throw new IllegalArgumentException(
995                             "illegal rule \"" + ruleString + "\", e=" + e);
996                 }
997             }
998 
999             if (source == null || target == null || source.isEmpty() || target.isEmpty()) {
1000                 throw new IllegalArgumentException(
1001                         "Need to specify both source and target. " + "\"" + ruleString + "\"");
1002             }
1003 
1004             if (source.contains(AccessNetworkConstants.AccessNetworkType.UNKNOWN)
1005                     && type != RULE_TYPE_DISALLOWED) {
1006                 throw new IllegalArgumentException("Unknown access network can be only specified in"
1007                         + " the disallowed rule. \"" + ruleString + "\"");
1008             }
1009 
1010             if (target.contains(AccessNetworkConstants.AccessNetworkType.UNKNOWN)) {
1011                 throw new IllegalArgumentException(
1012                         "Target access networks contains unknown. " + "\"" + ruleString + "\"");
1013             }
1014 
1015             if (type == 0) {
1016                 throw new IllegalArgumentException(
1017                         "Rule type is not specified correctly. " + "\"" + ruleString + "\"");
1018             }
1019 
1020             if (capabilities != null && capabilities.contains(-1)) {
1021                 throw new IllegalArgumentException(
1022                         "Network capabilities contains unknown. " + "\"" + ruleString + "\"");
1023             }
1024 
1025             if (!source.contains(AccessNetworkConstants.AccessNetworkType.IWLAN)
1026                     && !target.contains(AccessNetworkConstants.AccessNetworkType.IWLAN)) {
1027                 throw new IllegalArgumentException(
1028                         "IWLAN must be specified in either source or "
1029                                 + "target access networks.\""
1030                                 + ruleString
1031                                 + "\"");
1032             }
1033 
1034             mSourceAccessNetworks = source;
1035             mTargetAccessNetworks = target;
1036             this.mHandoverRuleType = type;
1037             mNetworkCapabilities = capabilities;
1038             mIsOnlyForRoaming = roaming;
1039         }
1040 
1041         @Override
toString()1042         public String toString() {
1043             return "[HandoverRule: type="
1044                     + (mHandoverRuleType == RULE_TYPE_ALLOWED ? "allowed" : "disallowed")
1045                     + ", source="
1046                     + mSourceAccessNetworks.stream()
1047                             .map(QnsConstants::accessNetworkTypeToString)
1048                             .collect(Collectors.joining("|"))
1049                     + ", target="
1050                     + mTargetAccessNetworks.stream()
1051                             .map(QnsConstants::accessNetworkTypeToString)
1052                             .collect(Collectors.joining("|"))
1053                     + ", isRoaming="
1054                     + mIsOnlyForRoaming
1055                     + ", capabilities="
1056                     + QnsUtils.networkCapabilitiesToString(mNetworkCapabilities)
1057                     + "]";
1058         }
1059     }
1060 
1061     private class QnsCarrierConfigChangeHandler extends Handler {
QnsCarrierConfigChangeHandler(Looper looper)1062         QnsCarrierConfigChangeHandler(Looper looper) {
1063             super(looper);
1064         }
1065 
1066         @Override
handleMessage(Message message)1067         public void handleMessage(Message message) {
1068             switch (message.what) {
1069                 case QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED:
1070                     Log.d(mLogTag, "Event received QNS_EVENT_CARRIER_CONFIG_CHANGED");
1071                     if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1072                         int newCarrierID = getCarrierId();
1073                         Log.d(
1074                                 mLogTag,
1075                                 "Carrier Id: current=" + mCurrCarrierId + ", new=" + newCarrierID);
1076                         if (newCarrierID != 0 && newCarrierID != UNKNOWN_CARRIER_ID) {
1077                             if (mCurrCarrierId != newCarrierID) {
1078                                 mCurrCarrierId = newCarrierID;
1079                                 loadQnsConfigurations();
1080                                 mIsConfigLoaded = true;
1081                                 notifyLoadQnsConfigurationsCompleted();
1082                             } else {
1083                                 if (isQnsConfigChanged()) {
1084                                     Log.d(mLogTag, "Qns Carrier config updated found");
1085                                     notifyQnsConfigurationsChanged();
1086                                 }
1087                             }
1088                         }
1089                     }
1090                     break;
1091                 default:
1092                     break;
1093             }
1094         }
1095     }
1096 
1097     /**
1098      * Constructor to Initial Slot and Context whose carrier config ID needs to be loaded along with
1099      * initialising the Action Intent on which Carrier Config ID to be loaded.
1100      */
QnsCarrierConfigManager(Context context, QnsEventDispatcher dispatcher, int slotIndex)1101     QnsCarrierConfigManager(Context context, QnsEventDispatcher dispatcher, int slotIndex) {
1102         mSlotIndex = slotIndex;
1103         mContext = context;
1104         mLogTag =
1105                 QnsConstants.QNS_TAG
1106                         + "_"
1107                         + QnsCarrierConfigManager.class.getSimpleName()
1108                         + "_"
1109                         + mSlotIndex;
1110         mQnsEventDispatcher = dispatcher;
1111         mAnspConfigMgr = new QnsCarrierAnspSupportConfig(slotIndex);
1112 
1113         HandlerThread handlerThread = new HandlerThread(mLogTag);
1114         handlerThread.start();
1115         mHandler =
1116                 new QnsCarrierConfigManager.QnsCarrierConfigChangeHandler(
1117                         handlerThread.getLooper());
1118 
1119         List<Integer> events = new ArrayList<>();
1120         events.add(QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED);
1121         mQnsEventDispatcher.registerEvent(events, mHandler);
1122 
1123         // sending empty message when new object created; as actual event will not be received in
1124         // case QNS restarts.
1125         // This EVENT will not be processed in bootup case since carrier id will be invalid until
1126         // actual event received from QnsEventDispatcher.
1127         mHandler.sendEmptyMessage(QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED);
1128 
1129         // To do : Update based on xml version Changes handling
1130         // To do : Operator Update on Threshold changes handling
1131     }
1132 
1133     /** Below API clears the current Access Network selection Policies */
close()1134     void close() {
1135         if (mHandler != null) mQnsEventDispatcher.unregisterEvent(mHandler);
1136     }
1137 
readFromCarrierConfigManager(Context context)1138     synchronized PersistableBundle readFromCarrierConfigManager(Context context) {
1139         PersistableBundle carrierConfigBundle;
1140         CarrierConfigManager carrierConfigManager =
1141                 context.getSystemService(CarrierConfigManager.class);
1142 
1143         if (carrierConfigManager == null) {
1144             throw new IllegalStateException("Carrier config manager is null.");
1145         }
1146         carrierConfigBundle = carrierConfigManager.getConfigForSubId(getSubId());
1147 
1148         return carrierConfigBundle;
1149     }
1150 
readFromAssets(Context context)1151     synchronized PersistableBundle readFromAssets(Context context) {
1152         PersistableBundle assetBundle;
1153 
1154         assetBundle = QnsUtils.readQnsDefaultConfigFromAssets(context, mCurrCarrierId);
1155 
1156         if (assetBundle == null) {
1157             throw new IllegalStateException("Carrier config manager is null.");
1158         }
1159 
1160         return assetBundle;
1161     }
1162 
1163     /** Below API is used for Loading the carrier configurations based on Current Carrier ID */
loadQnsConfigurations()1164     void loadQnsConfigurations() {
1165 
1166         PersistableBundle carrierConfigBundle = readFromCarrierConfigManager(mContext);
1167         Log.d(mLogTag, "CarrierConfig Bundle for Slot: " + mSlotIndex + carrierConfigBundle);
1168 
1169         PersistableBundle assetConfigBundle = readFromAssets(mContext);
1170         Log.d(mLogTag, "AssetConfig Bundle for Slot: " + mSlotIndex + assetConfigBundle);
1171 
1172         // load configurations supporting ANE
1173         loadQnsAneSupportConfigurations(carrierConfigBundle, assetConfigBundle);
1174 
1175         // load qns Ansp (Access Network Selection Policy) carrier Support Configurations
1176         // for building Internal ANSP Policies
1177         loadAnspCarrierSupportConfigs(carrierConfigBundle, assetConfigBundle);
1178 
1179         mAnspConfigMgr.loadQnsAnspSupportArray(carrierConfigBundle, assetConfigBundle);
1180 
1181         // Load configs using Carrier Config Manager Keys
1182         loadDirectFromCarrierConfigManagerKey(carrierConfigBundle);
1183 
1184         loadWfcConfigurations(carrierConfigBundle, assetConfigBundle);
1185 
1186         loadMediaThreshold(carrierConfigBundle, assetConfigBundle);
1187     }
1188 
1189     /**
1190      * Below API takes care of loading the configuration based on the carrier config Manager
1191      * available for given carrier config manager keys.
1192      */
loadDirectFromCarrierConfigManagerKey(PersistableBundle bundleCarrier)1193     void loadDirectFromCarrierConfigManagerKey(PersistableBundle bundleCarrier) {
1194         loadHandoverRules(
1195                 bundleCarrier, null, CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY);
1196         loadCarrierConfig(bundleCarrier);
1197     }
1198 
1199     /**
1200      * Below API takes care of validating the configs (Threshold & HO rules) Updates after loading
1201      * Qns configurations, for the current operator in use, in case of config update scenario
1202      *
1203      * @return : true/false
1204      */
isQnsConfigChanged()1205     synchronized boolean isQnsConfigChanged() {
1206         PersistableBundle carrierConfigBundle = readFromCarrierConfigManager(mContext);
1207         Log.d(
1208                 mLogTag,
1209                 "Check carrier config for Qns item changefor_slot: "
1210                         + mSlotIndex
1211                         + "_"
1212                         + carrierConfigBundle);
1213         PersistableBundle assetConfigBundle = readFromAssets(mContext);
1214         Log.d(
1215                 mLogTag,
1216                 "Check Asset config for Qns item changefor_slot: "
1217                         + mSlotIndex
1218                         + "_"
1219                         + assetConfigBundle);
1220 
1221         boolean isThresholdConfigChanged =
1222                 checkThresholdConfigChange(carrierConfigBundle, assetConfigBundle);
1223         boolean isHandoverRulesChanged =
1224                 checkHandoverRuleConfigChange(
1225                         carrierConfigBundle,
1226                         null,
1227                         CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY);
1228         Log.d(
1229                 mLogTag,
1230                 "Threshold config changed = "
1231                         + isThresholdConfigChanged
1232                         + ", IMS handover rule changed = "
1233                         + isHandoverRulesChanged);
1234 
1235         return (isThresholdConfigChanged || isHandoverRulesChanged);
1236     }
1237 
1238     /**
1239      * Below API takes to check if current HO rules as any difference with existing HO rules Updated
1240      * based on Event Carrier config change event received after initial loading @Param
1241      * PersistableBundle : configBundle
1242      *
1243      * @return true/false
1244      */
checkHandoverRuleConfigChange( PersistableBundle carrierConfigBundle, PersistableBundle assetConfigBundle, String key)1245     synchronized boolean checkHandoverRuleConfigChange(
1246             PersistableBundle carrierConfigBundle,
1247             PersistableBundle assetConfigBundle,
1248             String key) {
1249         List<HandoverRule> handoverUpdateRuleList =
1250                 updateHandoverRules(carrierConfigBundle, assetConfigBundle, key);
1251 
1252         Log.d(mLogTag, "New rule:" + handoverUpdateRuleList.toString());
1253         Log.d(mLogTag, "Existing rule:" + mHandoverRuleList.toString());
1254 
1255         if (mHandoverRuleList.toString().equals(handoverUpdateRuleList.toString())
1256                 || handoverUpdateRuleList.isEmpty()
1257                 || mHandoverRuleList.isEmpty()) {
1258             handoverUpdateRuleList.clear();
1259             return false;
1260         } else {
1261             mHandoverRuleList = new ArrayList<>(handoverUpdateRuleList);
1262             Log.d(mLogTag, "New rule Updated:" + mHandoverRuleList);
1263             handoverUpdateRuleList.clear();
1264             return true;
1265         }
1266     }
1267 
1268     /**
1269      * Below API takes to check if ANSP threshold configs was Updated based on Event Carrier config
1270      * change event received after initial Qns configuration loading is completed
1271      */
checkThresholdConfigChange( PersistableBundle carrierConfigBundle, PersistableBundle assetConfigBundle)1272     synchronized boolean checkThresholdConfigChange(
1273             PersistableBundle carrierConfigBundle, PersistableBundle assetConfigBundle) {
1274 
1275         return mAnspConfigMgr.checkQnsAnspConfigChange(carrierConfigBundle, assetConfigBundle);
1276     }
1277 
1278     /**
1279      * Below API takes care of loading the configuration based on the Bundle data built based on
1280      * asset folder xml file . (Except reading Key item of threshold & ANSP
1281      */
loadQnsAneSupportConfigurations( PersistableBundle bundleCarrier, PersistableBundle bundleAsset)1282     void loadQnsAneSupportConfigurations(
1283             PersistableBundle bundleCarrier, PersistableBundle bundleAsset) {
1284 
1285         mIsWfcInAirplaneModeOnSupport =
1286                 getConfig(
1287                         bundleCarrier, bundleAsset, KEY_QNS_SUPPORT_WFC_DURING_AIRPLANE_MODE_BOOL);
1288         mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported =
1289                 getConfig(
1290                         bundleCarrier,
1291                         bundleAsset,
1292                         KEY_IN_CALL_HO_DECISION_WLAN_TO_WWAN_WITHOUT_VOPS_CONDITION_BOOL);
1293         mIsHoGuardOnPreferenceSupport =
1294                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_HO_GUARDING_BY_PREFERENCE_BOOL);
1295         mIsServiceBarringCheckSupport =
1296                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_SUPPORT_SERVICE_BARRING_CHECK_BOOL);
1297         mIsVideoOverIWLANWithCellularCheckSupport =
1298                 getConfig(
1299                         bundleCarrier,
1300                         bundleAsset,
1301                         KEY_QNS_ALLOW_VIDEO_OVER_IWLAN_WITH_CELLULAR_LIMITED_CASE_BOOL);
1302         mIsRoveOutWifiBadGuardTimerConditionsSupported =
1303                 getConfig(
1304                         bundleCarrier,
1305                         bundleAsset,
1306                         KEY_QNS_ROVE_OUT_POLICY_WITH_WIFI_BAD_GUARDTIMER_CONDITIONS_BOOL);
1307         mIsAllowImsOverIwlanCellularLimitedCase =
1308                 getConfig(
1309                         bundleCarrier,
1310                         bundleAsset,
1311                         KEY_QNS_ALLOW_IMS_OVER_IWLAN_CELLULAR_LIMITED_CASE_BOOL);
1312         mIsBlockIwlanInInternationalRoamWithoutWwan =
1313                 getConfig(
1314                         bundleCarrier,
1315                         bundleAsset,
1316                         KEY_BLOCK_IWLAN_IN_INTERNATIONAL_ROAMING_WITHOUT_WWAN_BOOL);
1317         mIsBlockIpv6OnlyWifi = getConfig(bundleCarrier, bundleAsset, KEY_BLOCK_IPV6_ONLY_WIFI_BOOL);
1318 
1319         mWifiThresBackHaulTimer =
1320                 getConfig(
1321                         bundleCarrier,
1322                         bundleAsset,
1323                         KEY_QNS_WIFI_RSSI_THRESHOLDBACKHAUL_TIMER_MS_INT);
1324         mCellularThresBackHaulTimer =
1325                 getConfig(
1326                         bundleCarrier,
1327                         bundleAsset,
1328                         KEY_QNS_CELLULAR_SS_THRESHOLDBACKHAUL_TIMER_MS_INT);
1329         mQnsImsTransportType =
1330                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_IMS_TRANSPORT_TYPE_INT);
1331         mQnsSosTransportType =
1332                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_SOS_TRANSPORT_TYPE_INT);
1333         mQnsMmsTransportType =
1334                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_MMS_TRANSPORT_TYPE_INT);
1335         mQnsXcapSupportedAccessNetworkTypes =
1336                 getConfig(
1337                         bundleCarrier,
1338                         bundleAsset,
1339                         CarrierConfigManager.ImsSs.KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY);
1340         mQnsCbsTransportType =
1341                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_TRANSPORT_TYPE_INT);
1342         mQnsCbsTransportType =
1343                 getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_TRANSPORT_TYPE_INT);
1344         mXcapRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_XCAP_RAT_PREFERENCE_INT);
1345         mSosRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_SOS_RAT_PREFERENCE_INT);
1346         mMmsRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_MMS_RAT_PREFERENCE_INT);
1347         mCbsRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_RAT_PREFERENCE_INT);
1348         mNetworkEnableHysteresisTimer =
1349                 getConfig(
1350                         bundleCarrier,
1351                         bundleAsset,
1352                         KEY_QNS_IMS_NETWORK_ENABLE_HO_HYSTERESIS_TIMER_INT);
1353 
1354         mWwanHysteresisTimer =
1355                 getConfig(bundleCarrier, bundleAsset, KEY_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY);
1356         mWlanHysteresisTimer =
1357                 getConfig(bundleCarrier, bundleAsset, KEY_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY);
1358         mNonImsWwanHysteresisTimer =
1359                 getConfig(
1360                         bundleCarrier, bundleAsset, KEY_NON_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY);
1361         mNonImsWlanHysteresisTimer =
1362                 getConfig(
1363                         bundleCarrier, bundleAsset, KEY_NON_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY);
1364         mMinimumHandoverGuardingTimer =
1365                 getConfig(bundleCarrier, bundleAsset, KEY_MINIMUM_HANDOVER_GUARDING_TIMER_MS_INT);
1366         mWaitingTimerForPreferredTransport =
1367                 getConfig(
1368                         bundleCarrier,
1369                         bundleAsset,
1370                         KEY_WAITING_TIME_FOR_PREFERRED_TRANSPORT_WHEN_POWER_ON_INT_ARRAY);
1371         mAllowMaxIwlanHoCountOnReason =
1372                 getConfig(
1373                         bundleCarrier,
1374                         bundleAsset,
1375                         KEY_QNS_IN_CALL_ROVEIN_ALLOWED_COUNT_AND_FALLBACK_REASON_INT_ARRAY);
1376         mHoRestrictTimeOnRtpQuality =
1377                 getConfig(
1378                         bundleCarrier,
1379                         bundleAsset,
1380                         KEY_QNS_HO_RESTRICT_TIME_WITH_LOW_RTP_QUALITY_MILLIS_INT_ARRAY);
1381         mWlanRttBackhaulCheckConfigsOnPing =
1382                 getConfig(
1383                         bundleCarrier,
1384                         bundleAsset,
1385                         KEY_QNS_WLAN_RTT_BACKHAUL_CHECK_ON_ICMP_PING_STRING);
1386 
1387         mFallbackOnInitialConnectionFailure =
1388                 getConfig(
1389                         bundleCarrier,
1390                         bundleAsset,
1391                         KEY_QNS_FALLBACK_ON_INITIAL_CONNECTION_FAILURE_STRING_ARRAY);
1392         mImsAllowedRats =
1393                 getConfig(bundleCarrier, bundleAsset, KEY_IMS_CELLULAR_ALLOWED_RAT_STRING_ARRAY);
1394         mRoveInGuardTimerConditionThresholdGaps =
1395                 getConfig(
1396                         bundleCarrier,
1397                         bundleAsset,
1398                         KEY_QNS_ROVEIN_THRESHOLD_GAP_WITH_GUARD_TIMER_STRING_ARRAY);
1399         mSipDialogSessionPolicy =
1400                 getConfig(bundleCarrier, bundleAsset, KEY_SIP_DIALOG_SESSION_POLICY_INT);
1401         mAccessNetworkMeasurementHysteresisDb =
1402                 getConfig(
1403                         bundleCarrier,
1404                         bundleAsset,
1405                         KEY_QNS_CELLULAR_SIGNAL_STRENGTH_HYSTERESIS_DB_STRING_ARRAY);
1406 
1407         loadFallbackPolicyWithImsRegiFail(bundleCarrier, bundleAsset);
1408     }
1409 
1410     @VisibleForTesting
loadWfcConfigurations(PersistableBundle bundleCarrier, PersistableBundle bundleAsset)1411     void loadWfcConfigurations(PersistableBundle bundleCarrier, PersistableBundle bundleAsset) {
1412 
1413         mVowifiRegistrationTimerForVowifiActivation =
1414                 getConfig(
1415                         bundleCarrier,
1416                         bundleAsset,
1417                         KEY_QNS_VOWIFI_REGISTATION_TIMER_FOR_VOWIFI_ACTIVATION_INT);
1418     }
1419 
1420     @VisibleForTesting
loadFallbackPolicyWithImsRegiFail(PersistableBundle carrier, PersistableBundle asset)1421     void loadFallbackPolicyWithImsRegiFail(PersistableBundle carrier, PersistableBundle asset) {
1422         synchronized (this) {
1423             mFallbackWwanRuleWithImsUnregistered.clear();
1424             String[] fallbackRulesStrings =
1425                     getConfig(
1426                             carrier,
1427                             asset,
1428                             KEY_QNS_FALLBACK_WWAN_IMS_UNREGISTRATION_REASON_STRING_ARRAY);
1429             if (fallbackRulesStrings != null) {
1430                 Log.d(mLogTag, "loadFallbackPolicyWithImsRegiFail" + fallbackRulesStrings.length);
1431                 for (String ruleString : fallbackRulesStrings) {
1432                     Log.d(mLogTag, " ruleString1:" + ruleString);
1433                     FallbackRule rule = parseFallbackRule(ruleString);
1434                     if (rule != null) {
1435                         mFallbackWwanRuleWithImsUnregistered.add(rule);
1436                     }
1437                 }
1438             } else {
1439                 Log.d(mLogTag, "Config FallbackWwanRuleWithImsUnregistered is null");
1440             }
1441             mFallbackWwanRuleWithImsHoRegisterFail.clear();
1442             fallbackRulesStrings =
1443                     getConfig(
1444                             carrier,
1445                             asset,
1446                             KEY_QNS_FALLBACK_WWAN_IMS_HO_REGISTER_FAIL_REASON_STRING_ARRAY);
1447             if (fallbackRulesStrings != null) {
1448                 Log.d(mLogTag, "loadFallbackPolicyWithImsRegiFail2:" + fallbackRulesStrings.length);
1449                 for (String ruleString : fallbackRulesStrings) {
1450                     Log.d(mLogTag, " ruleString2:" + ruleString);
1451                     FallbackRule rule = parseFallbackRule(ruleString);
1452                     if (rule != null) {
1453                         mFallbackWwanRuleWithImsHoRegisterFail.add(rule);
1454                     }
1455                 }
1456             } else {
1457                 Log.d(mLogTag, "Config mFallbackWwanRuleWithImsHoRegisterFail is null");
1458             }
1459         }
1460     }
1461 
parseFallbackRule(String ruleString)1462     private FallbackRule parseFallbackRule(String ruleString) {
1463         if (TextUtils.isEmpty(ruleString)) {
1464             throw new IllegalArgumentException("illegal rule " + ruleString);
1465         }
1466         Set<Integer> reasons = new ArraySet<>();
1467         int time = 0;
1468         int preferenceMode = -1;
1469         ruleString = ruleString.trim().toLowerCase(Locale.ROOT);
1470         String[] expressions = ruleString.split("\\s*,\\s*");
1471         for (String expression : expressions) {
1472             String[] tokens = expression.trim().split("\\s*=\\s*");
1473             if (tokens.length != 2) {
1474                 throw new IllegalArgumentException(
1475                         "illegal rule " + ruleString + ", tokens=" + Arrays.toString(tokens));
1476             }
1477             String key = tokens[0].trim();
1478             String value = tokens[1].trim();
1479 
1480             try {
1481                 switch (key) {
1482                     case "cause":
1483                         String[] cause = value.trim().split("\\s*\\|\\s*");
1484                         for (String c : cause) {
1485                             if (!c.contains("~")) {
1486                                 reasons.add(Integer.parseInt(c));
1487                             } else {
1488                                 String[] tok = c.trim().split("\\s*~\\s*");
1489                                 int start = Integer.parseInt(tok[0]);
1490                                 int end = Integer.parseInt(tok[1]);
1491                                 for (int i = start; i <= end; i++) {
1492                                     reasons.add(i);
1493                                 }
1494                             }
1495                         }
1496                         break;
1497                     case "time":
1498                         time = Integer.parseInt(value);
1499                         break;
1500                     case "preference":
1501                         if (value.equals("cell")) {
1502                             preferenceMode = QnsConstants.CELL_PREF;
1503                         } else if (value.equals("wifi")) {
1504                             preferenceMode = QnsConstants.WIFI_PREF;
1505                         }
1506                         break;
1507 
1508                     default:
1509                         throw new IllegalArgumentException("unexpected key " + key);
1510                 }
1511 
1512             } catch (Exception e) {
1513                 e.printStackTrace();
1514                 throw new IllegalArgumentException("illegal rule \"" + ruleString + "\", e=" + e);
1515             }
1516         }
1517         if (reasons.size() > 0) {
1518             return new FallbackRule(reasons, time, preferenceMode);
1519         } else {
1520             return null;
1521         }
1522     }
1523 
getConfig( PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String configKey)1524     private synchronized <T> T getConfig(
1525             PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String configKey) {
1526         return QnsUtils.getConfig(bundleCarrier, bundleAsset, configKey);
1527     }
1528 
1529     /** Load handover rules from carrier config. */
1530     @VisibleForTesting
loadHandoverRules( PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key)1531     void loadHandoverRules(
1532             PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key) {
1533         synchronized (this) {
1534             mHandoverRuleList.clear();
1535             String[] handoverRulesStrings = getConfig(bundleCarrier, bundleAsset, key);
1536             if (handoverRulesStrings != null) {
1537                 for (String ruleString : handoverRulesStrings) {
1538                     Log.d(mLogTag, "loadHandoverRules: " + ruleString);
1539                     try {
1540                         mHandoverRuleList.add(new HandoverRule(ruleString));
1541                     } catch (IllegalArgumentException e) {
1542                         Log.d(mLogTag, "loadHandoverRules: " + e.getMessage());
1543                     }
1544                 }
1545             }
1546         }
1547     }
1548 
loadMediaThreshold(PersistableBundle bundleCarrier, PersistableBundle assetConfigBundle)1549     void loadMediaThreshold(PersistableBundle bundleCarrier, PersistableBundle assetConfigBundle) {
1550         //read Jitter
1551         mRTPMetricsData[0] = getConfig(
1552                 bundleCarrier, null,
1553                 CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_JITTER_THRESHOLD_MILLIS_INT);
1554         //read Packet Loss Rate
1555         mRTPMetricsData[1] = getConfig(
1556                 bundleCarrier, null,
1557                 CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT);
1558         //read Inactivity Time
1559         long inactivityTime = getConfig(
1560                 bundleCarrier, null,
1561                 CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG);
1562         mRTPMetricsData[3] = (int) inactivityTime;
1563         //read Packet Loss Duration
1564         mRTPMetricsData[2] = getConfig(
1565                 bundleCarrier, assetConfigBundle,
1566                 KEY_QNS_MEDIA_THRESHOLD_RTP_PACKET_LOSS_TIME_MILLIS_INT);
1567     }
1568 
1569     /** Updated handover rules from carrier config. */
1570     @VisibleForTesting
updateHandoverRules( PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key)1571     List<HandoverRule> updateHandoverRules(
1572             PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key) {
1573         List<HandoverRule> readNewHandoverRuleList = new ArrayList<>();
1574         synchronized (this) {
1575             String[] handoverRulesStrings = getConfig(bundleCarrier, bundleAsset, key);
1576             if (handoverRulesStrings != null) {
1577                 for (String ruleString : handoverRulesStrings) {
1578                     Log.d(mLogTag, "UpdateHandoverRules: " + ruleString);
1579                     try {
1580                         Log.d(mLogTag, "Rule Updated");
1581                         readNewHandoverRuleList.add(new HandoverRule(ruleString));
1582                     } catch (IllegalArgumentException e) {
1583                         Log.d(mLogTag, "UpdateHandoverRules: " + e.getMessage());
1584                     }
1585                 }
1586             }
1587         }
1588         return readNewHandoverRuleList;
1589     }
1590 
1591     /** Load carrier config. */
1592     @VisibleForTesting
loadCarrierConfig(PersistableBundle bundleCarrier)1593     void loadCarrierConfig(PersistableBundle bundleCarrier) {
1594         mIsMmtelCapabilityRequired =
1595                 getConfig(
1596                         bundleCarrier,
1597                         null,
1598                         CarrierConfigManager.Ims.KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY);
1599         mIsVolteRoamingSupported =
1600                 getConfig(
1601                         bundleCarrier,
1602                         null,
1603                         CarrierConfigManager.ImsVoice.KEY_CARRIER_VOLTE_ROAMING_AVAILABLE_BOOL);
1604     }
1605 
1606     /**
1607      * To read the current Carrier ID based on the Slot ID and Context info
1608      *
1609      * @return : Current Carrier ID
1610      */
getCarrierId()1611     int getCarrierId() {
1612         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1613         if (tm != null) {
1614             tm = tm.createForSubscriptionId(QnsUtils.getSubId(mContext, mSlotIndex));
1615             return tm.getSimCarrierId();
1616         }
1617         return 0;
1618     }
1619 
1620     /**
1621      * To read the current Subscription ID based on the Slot ID and Context info Output : Current
1622      * Carrier ID
1623      */
getSubId()1624     int getSubId() {
1625         mSubId = QnsUtils.getSubId(mContext, mSlotIndex);
1626         return mSubId;
1627     }
1628 
1629     /** Notify all the registrants of the Slot loaded after carrier config loading is Completed */
notifyLoadQnsConfigurationsCompleted()1630     protected void notifyLoadQnsConfigurationsCompleted() {
1631         if (mQnsCarrierConfigLoadedRegistrants != null) {
1632             mQnsCarrierConfigLoadedRegistrants.notifyRegistrants();
1633         } else {
1634             Log.d(mLogTag, "notifyLoadQnsConfigurationsCompleted. no Registrant.");
1635         }
1636     }
1637 
1638     /** Notify all the registrants of the Slot loaded after carrier config loading is Completed */
notifyQnsConfigurationsChanged()1639     protected void notifyQnsConfigurationsChanged() {
1640 
1641         if (mQnsCarrierConfigChangedRegistrants != null) {
1642             mQnsCarrierConfigChangedRegistrants.notifyRegistrants();
1643         } else {
1644             Log.d(mLogTag, "notifyQnsConfigurationsChanged. no Registrant.");
1645         }
1646     }
1647 
1648     /**
1649      * API exposed for other classes to register for notification with handlers on Carrier
1650      * Configuration Loaded
1651      *
1652      * @param h    Handler to receive event
1653      * @param what Event on which to be handled
1654      */
registerForConfigurationLoaded(Handler h, int what)1655     void registerForConfigurationLoaded(Handler h, int what) {
1656         mQnsCarrierConfigLoadedRegistrants.addUnique(h, what, null);
1657         if (mIsConfigLoaded) {
1658             // notify the handler if config is already loaded.
1659             h.sendEmptyMessage(what);
1660         }
1661     }
1662 
1663     /**
1664      * API exposed for other classes to register for notification with handlers on Carrier
1665      * Configuration changed
1666      *
1667      * @param h    Handler to receive event
1668      * @param what Event on which to be handled
1669      */
registerForConfigurationChanged(Handler h, int what)1670     void registerForConfigurationChanged(Handler h, int what) {
1671         mQnsCarrierConfigChangedRegistrants.addUnique(h, what, null);
1672     }
1673 
1674     /**
1675      * API exposed for other classes to unregister for notification of QNS Configuration loaded with
1676      * handlers
1677      *
1678      * @param h Handler to Unregister receiving event Output : Void
1679      */
unregisterForConfigurationLoaded(Handler h)1680     void unregisterForConfigurationLoaded(Handler h) {
1681         mQnsCarrierConfigLoadedRegistrants.remove(h);
1682     }
1683 
1684     /**
1685      * API exposed for other classes to unregister for notification of QNS Configuration changed
1686      * with handlers
1687      *
1688      * @param h Handler to Unregister receiving event Output : Void
1689      */
unregisterForConfigurationChanged(Handler h)1690     void unregisterForConfigurationChanged(Handler h) {
1691         mQnsCarrierConfigChangedRegistrants.remove(h);
1692     }
1693 
1694     /**
1695      * This method returns if WFC is supported in Airplane Mode On
1696      *
1697      * @return : boolean (True/False)
1698      */
allowWFCOnAirplaneModeOn()1699     boolean allowWFCOnAirplaneModeOn() {
1700 
1701         return mIsWfcInAirplaneModeOnSupport;
1702     }
1703 
1704     /**
1705      * This method returns if in-call handover decision from WLAN to WWAN should not consider VoPS
1706      * status.
1707      *
1708      * @return True if in-call handover decision from WLAN to WWAN should not consider VoPS status,
1709      * otherwise false.
1710      */
isInCallHoDecisionWlanToWwanWithoutVopsCondition()1711     boolean isInCallHoDecisionWlanToWwanWithoutVopsCondition() {
1712         return mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported;
1713     }
1714 
1715     /**
1716      * This method returns VOPS/VONR bit is required for WWAN availability.
1717      *
1718      * @return : boolean (True/False)
1719      */
isMmtelCapabilityRequired(int coverage)1720     boolean isMmtelCapabilityRequired(int coverage) {
1721         if (mIsMmtelCapabilityRequired == null || mIsMmtelCapabilityRequired.length == 0) {
1722             return true;
1723         }
1724         for (int i : mIsMmtelCapabilityRequired) {
1725             if ((i == CarrierConfigManager.Ims.NETWORK_TYPE_HOME
1726                             && coverage == QnsConstants.COVERAGE_HOME)
1727                     || (i == CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING
1728                             && coverage == QnsConstants.COVERAGE_ROAM)) {
1729                 return false;
1730             }
1731         }
1732         return true;
1733     }
1734 
1735     /**
1736      * This method returns if VoLTE roaming is supported by a carrier.
1737      *
1738      * @return True if VoLTE roaming is supported or UE is in home network, otherwise false.
1739      */
isVolteRoamingSupported(@nsConstants.CellularCoverage int coverage)1740     boolean isVolteRoamingSupported(@QnsConstants.CellularCoverage int coverage) {
1741         if (coverage == QnsConstants.COVERAGE_ROAM) {
1742             return mIsVolteRoamingSupported;
1743         }
1744         return true;
1745     }
1746 
1747     /**
1748      * This method returns Video call over WFC with wfc off & LTE preconditions met
1749      *
1750      * @return : boolean (True/False)
1751      */
allowVideoOverIWLANWithCellularLimitedCase()1752     boolean allowVideoOverIWLANWithCellularLimitedCase() {
1753         return mIsVideoOverIWLANWithCellularCheckSupport;
1754     }
1755 
1756     /**
1757      * This method returns if handover is allowed by policy
1758      *
1759      * @return True if handover is allowed by policy, otherwise false.
1760      */
isHandoverAllowedByPolicy( int netCapability, int srcAn, int destAn, @QnsConstants.CellularCoverage int coverage)1761     boolean isHandoverAllowedByPolicy(
1762             int netCapability, int srcAn, int destAn, @QnsConstants.CellularCoverage int coverage) {
1763         Log.d(
1764                 mLogTag,
1765                 "isHandoverAllowedByPolicy netCapability: "
1766                         + QnsUtils.getNameOfNetCapability(netCapability)
1767                         + " srcAccessNetwork:"
1768                         + QnsConstants.accessNetworkTypeToString(srcAn)
1769                         + " destAccessNetwork:"
1770                         + QnsConstants.accessNetworkTypeToString(destAn)
1771                         + "  "
1772                         + QnsConstants.coverageToString(coverage));
1773         // check Telephony handover policy.
1774         // Matching the rules by the configured order. Bail out if find first matching rule.
1775         for (HandoverRule rule : mHandoverRuleList) {
1776             if (rule.mIsOnlyForRoaming && coverage != QnsConstants.COVERAGE_ROAM) continue;
1777 
1778             if (rule.mSourceAccessNetworks.contains(srcAn)
1779                     && rule.mTargetAccessNetworks.contains(destAn)) {
1780                 // if no capability rule specified, data network capability is considered matched.
1781                 // otherwise, any capabilities overlap is also considered matched.
1782                 if (rule.mNetworkCapabilities.isEmpty()
1783                         || rule.mNetworkCapabilities.contains(netCapability)) {
1784                     if (rule.mHandoverRuleType == HandoverRule.RULE_TYPE_DISALLOWED) {
1785                         Log.d(mLogTag, "isHandoverAllowedByPolicy:Not allowed by policy " + rule);
1786                         return false;
1787                     } else {
1788                         Log.d(mLogTag, "isHandoverAllowedByPolicy: allowed by policy " + rule);
1789                         return true;
1790                     }
1791                 }
1792             }
1793         }
1794 
1795         Log.d(mLogTag, "isHandoverAllowedByPolicy: Did not find matching rule. ");
1796         // Disallow handover for non-IMS network capability anyway if no rule is found.
1797         if (netCapability != NetworkCapabilities.NET_CAPABILITY_IMS) return false;
1798 
1799         // Allow handover for IMS network capability anyway if no rule is found.
1800         return true;
1801     }
1802 
1803     /**
1804      * This method returns if Service Barring Check for HO decision is Supported
1805      *
1806      * @return : boolean (True/False)
1807      */
isServiceBarringCheckSupported()1808     boolean isServiceBarringCheckSupported() {
1809 
1810         return mIsServiceBarringCheckSupport;
1811     }
1812 
1813     /**
1814      * This method returns if the Guard timer (Ping Pong) hysteresis is preference specific
1815      *
1816      * @return : Based on Carrier Config Settings based on operator requirement possible values:
1817      * True / False
1818      */
isGuardTimerHysteresisOnPrefSupported()1819     boolean isGuardTimerHysteresisOnPrefSupported() {
1820 
1821         return mIsHoGuardOnPreferenceSupport;
1822     }
1823 
1824     /**
1825      * This method returns if the network(HOME or ROAM) requires handover guard timer.
1826      *
1827      * @return : Based on Carrier Config Settings based on operator requirement possible values:
1828      * True / False
1829      */
isHysteresisTimerEnabled(int coverage)1830     boolean isHysteresisTimerEnabled(int coverage) {
1831         if (mNetworkEnableHysteresisTimer == QnsConstants.COVERAGE_BOTH
1832                 || mNetworkEnableHysteresisTimer == coverage) {
1833             return true;
1834         }
1835         return false;
1836     }
1837 
1838     /**
1839      * Get carrier config for the KEY_ROAM_TRANSPORT_TYPE_SELECTION_WITHOUT_SIGNAL_STRENGTH_BOOL if
1840      * true, It ignores all thresholds needed to only refer to availability.
1841      *
1842      * @return true for key value is true. False for otherwise.
1843      */
isTransportTypeSelWithoutSSInRoamSupported()1844     boolean isTransportTypeSelWithoutSSInRoamSupported() {
1845 
1846         return mAnspSupportConfigArray[0];
1847     }
1848 
1849     /*
1850      * get carrierconfig for KEY_PREFER_CURRENT_TRANSPORT_TYPE_IN_VOICE_CALL
1851      * true: Prefer current transport type during voice call.
1852      *
1853      * @return true for key value is true. False for otherwise.
1854      */
isCurrentTransportTypeInVoiceCallSupported()1855     boolean isCurrentTransportTypeInVoiceCallSupported() {
1856 
1857         return mAnspSupportConfigArray[1];
1858     }
1859 
1860     /**
1861      * Get carrierconfig for KEY_POLICY_OVERRIDE_CELL_PREF_TO_IMS_PREF_HOME_BOOL
1862      * true: Use IMS Preferred when WFC Mode is Cellular Preferred at Home Network.
1863      *
1864      * @return true for key value is true. False for otherwise.
1865      */
isOverrideImsPreferenceSupported()1866     boolean isOverrideImsPreferenceSupported() {
1867         return mAnspSupportConfigArray[2];
1868     }
1869 
1870     /**
1871      * The method is to return if choose WFC prferred transport in both WWAN and WLAN are bad
1872      * conditions. It is controlled by
1873      * KEY_CHOOSE_WFC_PREFERRED_TRANSPORT_IN_BOTH_BAD_CONDITION_INT_ARRAY.
1874      *
1875      * @return : boolean (True/False)
1876      */
isChooseWfcPreferredTransportInBothBadCondition(int wfcMode)1877     boolean isChooseWfcPreferredTransportInBothBadCondition(int wfcMode) {
1878         if (mIsWfcPreferredTransportRequired == null
1879                 || mIsWfcPreferredTransportRequired.length == 0) {
1880             return false;
1881         }
1882         for (int i : mIsWfcPreferredTransportRequired) {
1883             if (wfcMode == i) {
1884                 return true;
1885             }
1886         }
1887         return false;
1888     }
1889 
1890     /**
1891      * This method returns whether the rove out(to Cellular) policy includes a Wi-Fi bad condition
1892      * at handover guarding time.
1893      *
1894      * @return : Based on Carrier Config Settings based on operator requirement possible values:
1895      * True / False
1896      */
isRoveOutWithWiFiLowQualityAtGuardingTime()1897     boolean isRoveOutWithWiFiLowQualityAtGuardingTime() {
1898 
1899         return mIsRoveOutWifiBadGuardTimerConditionsSupported;
1900     }
1901 
1902     /**
1903      * This method returns the waiting time for the preferred transport type at power up.
1904      *
1905      * @return : A timer in millisecond
1906      */
getWaitingTimerForPreferredTransportOnPowerOn(int transportType)1907     int getWaitingTimerForPreferredTransportOnPowerOn(int transportType) {
1908         switch (transportType) {
1909             case TRANSPORT_TYPE_WWAN:
1910                 return mWaitingTimerForPreferredTransport[0];
1911             case TRANSPORT_TYPE_WLAN:
1912                 return mWaitingTimerForPreferredTransport[1];
1913             default:
1914                 Log.d(mLogTag, "Invalid transport type, return the default timer.");
1915                 return QnsConstants.KEY_DEFAULT_VALUE;
1916         }
1917     }
1918 
1919     /**
1920      * This method returns the Transport type Preference on Power On.
1921      *
1922      * @return : Based on Carrier Config Settings Possible values (3000msec:Default or operator
1923      * customisation.
1924      */
getWIFIRssiBackHaulTimer()1925     int getWIFIRssiBackHaulTimer() {
1926         return mWifiThresBackHaulTimer;
1927     }
1928 
1929     /**
1930      * This method returns Cellular SS Backhaul Timer.
1931      *
1932      * @return : Based on Carrier Config Settings based on operator requirement possible values ( 0
1933      * : Invalid or 320ms)
1934      */
getCellularSSBackHaulTimer()1935     int getCellularSSBackHaulTimer() {
1936 
1937         return mCellularThresBackHaulTimer;
1938     }
1939 
1940     /**
1941      * This method returns IWLAN HO Avoid time due to Low RTP Quality Backhaul Timer.
1942      *
1943      * @return : Based on Carrier Config Settings based on operator requirement possible values ( 0
1944      * : or operator requirement)
1945      */
getHoRestrictedTimeOnLowRTPQuality( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork)1946     int getHoRestrictedTimeOnLowRTPQuality(
1947             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork) {
1948 
1949         if (accessNetwork == TRANSPORT_TYPE_WLAN) {
1950             return mHoRestrictTimeOnRtpQuality[0];
1951         } else if (accessNetwork == TRANSPORT_TYPE_WWAN) {
1952             return mHoRestrictTimeOnRtpQuality[1];
1953         } else {
1954             return QnsConstants.KEY_DEFAULT_VALUE;
1955         }
1956     }
1957 
1958     /**
1959      * This method returns QNS preferred transport type for network capabilities / Services
1960      *
1961      * @return : Based on Carrier Config Settings based on operator requirement possible values:
1962      * TRANSPORT_TYPE_ALLOWED_WWAN = 0 TRANSPORT_TYPE_ALLOWED_IWLAN = 1
1963      * TRANSPORT_TYPE_ALLOWED_BOTH = 2
1964      */
getQnsSupportedTransportType(int netCapability)1965     int getQnsSupportedTransportType(int netCapability) {
1966         if (netCapability == NetworkCapabilities.NET_CAPABILITY_IMS) {
1967             return mQnsImsTransportType;
1968         } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_EIMS) {
1969             return mQnsSosTransportType;
1970         } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_MMS) {
1971             return mQnsMmsTransportType;
1972         } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_XCAP) {
1973             HashSet<Integer> supportedTransportType = new HashSet<>();
1974             if (mQnsXcapSupportedAccessNetworkTypes != null) {
1975                 Arrays.stream(mQnsXcapSupportedAccessNetworkTypes)
1976                         .forEach(accessNetwork -> supportedTransportType.add(
1977                                 QnsUtils.getTransportTypeFromAccessNetwork(accessNetwork)));
1978             }
1979             if (supportedTransportType.contains(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)) {
1980                 if (supportedTransportType.contains(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) {
1981                     return QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH;
1982                 }
1983                 return QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN;
1984             }
1985             return QnsConstants.TRANSPORT_TYPE_ALLOWED_WWAN;
1986         } else if (netCapability == NetworkCapabilities.NET_CAPABILITY_CBS) {
1987             return mQnsCbsTransportType;
1988         }
1989         return QnsConstants.INVALID_ID;
1990     }
1991 
1992     /**
1993      * This method returns the hysteresis timer when handover from WLAN to WWAN.
1994      *
1995      * @return : the hysteresis timer
1996      */
getWwanHysteresisTimer(int netCapability, @QnsConstants.QnsCallType int callType)1997     int getWwanHysteresisTimer(int netCapability, @QnsConstants.QnsCallType int callType) {
1998         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC)) {
1999             return mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC);
2000         }
2001         switch (netCapability) {
2002             case NetworkCapabilities.NET_CAPABILITY_IMS:
2003             case NetworkCapabilities.NET_CAPABILITY_EIMS:
2004                 if (callType == QnsConstants.CALL_TYPE_IDLE) {
2005                     return mWwanHysteresisTimer[0];
2006                 } else if (callType == QnsConstants.CALL_TYPE_VOICE) {
2007                     return mWwanHysteresisTimer[1];
2008                 } else if (callType == QnsConstants.CALL_TYPE_VIDEO) {
2009                     return mWwanHysteresisTimer[2];
2010                 } else {
2011                     return QnsConstants.KEY_DEFAULT_VALUE;
2012                 }
2013             case NetworkCapabilities.NET_CAPABILITY_MMS:
2014             case NetworkCapabilities.NET_CAPABILITY_XCAP:
2015             case NetworkCapabilities.NET_CAPABILITY_CBS:
2016                 if (callType == QnsConstants.CALL_TYPE_IDLE) {
2017                     return mNonImsWwanHysteresisTimer[0];
2018                 } else {
2019                     return mNonImsWwanHysteresisTimer[1];
2020                 }
2021             default:
2022                 return QnsConstants.KEY_DEFAULT_VALUE;
2023         }
2024     }
2025 
2026     /**
2027      * This method returns the hysteresis timer when handover from WWAN to WLAN.
2028      *
2029      * @return : the hysteresis timer
2030      */
getWlanHysteresisTimer(int netCapability, @QnsConstants.QnsCallType int callType)2031     int getWlanHysteresisTimer(int netCapability, @QnsConstants.QnsCallType int callType) {
2032         if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC)) {
2033             return mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC);
2034         }
2035         switch (netCapability) {
2036             case NetworkCapabilities.NET_CAPABILITY_IMS:
2037             case NetworkCapabilities.NET_CAPABILITY_EIMS:
2038                 if (callType == QnsConstants.CALL_TYPE_IDLE) {
2039                     return mWlanHysteresisTimer[0];
2040                 } else if (callType == QnsConstants.CALL_TYPE_VOICE) {
2041                     return mWlanHysteresisTimer[1];
2042                 } else if (callType == QnsConstants.CALL_TYPE_VIDEO) {
2043                     return mWlanHysteresisTimer[2];
2044                 } else {
2045                     return QnsConstants.KEY_DEFAULT_VALUE;
2046                 }
2047             case NetworkCapabilities.NET_CAPABILITY_MMS:
2048             case NetworkCapabilities.NET_CAPABILITY_XCAP:
2049             case NetworkCapabilities.NET_CAPABILITY_CBS:
2050                 if (callType == QnsConstants.CALL_TYPE_IDLE) {
2051                     return mNonImsWlanHysteresisTimer[0];
2052                 } else {
2053                     return mNonImsWlanHysteresisTimer[1];
2054                 }
2055             default:
2056                 return QnsConstants.KEY_DEFAULT_VALUE;
2057         }
2058     }
2059 
2060     /**
2061      * This method returns the timer millis for the minimum guarding timer.
2062      *
2063      * @return the minimum guarding timer in millis. applies when handover guarding is disabled or
2064      * there is no guarding time.
2065      */
getMinimumHandoverGuardingTimer()2066     int getMinimumHandoverGuardingTimer() {
2067         int timer = mMinimumHandoverGuardingTimer;
2068         if (timer <= 0) {
2069             return 0;
2070         }
2071         if (timer >= QnsConstants.CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER_LIMIT) {
2072             timer = QnsConstants.CONFIG_DEFAULT_MIN_HANDOVER_GUARDING_TIMER_LIMIT;
2073         }
2074         return timer;
2075     }
2076 
2077     /**
2078      * This method returns the Threshold gap offset based on which threshold to be registered during
2079      * Guard timer Running / Expired conditions from Evaluator
2080      *
2081      * @return : Based on Carrier Config Settings & operator requirement Default Value : 0 gap
2082      * offset (Means different threshold for Guard timer conditions not enabled)
2083      */
getThresholdGapWithGuardTimer( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType)2084     int getThresholdGapWithGuardTimer(
2085             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType) {
2086 
2087         return getValueForMeasurementType(
2088                 accessNetwork, measType, mRoveInGuardTimerConditionThresholdGaps);
2089 
2090     }
2091 
2092     /**
2093      *  This method returns hysteresis Dbm level for ran and measurement type configured.
2094      *
2095      * @return : Based on Carrier Config Settings & operator requirement Default Value.
2096      * Note: If configured value set is less than zero or not set,
2097      * {@link QnsConstants#KEY_DEFAULT_VALUE}
2098      */
getWwanHysteresisDbLevel( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType)2099     public int getWwanHysteresisDbLevel(
2100             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType) {
2101 
2102         int hysteresisDb = getValueForMeasurementType(
2103                 accessNetwork, measType, mAccessNetworkMeasurementHysteresisDb);
2104         return hysteresisDb >= 0 ? hysteresisDb : QnsConstants.KEY_DEFAULT_VALUE;
2105     }
2106 
getValueForMeasurementType( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType, String [] measurementValues)2107     private int getValueForMeasurementType(
2108             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int measType,
2109             String [] measurementValues) {
2110 
2111         if (measurementValues == null) {
2112             return QnsConstants.KEY_DEFAULT_VALUE;
2113         }
2114 
2115         for (String check_offset : measurementValues) {
2116             if (check_offset == null || check_offset.isEmpty()) continue;
2117             String[] value = check_offset.split(":");
2118             String access_network = sAccessNetworkMap.get(accessNetwork);
2119             String measurement_Type = sMeasTypeMap.get(measType);
2120             try {
2121                 if (value.length == 3 && value[0].equalsIgnoreCase(access_network)
2122                         && value[1].equalsIgnoreCase(measurement_Type)) {
2123                     return Integer.parseInt(value[2]);
2124                 }
2125             } catch (Exception e) {
2126                 e.printStackTrace();
2127             }
2128         }
2129         return QnsConstants.KEY_DEFAULT_VALUE;
2130     }
2131 
hasThresholdGapWithGuardTimer()2132     boolean hasThresholdGapWithGuardTimer() {
2133         if (mRoveInGuardTimerConditionThresholdGaps == null) {
2134             return false;
2135         }
2136         return true;
2137     }
2138 
2139     /**
2140      * This method returns Access Network Selection Policy based on network capability
2141      *
2142      * @param targetTransportType : WWAN/WLAN
2143      * @return : Target transport mapped to string
2144      */
transportNetworkToString(int targetTransportType)2145     static String transportNetworkToString(int targetTransportType) {
2146         switch (targetTransportType) {
2147             case TRANSPORT_TYPE_WWAN:
2148                 return "CELLULAR";
2149             case TRANSPORT_TYPE_WLAN:
2150                 return "WIFI";
2151         }
2152         return "";
2153     }
2154 
2155     /**
2156      * Finds and returns a threshold config that meets the given parameter condition.
2157      *
2158      * @param accessNetwork   (EUTRAN/UTRAN/NGRAN/GERAN/IWLAN)
2159      * @param callType        (IDLE/VOICE/VIDEO)
2160      * @param measurementType (RSRP/RSRQ/RSSNR/SSRSP/SSRSQ/RSCP/RSSI)
2161      * @return QnsConfigArray for good, bad and worst thresholds. If the value does not exist or is
2162      * not supported, it is filled with invalid (0x0000FFFF). Note, for the wifi case, the worst
2163      * in thresholds will be invalid. INVALID VALUE, if not found item or exceptions.
2164      */
getThreshold( @ccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int callType, int measurementType)2165     QnsConfigArray getThreshold(
2166             @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork,
2167             int callType,
2168             int measurementType) {
2169         int[] thresholdList = new int[] {0x0000FFFF, 0x0000FFFF, 0x0000FFFF};
2170         if (accessNetwork == AccessNetworkConstants.AccessNetworkType.UNKNOWN
2171                 || measurementType == SIGNAL_MEASUREMENT_TYPE_UNKNOWN) {
2172             return null;
2173         }
2174 
2175         String access_network = sAccessNetworkMap.get(accessNetwork);
2176         String measurement_Type = sMeasTypeMap.get(measurementType);
2177         String call_Type = sCallTypeMap.get(callType);
2178 
2179         if (access_network != null && measurement_Type != null && call_Type != null) {
2180             String key =
2181                     "qns."
2182                             + call_Type
2183                             + "_"
2184                             + access_network
2185                             + "_"
2186                             + measurement_Type
2187                             + "_"
2188                             + "int_array";
2189 
2190             thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key);
2191 
2192             if (thresholdList != null && thresholdList.length > 1) {
2193                 if (AccessNetworkConstants.AccessNetworkType.IWLAN == accessNetwork
2194                         || thresholdList.length == 2) {
2195                     return new QnsConfigArray(thresholdList[0], thresholdList[1]);
2196                 } else {
2197                     return new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]);
2198                 }
2199             } else {
2200                 thresholdList = new int[] {0x0000FFFF, 0x0000FFFF, 0x0000FFFF};
2201             }
2202         }
2203         return new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]);
2204     }
2205 
getThresholdByPref( int accessNetwork, int callType, int measurementType, int preference)2206     QnsConfigArray getThresholdByPref(
2207             int accessNetwork, int callType, int measurementType, int preference) {
2208         if (accessNetwork == AccessNetworkConstants.AccessNetworkType.UNKNOWN
2209                 || measurementType == SIGNAL_MEASUREMENT_TYPE_UNKNOWN) {
2210             return null;
2211         }
2212 
2213         int[] thresholdList = null;
2214         String access_network = sAccessNetworkMap.get(accessNetwork);
2215         String measurement_Type = sMeasTypeMap.get(measurementType);
2216         String call_Type = sCallTypeMap.get(callType);
2217 
2218         if (access_network == null || measurement_Type == null || call_Type == null) {
2219             return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF);
2220         }
2221 
2222         if (accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN
2223                 && preference == QnsConstants.WIFI_PREF) {
2224             String overrideKey =
2225                     "qns.override_wifi_pref_"
2226                             + call_Type
2227                             + "_"
2228                             + access_network
2229                             + "_"
2230                             + measurement_Type
2231                             + "_int_array";
2232             thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(overrideKey);
2233         }
2234 
2235         if (thresholdList == null || thresholdList.length < 2) {
2236             String key =
2237                     "qns."
2238                             + call_Type
2239                             + "_"
2240                             + access_network
2241                             + "_"
2242                             + measurement_Type
2243                             + "_int_array";
2244             thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key);
2245         }
2246         if (thresholdList == null || thresholdList.length < 2) {
2247             return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF);
2248         }
2249 
2250         if (AccessNetworkConstants.AccessNetworkType.IWLAN == accessNetwork
2251                 || thresholdList.length == 2) {
2252             QnsConfigArray qnsConfigArray = new QnsConfigArray(thresholdList[0], thresholdList[1]);
2253             return applyProvisioningInfo(qnsConfigArray, accessNetwork, measurementType, callType);
2254         }
2255 
2256         QnsConfigArray qnsConfigArray =
2257                 new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]);
2258         return applyProvisioningInfo(qnsConfigArray, accessNetwork, measurementType, callType);
2259     }
2260 
getWifiRssiThresholdWithoutCellular(int callType)2261     QnsConfigArray getWifiRssiThresholdWithoutCellular(int callType) {
2262         int[] thresholdList;
2263         String call_Type = sCallTypeMap.get(callType);
2264 
2265         if (call_Type == null) {
2266             return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF);
2267         }
2268 
2269         String key = "qns." + call_Type + "_wifi_rssi_without_cellular_int_array";
2270         thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key);
2271 
2272         if (thresholdList == null || thresholdList.length < 2) {
2273             return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF);
2274         }
2275 
2276         return new QnsConfigArray(thresholdList[0], thresholdList[1]);
2277     }
2278 
2279     /**
2280      * Finds and returns a policy config that meets the given parameter condition.
2281      *
2282      * @param direction    (ROVE_IN / ROVE_OUT)
2283      * @param preCondition (Types of CALL, PREFERENCE, COVERAGE and so on)
2284      * @return QnsConfigArray for good, bad and worst policy. If the value does not exist or is not
2285      * supported, it is filled with invalid. (0x0000FFFF). Note, for the wifi case, the worst in
2286      * thresholds will be invalid. null, if not found item or exceptions.
2287      */
getPolicy( @nsConstants.RoveDirection int direction, AccessNetworkSelectionPolicy.PreCondition preCondition)2288     String[] getPolicy(
2289             @QnsConstants.RoveDirection int direction,
2290             AccessNetworkSelectionPolicy.PreCondition preCondition) {
2291 
2292         String key =
2293                 "qns.condition_"
2294                         + QnsConstants.directionToString(direction).toLowerCase()
2295                         + "_"
2296                         + QnsConstants.callTypeToString(preCondition.getCallType()).toLowerCase()
2297                         + "_"
2298                         + QnsConstants.preferenceToString(preCondition.getPreference())
2299                                 .toLowerCase()
2300                         + "_"
2301                         + QnsConstants.coverageToString(preCondition.getCoverage()).toLowerCase()
2302                         + "_";
2303 
2304         if (preCondition instanceof AccessNetworkSelectionPolicy.GuardingPreCondition) {
2305             AccessNetworkSelectionPolicy.GuardingPreCondition guardingCondition =
2306                     (AccessNetworkSelectionPolicy.GuardingPreCondition) preCondition;
2307             String guardingKey =
2308                     key
2309                             + QnsConstants.guardingToString(guardingCondition.getGuarding())
2310                                     .toLowerCase()
2311                             + "_string_array";
2312             String[] guardingPolicy = mAnspConfigMgr.getAnspCarrierPolicy(guardingKey);
2313             if (guardingPolicy != null) {
2314                 return guardingPolicy;
2315             }
2316         }
2317         key = key + "string_array";
2318         return mAnspConfigMgr.getAnspCarrierPolicy(key);
2319     }
2320 
2321     /**
2322      * This method returns RTP Metrics data of Carrier for HO decision making
2323      *
2324      * @return config of RTP metrics. refer {@link RtpMetricsConfig}
2325      */
2326     @VisibleForTesting
getRTPMetricsData()2327     RtpMetricsConfig getRTPMetricsData() {
2328 
2329         return new RtpMetricsConfig(
2330                 mRTPMetricsData[0], mRTPMetricsData[1], mRTPMetricsData[2], mRTPMetricsData[3]);
2331     }
2332 
2333     /**
2334      * This retrieves fallback timer to WWAN with the reason of IMS unregistered.
2335      *
2336      * @return fallback time in millis.
2337      */
2338     @VisibleForTesting
getFallbackTimeImsUnregistered(int reason, int preferMode)2339     int getFallbackTimeImsUnregistered(int reason, int preferMode) {
2340         Log.d(
2341                 mLogTag,
2342                 "getFallbackTimeImsUnregistered reason:" + reason + " prefMode:" + preferMode);
2343         for (FallbackRule rule : mFallbackWwanRuleWithImsUnregistered) {
2344             Log.d(mLogTag, rule.toString());
2345             if (preferMode != QnsConstants.WIFI_ONLY
2346                     && (rule.mPreferenceMode == -1 || rule.mPreferenceMode == preferMode)) {
2347                 int time = rule.getFallBackTime(reason);
2348                 if (time > 0) {
2349                     Log.d(mLogTag, "getFallbackTimeImsUnregistered fallbackTime:" + time);
2350                     return time;
2351                 }
2352             }
2353         }
2354         Log.d(mLogTag, "getFallbackTimeImsUnregistered fallbackTime:" + 0);
2355         return 0;
2356     }
2357 
2358     /**
2359      * This retrieves fallback timer to WWAN with the reason of IMS HO register fail.
2360      *
2361      * @return fallback time in millis.
2362      */
2363     @VisibleForTesting
getFallbackTimeImsHoRegisterFailed(int reason, int preferMode)2364     int getFallbackTimeImsHoRegisterFailed(int reason, int preferMode) {
2365         Log.d(
2366                 mLogTag,
2367                 "getFallbackTimeImsHoRegisterFailed reason:" + reason + " prefMode:" + preferMode);
2368         for (FallbackRule rule : mFallbackWwanRuleWithImsHoRegisterFail) {
2369             if (preferMode != QnsConstants.WIFI_ONLY
2370                     && (rule.mPreferenceMode == -1 || rule.mPreferenceMode == preferMode)) {
2371                 Log.d(mLogTag, rule.toString());
2372                 int time = rule.getFallBackTime(reason);
2373                 Log.d(mLogTag, "getFallbackTimeImsHoRegisterFailed fallback time: " + time);
2374                 if (time > 0) return time;
2375             }
2376         }
2377         Log.d(mLogTag, "getFallbackTimeImsHoRegisterFailed fallback time: " + 0);
2378         return 0;
2379     }
2380 
2381     /**
2382      * This method returns Access Network Selection Policy Support configurations with boolean array
2383      * list type
2384      *
2385      */
loadAnspCarrierSupportConfigs( PersistableBundle bundleCarrier, PersistableBundle bundleAsset)2386     void loadAnspCarrierSupportConfigs(
2387             PersistableBundle bundleCarrier, PersistableBundle bundleAsset) {
2388         int i = 0;
2389         String[] anspConfigs = {
2390             KEY_ROAM_TRANSPORT_TYPE_SELECTION_WITHOUT_SIGNAL_STRENGTH_BOOL,
2391             KEY_PREFER_CURRENT_TRANSPORT_TYPE_IN_VOICE_CALL_BOOL,
2392             KEY_POLICY_OVERRIDE_CELL_PREF_TO_IMS_PREF_HOME_BOOL
2393         };
2394 
2395         for (String key : anspConfigs) {
2396             mAnspSupportConfigArray[i] = getConfig(bundleCarrier, bundleAsset, key);
2397             i += 1;
2398         }
2399 
2400         mIsWfcPreferredTransportRequired =
2401                 getConfig(
2402                         bundleCarrier,
2403                         bundleAsset,
2404                         KEY_CHOOSE_WFC_PREFERRED_TRANSPORT_IN_BOTH_BAD_CONDITION_INT_ARRAY);
2405     }
2406 
2407     /**
2408      * This method gives the network capabilities supported based on
2409      * KEY_QNS_<NetworkCapability></NetworkCapability>_TRANSPORT_TYPE_INT
2410      *
2411      * @return : Supported network capabilities
2412      */
getQnsSupportedNetCapabilities()2413     List<Integer> getQnsSupportedNetCapabilities() {
2414         List<Integer> netCapabilities = new ArrayList<>();
2415         if (mQnsImsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN
2416                 || mQnsImsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) {
2417             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_IMS);
2418         }
2419         if (mQnsSosTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN
2420                 || mQnsSosTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) {
2421             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_EIMS);
2422         }
2423         if (mQnsMmsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN
2424                 || mQnsMmsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) {
2425             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_MMS);
2426         }
2427         if (mQnsXcapSupportedAccessNetworkTypes != null
2428                 && Arrays.stream(mQnsXcapSupportedAccessNetworkTypes)
2429                         .anyMatch(accessNetwork -> QnsUtils.getTransportTypeFromAccessNetwork(
2430                                 accessNetwork) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN)) {
2431             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_XCAP);
2432         }
2433         if (mQnsCbsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN
2434                 || mQnsCbsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) {
2435             netCapabilities.add(NetworkCapabilities.NET_CAPABILITY_CBS);
2436         }
2437         return netCapabilities;
2438     }
2439 
2440     private static HashMap<Integer, String> sRatStringMatcher;
2441     static {
2442         sRatStringMatcher = new HashMap<>();
sRatStringMatcher.put(AccessNetworkConstants.AccessNetworkType.EUTRAN, "LTE")2443         sRatStringMatcher.put(AccessNetworkConstants.AccessNetworkType.EUTRAN, "LTE");
sRatStringMatcher.put(AccessNetworkConstants.AccessNetworkType.NGRAN, "NR")2444         sRatStringMatcher.put(AccessNetworkConstants.AccessNetworkType.NGRAN, "NR");
sRatStringMatcher.put(AccessNetworkConstants.AccessNetworkType.UTRAN, "3G")2445         sRatStringMatcher.put(AccessNetworkConstants.AccessNetworkType.UTRAN, "3G");
sRatStringMatcher.put(AccessNetworkConstants.AccessNetworkType.GERAN, "2G")2446         sRatStringMatcher.put(AccessNetworkConstants.AccessNetworkType.GERAN, "2G");
2447     }
2448 
2449     /**
2450      * This method returns Allowed cellular RAT for IMS
2451      *
2452      * @param accessNetwork : (EUTRAN, NGRAN, UTRAN, GERAN)
2453      * @param netCapability : (ims, sos, mms, xcap, cbs)
2454      * @return : True or False based on configuration
2455      */
isAccessNetworkAllowed(int accessNetwork, int netCapability)2456     boolean isAccessNetworkAllowed(int accessNetwork, int netCapability) {
2457 
2458         switch (netCapability) {
2459             case NetworkCapabilities.NET_CAPABILITY_EIMS:
2460             case NetworkCapabilities.NET_CAPABILITY_IMS:
2461                 // cases to be enhanced for different key items when added
2462                 String ratName = sRatStringMatcher.get(accessNetwork);
2463                 if (mImsAllowedRats != null
2464                         && ratName != null
2465                         && Arrays.stream(mImsAllowedRats)
2466                                 .anyMatch(ratType -> TextUtils.equals(ratType, ratName))) {
2467                     return true;
2468                 }
2469                 break;
2470             case NetworkCapabilities.NET_CAPABILITY_XCAP:
2471                 return mQnsXcapSupportedAccessNetworkTypes != null
2472                         && Arrays.stream(mQnsXcapSupportedAccessNetworkTypes)
2473                                 .anyMatch(xcapAccessNetwork -> accessNetwork == xcapAccessNetwork);
2474             default:
2475                 return false;
2476         }
2477         return false;
2478     }
2479 
2480     /**
2481      * This method returns max HO Back to IWLAN count value with Fallback reason to Rove Out
2482      *
2483      * @return : int array (Ex: -1,-1 or 1,2 or 3,1 etc... )
2484      */
getQnsMaxIwlanHoCountDuringCall()2485     int getQnsMaxIwlanHoCountDuringCall() {
2486 
2487         if (mAllowMaxIwlanHoCountOnReason[0] <= 0) {
2488             mAllowMaxIwlanHoCountOnReason[0] = MAX_COUNT_INVALID;
2489         }
2490 
2491         return mAllowMaxIwlanHoCountOnReason[0];
2492     }
2493 
2494     /**
2495      * This method returns Supported Fallback reason to Rove Out from IWLAN
2496      *
2497      * @return : int array (Ex: -1,-1 or 1,2 or 3,1 etc... )
2498      */
getQnsIwlanHoRestrictReason()2499     int getQnsIwlanHoRestrictReason() {
2500         if (mAllowMaxIwlanHoCountOnReason[1] <= 0) {
2501             mAllowMaxIwlanHoCountOnReason[1] = FALLBACK_REASON_INVALID;
2502         }
2503         return mAllowMaxIwlanHoCountOnReason[1];
2504     }
2505 
2506     /**
2507      * This method returns to allow enabled Wi-Fi calling based on exceptional cellular state, even
2508      * when Wi-Fi calling is disabled.
2509      *
2510      * <p>Enable Wi-Fi calling If the call state is idle and the cellular network the UE is staying
2511      * on does not allow ims pdn.
2512      *
2513      * @return : Based on Carrier Config Settings based on operator requirement possible values:
2514      * True / False
2515      */
allowImsOverIwlanCellularLimitedCase()2516     boolean allowImsOverIwlanCellularLimitedCase() {
2517         return mIsAllowImsOverIwlanCellularLimitedCase;
2518     }
2519 
2520     /**
2521      * This method returns if Iwlan is not allowed when UE is in no WWAN coverage and the last
2522      * stored country code is outside the home country.
2523      *
2524      * @return True if need to block Iwlan, otherwise false.
2525      */
blockIwlanInInternationalRoamWithoutWwan()2526     boolean blockIwlanInInternationalRoamWithoutWwan() {
2527         return mIsBlockIwlanInInternationalRoamWithoutWwan;
2528     }
2529 
2530     /**
2531      * This method returns if IPv6 only WiFi is allowed
2532      *
2533      * @return True if need to block IPv6 only WiFi, otherwise false.
2534      */
blockIpv6OnlyWifi()2535     boolean blockIpv6OnlyWifi() {
2536         return mIsBlockIpv6OnlyWifi;
2537     }
2538 
2539     /**
2540      * This method returns the wait timer in milliseconds that VoWiFi registration in VoWiFi
2541      * activation process
2542      */
getVowifiRegistrationTimerForVowifiActivation()2543     int getVowifiRegistrationTimerForVowifiActivation() {
2544         return mVowifiRegistrationTimerForVowifiActivation;
2545     }
2546 
2547     /**
2548      * This method returns whether the IMS Registration state option is added when reporting a
2549      * qualified Wi-Fi network for network capabilities other than ims.
2550      *
2551      * @return : Based on Carrier Config Settings based on operator requirement possible values:
2552      * True / False
2553      */
getRatPreference(int netCapability)2554     int getRatPreference(int netCapability) {
2555         switch (netCapability) {
2556             case NetworkCapabilities.NET_CAPABILITY_XCAP:
2557                 return mXcapRatPreference;
2558             case NetworkCapabilities.NET_CAPABILITY_EIMS:
2559                 return mSosRatPreference;
2560             case NetworkCapabilities.NET_CAPABILITY_MMS:
2561                 return mMmsRatPreference;
2562             case NetworkCapabilities.NET_CAPABILITY_CBS:
2563                 return mCbsRatPreference;
2564         }
2565         return QnsConstants.RAT_PREFERENCE_DEFAULT;
2566     }
2567 
2568     /**
2569      * This method returns the rtt check server address config as per operator requirement
2570      *
2571      * @return Based on carrier config settings of operator. By default, to be made empty to
2572      * disable the feature.
2573      */
getWlanRttServerAddressConfig()2574     String getWlanRttServerAddressConfig() {
2575         String[] ping_address = getWlanRttPingConfigs();
2576 
2577         if (ping_address != null && ping_address[0] != null && !ping_address[0].isEmpty()) {
2578             return ping_address[0];
2579         } else {
2580             return null;
2581         }
2582     }
2583 
2584     /**
2585      * This method returns No of Pings, Intra Ping Interval, Size of the packet, RTT criteria RTT
2586      * retry timer
2587      *
2588      * @return : Based on carrier config settings as per operator requirement
2589      */
getWlanRttOtherConfigs()2590     int[] getWlanRttOtherConfigs() {
2591         int[] pingConfigs = new int[5];
2592         String[] rtt_ping_config = getWlanRttPingConfigs();
2593 
2594         if (rtt_ping_config != null && !rtt_ping_config[0].isEmpty()) {
2595             for (int i = 1; i < 6; i++) {
2596                 if (rtt_ping_config[i] != null) {
2597                     pingConfigs[i - 1] = Integer.parseInt(rtt_ping_config[i]);
2598                 }
2599             }
2600         }
2601         return pingConfigs;
2602     }
2603 
2604     /**
2605      * This method returns fallback Hysteresis timer on RTT Failure.
2606      *
2607      * @return : Based on carrier config settings as per operator requirement
2608      */
getWlanRttFallbackHystTimer()2609     int getWlanRttFallbackHystTimer() {
2610         String[] rtt_hyst_fallback_timer = getWlanRttPingConfigs();
2611 
2612         if (rtt_hyst_fallback_timer != null
2613                 && !rtt_hyst_fallback_timer[0].isEmpty()
2614                 && rtt_hyst_fallback_timer[6] != null) {
2615             return Integer.parseInt(rtt_hyst_fallback_timer[6]);
2616         } else {
2617             return 0;
2618         }
2619     }
2620 
getWlanRttPingConfigs()2621     private String[] getWlanRttPingConfigs() {
2622         if (mWlanRttBackhaulCheckConfigsOnPing == null) return null;
2623 
2624         return mWlanRttBackhaulCheckConfigsOnPing.split(",");
2625     }
2626 
2627     /**
2628      * If fallback for Initial connection failure for the network capability is met is supported ,
2629      * this method provides information about the failure retry count or retry timer or both if
2630      * supported until fallback to other transport.
2631      *
2632      * @param netCapability : (ims,sos,mms,xcap,cbs)
2633      * @return :
2634      * <NetworkCapability_SupportForFallback>:<retry_count>:<retry_timer>:<max_fallback_count>
2635      */
getInitialDataConnectionFallbackConfig(int netCapability)2636     int[] getInitialDataConnectionFallbackConfig(int netCapability) {
2637 
2638         int[] fallbackConfigOnDataFail = new int[4];
2639         String[] fallback_config = getFallbackConfigForNetCapability(netCapability);
2640 
2641         if (fallback_config != null
2642                 && fallback_config[0] != null
2643                 && fallback_config[0].length() > 0) {
2644             // netCapability Availability Status
2645             fallbackConfigOnDataFail[0] = 1;
2646 
2647             // Retry Count :  && fallback_config[1].length() > 0
2648             if (fallback_config.length > 1
2649                     && fallback_config[1] != null
2650                     && !fallback_config[1].isEmpty()) {
2651                 fallbackConfigOnDataFail[1] = Integer.parseInt(fallback_config[1]);
2652             }
2653 
2654             // Retry timer
2655             if (fallback_config.length > 2
2656                     && fallback_config[2] != null
2657                     && !fallback_config[2].isEmpty()) {
2658                 fallbackConfigOnDataFail[2] = Integer.parseInt(fallback_config[2]);
2659             }
2660 
2661             // Max fallback count
2662             if (fallback_config.length > 4
2663                     && fallback_config[4] != null
2664                     && !fallback_config[4].isEmpty()) {
2665                 fallbackConfigOnDataFail[3] = Integer.parseInt(fallback_config[4]);
2666             }
2667         }
2668         return fallbackConfigOnDataFail;
2669     }
2670 
2671     /**
2672      * This method returns the fall back timer to be starting the restriction , for no. of retries
2673      * when met with the pdn fail fallback causes
2674      *
2675      * @param netCapability : (ims,sos,mms,xcap,cbs)
2676      * @return : Fallback Guard timer to be set on starting the fallback restrict @ RestrictManager
2677      */
getFallbackGuardTimerOnInitialConnectionFail(int netCapability)2678     int getFallbackGuardTimerOnInitialConnectionFail(int netCapability) {
2679         String[] fallback_guard_timer = getFallbackConfigForNetCapability(netCapability);
2680 
2681         if (fallback_guard_timer != null
2682                 && fallback_guard_timer[0] != null
2683                 && fallback_guard_timer[0].length() > 0
2684                 && ((fallback_guard_timer.length > 1
2685                                 && fallback_guard_timer[1] != null
2686                                 && !fallback_guard_timer[1].isEmpty())
2687                         || (fallback_guard_timer.length > 2
2688                                 && fallback_guard_timer[2] != null
2689                                 && !fallback_guard_timer[2].isEmpty()))
2690                 && (fallback_guard_timer.length > 3
2691                         && fallback_guard_timer[3] != null
2692                         && !fallback_guard_timer[3].isEmpty())) {
2693             return Integer.parseInt(fallback_guard_timer[3]);
2694         } else {
2695             return 0;
2696         }
2697     }
2698 
2699     /**
2700      * To support find the right Initial Pdn connection failure fallback config based on network
2701      * capability
2702      */
getFallbackConfigForNetCapability(int netCapability)2703     private String[] getFallbackConfigForNetCapability(int netCapability) {
2704         if (mFallbackOnInitialConnectionFailure != null
2705                 && mFallbackOnInitialConnectionFailure.length > 0) {
2706             String netCapabilityName = QnsUtils.getNameOfNetCapability(netCapability);
2707             for (String config : mFallbackOnInitialConnectionFailure) {
2708                 Log.d(mLogTag, "Fallback On Initial Failure enabled for " + config);
2709                 if (config.contains(netCapabilityName)) {
2710                     return config.split(":");
2711                 }
2712             }
2713         }
2714         return null;
2715     }
2716 
2717     /**
2718      * Get the Sip Dialog Session policy when the Sip Dialog State is active. This Sip Dialog
2719      * Session policy is applied when there is no calling in the subscription, and when the device
2720      * is in a calling state, the calling policy is used first.
2721      *
2722      * @return 0: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_NONE} not Applied. The default value
2723      * for this key. 1: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_FOLLOW_VOICE_CALL} apply voice
2724      * call policy. 2: {@code QnsConstants#SIP_DIALOG_SESSION_POLICY_FOLLOW_VIDEO_CALL}  apply video
2725      * call policy.
2726      */
getSipDialogSessionPolicy()2727     @QnsConstants.QnsSipDialogSessionPolicy int getSipDialogSessionPolicy() {
2728         return mSipDialogSessionPolicy;
2729     }
2730 
2731     static class QnsConfigArray {
2732 
2733         /*
2734          * static invalid
2735          */
2736         static final int INVALID = 0x0000FFFF;
2737         /*
2738          * Thresholds, A signal value of good strength to enter.
2739          */
2740         int mGood = INVALID;
2741         /*
2742          * Thresholds, A signal value of bad strength to leave.
2743          */
2744         int mBad = INVALID;
2745         /*
2746          * Thresholds, A signal value of worst strength to enter.
2747          * The worst strength is only applicable for cellular.
2748          */
2749         int mWorst = INVALID;
2750 
QnsConfigArray(int good, int bad, int worst)2751         QnsConfigArray(int good, int bad, int worst) {
2752             set(good, bad, worst);
2753         }
2754 
QnsConfigArray(int good, int bad)2755         QnsConfigArray(int good, int bad) {
2756             set(good, bad, INVALID);
2757         }
2758 
set(int good, int bad, int worst)2759         void set(int good, int bad, int worst) {
2760             mGood = good;
2761             mBad = bad;
2762             mWorst = worst;
2763         }
2764 
2765         @Override
toString()2766         public String toString() {
2767             return "QnsConfigArray{"
2768                     + "Good="
2769                     + mGood
2770                     + ", Bad="
2771                     + mBad
2772                     + ", Worst="
2773                     + mWorst
2774                     + '}';
2775         }
2776     }
2777 
2778     @VisibleForTesting
2779     static class RtpMetricsConfig {
2780         /** Maximum jitter */
2781         final int mJitter;
2782 
2783         /** RTP packet loss rate in percentage */
2784         final int mPktLossRate;
2785 
2786         /** Time interval(milliseconds) of RTP packet loss rate */
2787         final int mPktLossTime;
2788 
2789         /** No RTP interval in milliseconds */
2790         final int mNoRtpInterval;
2791 
RtpMetricsConfig(int jitter, int pktLossRate, int pktLossTime, int noRtpInterval)2792         RtpMetricsConfig(int jitter, int pktLossRate, int pktLossTime, int noRtpInterval) {
2793             this.mJitter = jitter;
2794             this.mPktLossRate = pktLossRate;
2795             this.mPktLossTime = pktLossTime;
2796             this.mNoRtpInterval = noRtpInterval;
2797         }
2798 
2799         @Override
toString()2800         public String toString() {
2801             return "RtpMetricsConfig{"
2802                     + "mJitter="
2803                     + mJitter
2804                     + ", mPktLossRate="
2805                     + mPktLossRate
2806                     + ", mPktLossTime="
2807                     + mPktLossTime
2808                     + ", mNoRtpInterval="
2809                     + mNoRtpInterval
2810                     + '}';
2811         }
2812     }
2813 
2814     @VisibleForTesting
getQnsCarrierAnspSupportConfig()2815     QnsCarrierAnspSupportConfig getQnsCarrierAnspSupportConfig() {
2816         return mAnspConfigMgr;
2817     }
2818 }
2819