| /* |
| * Copyright (C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.qns; |
| |
| import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN; |
| import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; |
| import static android.telephony.SignalThresholdInfo.*; |
| import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID; |
| |
| import static com.android.qns.QnsConstants.FALLBACK_REASON_INVALID; |
| import static com.android.qns.QnsConstants.MAX_COUNT_INVALID; |
| import static com.android.qns.QnsConstants.SIGNAL_MEASUREMENT_TYPE_ECNO; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.content.Context; |
| import android.hardware.radio.V1_5.ApnTypes; |
| import android.os.Handler; |
| import android.os.HandlerThread; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.PersistableBundle; |
| import android.os.RegistrantList; |
| import android.telephony.AccessNetworkConstants; |
| import android.telephony.Annotation.NetCapability; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.telephony.data.ApnSetting; |
| import android.telephony.ims.ProvisioningManager; |
| import android.text.TextUtils; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.util.SparseArray; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| |
| /** |
| * This class supports loading Ansp(Access Network Selection Policy , Thresholds , Handover Polices |
| * & Other Supporting Carrier configurations , to support ANE to decide on the HO decision |
| * management & listing related Access Network to pass to Telephony |
| */ |
| public class QnsCarrierConfigManager { |
| /** |
| * Boolean indicating the WFC services in QNS Side is enabled, when airplane mode is On |
| * |
| * <p>{@code true}: QNS is enabled for WFC services in airplane mode on. {@code false}: QNS is |
| * disabled for WFC services in airplane mode on. The default value for this key is {@code true} |
| */ |
| public static final String KEY_QNS_SUPPORT_WFC_DURING_AIRPLANE_MODE_BOOL = |
| "qns.support_wfc_during_airplane_mode_bool"; |
| |
| /** |
| * Boolean indicating if in-call handover decision from WLAN to WWAN should consider VoPS |
| * status. |
| * |
| * <p>{@code true}: In-call handover decision from WLAN to WWAN won't consider VoPS status, for |
| * example, UE can perform handover from WLAN to LTE even if LTE network does not support VoPS. |
| * {@code false}: In-call handover decision from WLAN to WWAN will consider VoPS status, for |
| * example, UE should not perform handover from WLAN to LTE if LTE network does not support |
| * VoPS. |
| * The default value for this key is {@code false} |
| */ |
| public static final String KEY_IN_CALL_HO_DECISION_WLAN_TO_WWAN_WITHOUT_VOPS_CONDITION_BOOL = |
| "qns.in_call_ho_decision_wlan_to_wwan_without_vops_condition_bool"; |
| |
| /** |
| * Boolean indicating Iwlan TransportType priority is enabled , when VOPS(Voice Over PS Session) |
| * flag from NW is false . |
| * |
| * <p>{@code true}: Iwlan TransportType selection priority is enabled, when VOPS(Voice Over PS |
| * Session) is false. {@code false}: Iwlan TransportType selection priority is disabled, when |
| * VOPS (Voice Over PS Session) is false. The default value for this key is {@code true} |
| */ |
| public static final String KEY_QNS_VOPS_NOTAVAILABLE_PRIORITY_IWLAN_BOOL = |
| "qns.support_vops_notavailable_priority_iwlan_bool"; |
| |
| /** |
| * Boolean indicating when disabled , supporting of Guard Timer applied to both TransportType |
| * WWAN (Cellular) & WLAN ( Wifi) |
| * |
| * <p>{@code false}: Whe Disabled , Guard timer (To avoid Ping Pong) is executed for both the |
| * direction ( ie Cellular to Wifi & Wifi to Cellular) {@code true}: when enabled , Guard timer |
| * (To avoid Ping Pong) is executed only based on the preference set. The default value for this |
| * key is {@code false} |
| */ |
| public static final String KEY_QNS_HO_GUARDING_BY_PREFERENCE_BOOL = |
| "qns.ho_guarding_by_preference_bool"; |
| /** |
| * Boolean indicating the Service Barring check is disabled, when making HO decision from |
| * transport type WWAN (Cellular) to Transport type WLAN Wifi |
| * |
| * <p>{@code false}: Service Barring check is disabled , when making HO decision from transport |
| * type WWAN (Cellular) to Transport type WLAN Wifi {@code true}: Service Barring check is |
| * enabled , when making HO decision from transport type WWAN (Cellular) to Transport type WLAN |
| * Wifi The default value for this key is {@code false} |
| */ |
| public static final String KEY_QNS_SUPPORT_SERVICE_BARRING_CHECK_BOOL = |
| "qns.support_service_barring_check_bool"; |
| |
| /** |
| * Boolean indicating the transport type selection without Signal Strength is disabled, during |
| * roaming condition |
| * |
| * <p>{@code false}: when disabled , transport type selection is based on RAT existence & signal |
| * quality during roaming.. {@code true}: when enabled , transport type selection is based on |
| * RAT availability during roaming. (not depends on Signal Strength) The default value for this |
| * key is {@code false} |
| */ |
| public static final String KEY_ROAM_TRANSPORT_TYPE_SELECTION_WITHOUT_SIGNAL_STRENGTH_BOOL = |
| "qns.roam_transport_type_selection_without_signal_strength_bool"; |
| |
| /** |
| * Boolean indicating the preference to select/continue call in current Transport Type is |
| * disabled. |
| * |
| * <p>{@code false}: When disabled , preference to select/continue call in current Transport |
| * Type is not allowed {@code true}: When enabled , preference to select/continue call in |
| * current Transport Type is allowed The default value for this key is {@code false} |
| */ |
| public static final String KEY_PREFER_CURRENT_TRANSPORT_TYPE_IN_VOICE_CALL_BOOL = |
| "qns.prefer_current_transport_type_in_voice_call_bool"; |
| |
| /** |
| * Boolean to override IMS Mode Preference from cellular preference. |
| * |
| * <p>{@code false}: When disabled , no ims override preference. {@code true}: When enabled , |
| * load ims mode preference instead of cellular mode preference at home network. The default |
| * value for this key is {@code false} |
| */ |
| public static final String KEY_POLICY_OVERRIDE_CELL_PREF_TO_IMS_PREF_HOME_BOOL = |
| "qns.override_cell_pref_to_ims_pref_home"; |
| |
| /** |
| * Boolean indicating allowing video call over wifi is disabled , when cellular limited case |
| * meets.(ie no LTE home network is available, or if an LTE home network is available but VoPS |
| * is disabled or has 100% SSAC voice barring) |
| * |
| * <p>{@code false}: When disabled , preference to allow video call on meeting cellular limited |
| * case conditions over Wifi is not allowed. {@code true}: When enabled , preference to move |
| * video call on meeting cellular limited case conditions over Wifi is allowed. The default |
| * value for this key is {@code false} |
| */ |
| public static final String KEY_QNS_ALLOW_VIDEO_OVER_IWLAN_WITH_CELLULAR_LIMITED_CASE_BOOL = |
| "qns.allow_video_over_iwlan_with_cellular_limited_case_bool"; |
| |
| /** |
| * Boolean indicating cellular2WiFi-hystersis Scenario rove out policies of WIth WIfi Bad |
| * criteria check with Guard TImer conditions is disabled. |
| * |
| * <p>{@code false}: When disabled , cellular2WiFi-hystersis Scenario rove out policies during |
| * guard timer conditions(Running/Expired state) is not available {@code true}: When enabled , |
| * cellular2WiFi-hystersis Scenario rove out policies during guard timer |
| * conditions(Running/Expired state) is available The default value for this key is {@code |
| * false} |
| */ |
| public static final String KEY_QNS_ROVE_OUT_POLICY_WITH_WIFI_BAD_GUARDTIMER_CONDITIONS_BOOL = |
| "qns.rove_out_policy_with_wifi_bad_guardtimer_conditions_bool"; |
| |
| /** |
| * Boolean indicating enabling of Wi-Fi call when in a call state idle with a cellular network |
| * that does not support ims pdn. |
| * |
| * <p>{@code false}: When disabled , There is no action to enable Wi-Fi Calling. {@code true}: |
| * When enabled , Enable Wi-Fi calling, if the call state is idle and the cellular network the |
| * UE is staying on does not allow ims pdn. The default value for this key is {@code false} |
| */ |
| public static final String KEY_QNS_ALLOW_IMS_OVER_IWLAN_CELLULAR_LIMITED_CASE_BOOL = |
| "qns.allow_ims_over_iwlan_cellular_limited_case_bool"; |
| |
| /** |
| * Boolean indicating if to block IWLAN when UE is in no WWAN coverage and the last stored |
| * country code is outside the home country. |
| * By default this value is {@code false}. |
| * |
| */ |
| public static final String KEY_BLOCK_IWLAN_IN_INTERNATIONAL_ROAMING_WITHOUT_WWAN_BOOL = |
| "qns.block_iwlan_in_international_roaming_without_wwan_bool"; |
| |
| /** |
| * Boolean indicating if to block IWLAN when UE is connected to IPv6 only WiFi AP. The setting |
| * may only apply on Android T. For Android U onwards, we may support a carrier config at IWLAN |
| * if we still encounter any issues for IPv6 WFC. By default this value is {@code true}. |
| */ |
| public static final String KEY_BLOCK_IPV6_ONLY_WIFI_BOOL = "qns.block_ipv6_only_wifi_bool"; |
| |
| /** |
| * Specifies the Rat Preference for the XCAP apn type. Boolean indicating adding the IMS |
| * Registration condition to the Wi-Fi Rove in condition. |
| * |
| * <ul> |
| * <li>{@code QnsConstants#RAT_PREFERENCE_DEFAULT}: Default, Follow the system preference. |
| * <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_ONLY}: If set , choose Wi-Fi always |
| * <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE}: If set , choose Wi-Fi |
| * when the Wi-Fi Calling is available.(when IMS is registered through the Wi-Fi) |
| * <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR}: If set , choose Wi-Fi when |
| * no cellular |
| * <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE}: If set , |
| * choose Wi-Fi when cellular is available at home network. |
| * </ul> |
| */ |
| public static final String KEY_QNS_XCAP_RAT_PREFERENCE_INT = "qns.xcap_rat_preference_int"; |
| |
| /** |
| * Specifies the Rat Preference for the SOS apn type. Boolean indicating adding the IMS |
| * Registration condition to the Wi-Fi Rove in condition. |
| * |
| * <ul> |
| * <li>{@code QnsConstants#RAT_PREFERENCE_DEFAULT}: Default, Follow the system preference. |
| * <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_ONLY}: If set , choose Wi-Fi always |
| * <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE}: If set , choose Wi-Fi |
| * when the Wi-Fi Calling is available.(when IMS is registered through the Wi-Fi) |
| * <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR}: If set , choose Wi-Fi when |
| * no cellular |
| * <li>{@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE}: If set , |
| * choose Wi-Fi when cellular is available at home network. |
| * </ul> |
| */ |
| public static final String KEY_QNS_SOS_RAT_PREFERENCE_INT = "qns.sos_rat_preference_int"; |
| |
| /** |
| * Specifies the Rat Preference for the MMS apn type. Boolean indicating adding the IMS |
| * Registration condition to the Wi-Fi Rove in condition. |
| * |
| * <p>{@code QnsConstants#RAT_PREFERENCE_DEFAULT}: Default value , Follow the system preference. |
| * {@code QnsConstants#RAT_PREFERENCE_WIFI_ONLY}: If set , choose Wi-Fi always {@code |
| * QnsConstants#RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE}: If set , choose Wi-Fi when the Wi-Fi |
| * Calling is available.(when IMS is registered through the Wi-Fi) {@code |
| * QnsConstants#RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR}: If set , choose Wi-Fi when no cellular |
| * {@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE}: If set , choose Wi-Fi |
| * when cellular is available at home network. The default value for this key is {@code |
| * QnsConstants#RAT_PREFERENCE_DEFAULT} |
| */ |
| public static final String KEY_QNS_MMS_RAT_PREFERENCE_INT = "qns.mms_rat_preference_int"; |
| |
| /** |
| * Specifies the Rat Preference for the CBS apn type. Boolean indicating adding the IMS |
| * Registration condition to the Wi-Fi Rove in condition. |
| * |
| * <p>{@code QnsConstants#RAT_PREFERENCE_DEFAULT}: Default value , Follow the system preference. |
| * {@code QnsConstants#RAT_PREFERENCE_WIFI_ONLY}: If set , choose Wi-Fi always {@code |
| * QnsConstants#RAT_PREFERENCE_WIFI_WHEN_WFC_AVAILABLE}: If set , choose Wi-Fi when the Wi-Fi |
| * Calling is available.(when IMS is registered through the Wi-Fi) {@code |
| * QnsConstants#RAT_PREFERENCE_WIFI_WHEN_NO_CELLULAR}: If set , choose Wi-Fi when no cellular |
| * {@code QnsConstants#RAT_PREFERENCE_WIFI_WHEN_HOME_IS_NOT_AVAILABLE}: If set , choose Wi-Fi |
| * when cellular is available at home network. The default value for this key is {@code |
| * QnsConstants#RAT_PREFERENCE_DEFAULT} |
| */ |
| public static final String KEY_QNS_CBS_RAT_PREFERENCE_INT = "qns.cbs_rat_preference_int"; |
| |
| /** |
| * Specifies the interval at which the Wifi Backhaul timer in milli seconds, for threshold Wifi |
| * rssi signal strength fluctuation in case, on meeting the criteria in Rove In Scenario (Moving |
| * to Cellular to Wifi) {@link QnsConstants}. The values are set as below: |
| * |
| * <ul> |
| * <li>0: {@link QnsConstants#DEFAULT_WIFI_BACKHAUL_TIMER} |
| * <li>1: {@link QnsConstants#KEY_DEFAULT_VALUE} |
| * </ul> |
| * |
| * &As per operator Requirements. |
| * |
| * <p>{@code QnsConstants#DEFAULT_WIFI_BACKHAUL_TIMER}: If set , specifies interval of 3secs |
| * running the backhaul check(To avoid Wifi Fluctuation) on meeting the criteria in Rove in case |
| * {@code QnsConstants#KEY_DEFAULT_VALUE}: If set , this feature to be disabled <As per Operator |
| * requirement configurable>: If this value set , specifies interval in milli seconds running |
| * the backhaul check. The default value for this key is {@link |
| * QnsConstants#DEFAULT_WIFI_BACKHAUL_TIMER} |
| */ |
| public static final String KEY_QNS_WIFI_RSSI_THRESHOLDBACKHAUL_TIMER_MS_INT = |
| "qns.wifi_rssi_thresholdbackhaul_timer_int"; |
| |
| /** |
| * Specifies the interval at which the Cellular Backhaul timer in milli seconds for cellular |
| * signal strengths fluctuation in case, on meeting the criteria in Rove out Scenario (Moving to |
| * Wifi from Cellular) The values are set as below: |
| * |
| * <ul> |
| * <li>0: {@link QnsConstants#KEY_DEFAULT_VALUE} |
| * </ul> |
| * |
| * &As per operator Requirements. |
| * |
| * <p>{@code QnsConstants#KEY_DEFAULT_VALUE}: If set , this feature to be disabled <As per |
| * Operator requirement configurable>: If this value set , specifies interval in milli seconds |
| * running the backhaul check over Cellular in Rove Out The default value for this key is {@link |
| * QnsConstants#KEY_DEFAULT_VALUE} |
| */ |
| public static final String KEY_QNS_CELLULAR_SS_THRESHOLDBACKHAUL_TIMER_MS_INT = |
| "qns.cellular_ss_thresholdbackhaul_timer_int"; |
| |
| /** |
| * Specifies the Transport type UE supports with QNS services for IMS APN type. {@link |
| * QnsConstants}. The values are set as below: |
| * |
| * <ul> |
| * <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| * <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN} |
| * <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH} |
| * </ul> |
| * |
| * {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is |
| * cellular for IMS APN Type. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If this value |
| * set , Transport type UE supports is Wifi for IMS APN Type. {@code |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is |
| * both Cellular & Wifi for IMS APN Type The default value for this key is {@link |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH} |
| */ |
| public static final String KEY_QNS_IMS_TRANSPORT_TYPE_INT = "qns.ims_transport_type_int"; |
| |
| /** |
| * Specifies the Transport type UE supports with QNS services for SOS APN type. {@link |
| * QnsConstants}. The values are set as below: |
| * |
| * <ul> |
| * <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| * <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN} |
| * <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH} |
| * </ul> |
| * |
| * {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is |
| * cellular for SOS APN type. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If this value |
| * set , Transport type UE supports is Wifi for SOS APN type. {@code |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is |
| * both Cellular & Wifi for SOS APN type. The default value for this key is {@link |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| */ |
| public static final String KEY_QNS_SOS_TRANSPORT_TYPE_INT = "qns.sos_transport_type_int"; |
| |
| /** |
| * Specifies the Transport type UE supports with QNS services for MMS APN Type. {@link |
| * QnsConstants}. The values are set as below: |
| * |
| * <ul> |
| * <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| * <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN} |
| * <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH} |
| * </ul> |
| * |
| * {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is |
| * cellular for MMS APN Type. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If this value |
| * set , Transport type UE supports is Wifi for MMS APN Type. {@code |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is |
| * both Cellular & Wifi for MMS APN Type. The default value for this key is {@link |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| */ |
| public static final String KEY_QNS_MMS_TRANSPORT_TYPE_INT = "qns.mms_transport_type_int"; |
| |
| /** |
| * Specifies the Transport type UE supports with QNS services for XCAP APN type. {@link |
| * QnsConstants}. The values are set as below: |
| * |
| * <ul> |
| * <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| * <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN} |
| * <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH} |
| * </ul> |
| * |
| * <p>{@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is |
| * cellular for XCAP APN type. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If this value |
| * set , Transport type UE supports is Wifi for XCAP APN type. {@code |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is |
| * both Cellular & Wifi for XCAP APN type. The default value for this key is {@link |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| */ |
| public static final String KEY_QNS_XCAP_TRANSPORT_TYPE_INT = "qns.xcap_transport_type_int"; |
| |
| /** |
| * Specifies the Transport type UE supports with QNS services for CBS APN type. {@link |
| * QnsConstants}. The values are set as below: |
| * |
| * <ul> |
| * <li>0: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| * <li>1: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN} |
| * <li>2: {@link QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH} |
| * </ul> |
| * |
| * {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN}: If set , Transport type UE supports is |
| * cellular for CBS APN type. {@code QnsConstants#TRANSPORT_TYPE_ALLOWED_IWLAN}: If this value |
| * set , Transport type UE supports is Wifi for CBS APN type. {@code |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_BOTH}: If this value set , Transport type UE supports is |
| * both Cellular & Wifi for CBS APN type. The default value for this key is {@link |
| * QnsConstants#TRANSPORT_TYPE_ALLOWED_WWAN} |
| */ |
| public static final String KEY_QNS_CBS_TRANSPORT_TYPE_INT = "qns.cbs_transport_type_int"; |
| |
| /** |
| * For IMS PDN, specify a list of the hysteresis timer(millisecond) for handover from WLAN and |
| * WWAN to avoid ping-pong effect. |
| * |
| * <ul> |
| * <li>Index 0: The hysteresis timer for handover from WLAN and WWAN in idle state. |
| * <li>Index 1: The hysteresis timer for handover from WLAN and WWAN in voice call state. |
| * <li>Index 2: The hysteresis timer for handover from WLAN and WWAN in video call state. |
| * </ul> |
| * |
| * <p>The default values are {@link QnsConstants#KEY_DEFAULT_HYST_TIMER} |
| */ |
| public static final String KEY_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY = |
| "qns.ims_wwan_hysteresis_timer_ms_int_array"; |
| |
| /** |
| * For IMS PDN, specify a list of the hysteresis timer(millisecond) for handover from WWAN and |
| * WLAN to avoid ping-pong effect. |
| * |
| * <ul> |
| * <li>Index 0: The hysteresis timer for handover from WWAN and WLAN in idle state. |
| * <li>Index 1: The hysteresis timer for handover from WWAN and WLAN in voice call state. |
| * <li>Index 2: The hysteresis timer for handover from WWAN and WLAN in video call state. |
| * </ul> |
| * |
| * <p>The default values are {@link QnsConstants#KEY_DEFAULT_HYST_TIMER} |
| */ |
| public static final String KEY_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY = |
| "qns.ims_wlan_hysteresis_timer_ms_int_array"; |
| |
| /** |
| * Location(HOME/ROAM) of using handover hysteresis timer |
| * <li>0: {@link QnsConstants#COVERAGE_HOME} |
| * <li>1: {@link QnsConstants#COVERAGE_ROAM} |
| * <li>2: {@link QnsConstants#COVERAGE_BOTH} The default value for this key is {@link |
| * QnsConstants#COVERAGE_BOTH} |
| */ |
| public static final String KEY_QNS_IMS_NETWORK_ENABLE_HO_HYSTERESIS_TIMER_INT = |
| "qns.ims_network_enable_hysteresis_timer_int"; |
| |
| /** |
| * For MMS, XCAP and CBS PDNs, specify a list of the hysteresis timer(millisecond) for handover |
| * from WLAN and WWAN to avoid ping-pong effect. |
| * |
| * <ul> |
| * <li>Index 0: The hysteresis timer for handover from WLAN to WWAN in idle state. |
| * <li>Index 1: The hysteresis timer for handover from WLAN to WWAN in call state. |
| * </ul> |
| * |
| * <p>The default values are {@link QnsConstants#KEY_DEFAULT_VALUE} |
| */ |
| public static final String KEY_NON_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY = |
| "qns.non_ims_wwan_hysteresis_timer_ms_int_array"; |
| |
| /** |
| * For MMS, XCAP and CBS PDNs, specify a list of the hysteresis timer(millisecond) for handover |
| * from WWAN and WLAN to avoid ping-pong effect. |
| * |
| * <ul> |
| * <li>Index 0: The hysteresis timer for handover from WWAN and WLAN in idle state. |
| * <li>Index 1: The hysteresis timer for handover from WWAN and WLAN in call state. |
| * </ul> |
| * |
| * <p>The default values are {@link QnsConstants#KEY_DEFAULT_VALUE} |
| */ |
| public static final String KEY_NON_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY = |
| "qns.non_ims_wlan_hysteresis_timer_ms_int_array"; |
| |
| /** |
| * List of 4 items indicating the RTP media metrics criteria to be set ,to make HO decision |
| * during Call. The three items part of integer array is jitter , Packet loss rate & RTP |
| * interval. |
| * |
| * <p>{@link QnsConstants}. The values are set as below: |
| * |
| * <ul> |
| * <li>0: {@link QnsConstants#KEY_DEFAULT_JITTER} |
| * <li>1: {@link QnsConstants#KEY_DEFAULT_PACKET_LOSS_RATE} |
| * <li>2: {@link QnsConstants#KEY_DEFAULT_PACKET_LOSS_TIME_MILLIS} |
| * <li>3: {@link QnsConstants#KEY_DEFAULT_NO_RTP_INTERVAL_MILLIS} |
| * </ul> |
| * |
| * {@code QnsConstants#KEY_DEFAULT_JITTER , QnsConstants#KEY_DEFAULT_PACKET_LOSS_RATE , |
| * QnsConstants#KEY_DEFAULT_NO_RTP_INTERVAL }: If set , indicates the jitter : Indicating the |
| * latentcy , Packet loss rate : Indicating the percentage loss & RTP interval indicating the |
| * interval in secs criteria to determine the HO decision . The default value for this key is |
| * {@code QnsConstants#KEY_DEFAULT_JITTER, QnsConstants#KEY_DEFAULT_PACKET_LOSS_RATE, |
| * QnsConstants#KEY_DEFAULT_PACKET_LOSS_TIME_MILLIS, |
| * QnsConstants#KEY_DEFAULT_NO_RTP_INTERVAL_MILLIS} |
| */ |
| public static final String KEY_QNS_RTP_METRICS_INT_ARRAY = "qns.rtp_metrics_int_array"; |
| |
| /** |
| * Specify a list of the waiting time(millisecond) for the preferred transport type when power |
| * up. |
| * |
| * <ul> |
| * <li>Index 0: The waiting time for WWAN in cellular preferred mode. |
| * <li>Index 1: The waiting time for WLAN in WiFi preferred mode. |
| * </ul> |
| * |
| * <p>The default values are all {@link QnsConstants#KEY_DEFAULT_VALUE} |
| * |
| * <p>For example, if set 45000ms in the index 0 of this list, WLAN will be restricted 45000ms |
| * in cellular preferred mode when power up, and the timer will be canceled if IMS PDN is |
| * connected on WWAN within 45000ms. |
| */ |
| public static final String KEY_WAITING_TIME_FOR_PREFERRED_TRANSPORT_WHEN_POWER_ON_INT_ARRAY = |
| "qns.waiting_time_for_preferred_transport_when_power_on_int_array"; |
| |
| /** |
| * Specifies the number of count allowed IWLAN on HO to cellular during call due to fallback |
| * reason such as Wifi bad or RTP Low Quality Criteria |
| * |
| * <p>The Possible values are set as below: <rovein_count_allowed,rove_outfallback_reason |
| * |
| * <ul> |
| * <li><-1,-1></-1,-1>:{@link QnsConstants#MAX_COUNT_INVALID,QnsConstants#MAX_COUNT_INVALID} |
| * </ul> |
| * |
| * & As per operator Requirements (Ex: 3,1 or 1,2) |
| * |
| * <p>The default value for this key is {@link QnsConstants#MAX_COUNT_INVALID, |
| * QnsConstants#FALLBACK_REASON_INVALID} |
| */ |
| public static final String KEY_QNS_IN_CALL_ROVEIN_ALLOWED_COUNT_AND_FALLBACK_REASON_INT_ARRAY = |
| "qns.in_call_rovein_allowed_and_fallback_reason_int_array"; |
| |
| /** |
| * Specifies the number of count allowed IWLAN on HO to cellular during call due to fallback |
| * reason such as Wifi bad or RTP Low Quality Criteria |
| * |
| * <p>The Possible values are set as below: |
| * |
| * <ul> |
| * <li>Index 0: The waiting time for WLAN //If set to 0 , feature is disabled for WLAN-WWAN |
| * <li>Index 1: The waiting time for WWAN //If set to 0 , feature is disabled for WWAN-WLAN |
| * </ul> |
| * |
| * The default value for this key is {@link |
| * QnsConstants#KEY_DEFAULT_IWLAN_AVOID_TIME_LOW_RTP_QUALITY_MILLIS, |
| * QnsConstants#KEY_DEFAULT_VALUE} |
| */ |
| public static final String KEY_QNS_HO_RESTRICT_TIME_WITH_LOW_RTP_QUALITY_MILLIS_INT_ARRAY = |
| "qns.ho_restrict_time_with_low_rtp_quality_int_array"; |
| |
| /** |
| * Specify if choosing the transport type based on WFC preference mode when both WWAN and WLAN |
| * are not able to meet service requirements. |
| * |
| * <p>The possible values are set as below: |
| * |
| * <ul> |
| * <li>1: {@link ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED} |
| * <li>2: {@link ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED} |
| * </ul> |
| * |
| * {@code ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}: Only apply the design when WFC |
| * preference mode is cellular preferred. Choose WWAN when cellular preferred and both WWAN and |
| * WLAN are in bad condition. {@code ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}: Only apply the |
| * design when WFC preference mode is WiFi preferred. Choose WLAN when WiFi preferred and both |
| * WWAN and WLAN are in bad condition. |
| * |
| * <p>If set to {ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED, |
| * ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}, the design will apply on both cellular and WiFi |
| * preference mode. |
| * |
| * <p>The default value for this key is empty. An empty array indicates staying on the current |
| * transport when both WWAN and WLAN are not able to meet service requirements. |
| */ |
| public static final String KEY_CHOOSE_WFC_PREFERRED_TRANSPORT_IN_BOTH_BAD_CONDITION_INT_ARRAY = |
| "qns.choose_wfc_preferred_transport_in_both_bad_condition_int_array"; |
| |
| /** |
| * List of Array items indicating APN Types with fallback support based on retry count or retry |
| * timer or either of them with fallback guard timer to be set |
| * |
| *<p><string-array name="qns.fallback_on_initial_connection_failure_string_array" num="2"> |
| * <item value="<apn_type>:<retry_count>:<retry_timer>:<fallback_guard_timer>"/> |
| * <item value="ims:3:60000:10000"/> |
| * |
| * <p>The default value for this key is null indicating not enabled by default for fallback in |
| * case of initial connection failure |
| */ |
| public static final String KEY_QNS_FALLBACK_ON_INITIAL_CONNECTION_FAILURE_STRING_ARRAY = |
| "qns.fallback_on_initial_connection_failure_string_array"; |
| |
| /** |
| * List of Array items indicating the Access Network Allowed For IMS APN Type. The values are |
| * set as below: "LTE" "NR" "3G" "2G" The default value for this key is {@Code "LTE","NR"} |
| */ |
| public static final String KEY_IMS_CELLULAR_ALLOWED_RAT_STRING_ARRAY = |
| "qns.ims_cellular_allowed_rat_string_array"; |
| |
| /** |
| * List of Array items indicating the Access Network Allowed For IMS APN Type. The values are |
| * set as below: Format "<accessNetwork>:<meas_type>:<gap>" "eutran:rsrp:-2" "ngran:ssrsrp:2" |
| * Note: Similar format followed across different accessNetwork & Measurement TYpes The default |
| * value for this key is {@Code ""} |
| */ |
| public static final String KEY_QNS_ROVEIN_THRESHOLD_GAP_WITH_GUARD_TIMER_STRING_ARRAY = |
| "qns.rove_in_threshold_gap_with_guard_timer_string_array"; |
| |
| /** |
| * List of Array items indicating IMS unregistered cause & time(millis) for fallback (to WWAN). |
| * |
| * <p><string-array name="qns.fallback_wwan_ims_unregistration_reason_string_array" num="2"> |
| * <!-- fallback WWAN with ImsReason 321~378,1503 during 60sec at cellular prefer mode --> |
| * <item value="cause=321~378|1503, time=60000, preference=cell"/> |
| * <!-- fallback WWAN with ImsReason 240,243,323~350 during 90sec --> |
| * <item value="cause=240|243|323~350, time=90000"/> </string-array> |
| * |
| * <p>The default value for this key is {@Code ""} |
| */ |
| public static final String KEY_QNS_FALLBACK_WWAN_IMS_UNREGISTRATION_REASON_STRING_ARRAY = |
| "qns.fallback_wwan_ims_unregistration_reason_string_array"; |
| |
| /** |
| * List of Array items indicating IMS HO registration fail cause & time(millis) for fallback (to |
| * WWAN). |
| * |
| * <p><string-array name="qns.fallback_wwan_ims_ho_reigster_fail_reason_string_array" num="2"> |
| * <!-- fallback WWAN with ImsReason 321~378,1503 during 60sec at cellular prefer mode --> |
| * <item value="cause=321~378|1503, time=60000, preference=cell"/> |
| * <!-- fallback WWAN with ImsReason 240,243,323~350 during 90sec --> |
| * <item value="cause=240|243|323~350, time=90000"/> </string-array> |
| * |
| * <p>The default value for this key is {@Code ""} |
| */ |
| public static final String KEY_QNS_FALLBACK_WWAN_IMS_HO_REGISTER_FAIL_REASON_STRING_ARRAY = |
| "qns.fallback_wwan_ims_ho_reigster_fail_reason_string_array"; |
| |
| /** |
| * String array indicating APN types that they check international roaming condition. |
| * |
| * <string-array name="exclude_domestic_roaming_condition_string_array" num="3"> |
| * <item value="ims"/> |
| * <item value="emergency"/> |
| * <item value="xcap"/> |
| * </string-array> |
| */ |
| public static final String KEY_APN_TYPES_WITH_INTERNATIONAL_ROAMING_CONDITION_STRING_ARRAY = |
| "qns.apn_types_with_international_roaming_condition_string_array"; |
| |
| /** |
| * String array indicating PLMN list to be regarded as international roaming. |
| * |
| * <p> If only MCC is included without MNC, PLMNs that they have same MCC value will be |
| * regarded as international roaming. |
| * <string-array name="plmn_list_regarded_as_international_roaming_string_array" num="3"> |
| * <item value="32070"/> |
| * <item value="320157"/> |
| * <item value="318"/> |
| * </string-array> |
| */ |
| public static final String KEY_PLMN_LIST_REGARDED_AS_INTERNATIONAL_ROAMING_STRING_ARRAY = |
| "plmn_list_regarded_as_international_roaming_string_array"; |
| |
| /** |
| * String array indicating PLMN list to be regarded as domestic roaming. |
| * |
| * <p> If only MCC is included without MNC, PLMNs that they have same MCC value will be |
| * regarded as domestic roaming. |
| * <string-array name="plmn_list_regarded_as_domestic_roaming_string_array" num="3"> |
| * <item value="32070"/> |
| * <item value="320157"/> |
| * <item value="318"/> |
| * </string-array> |
| */ |
| public static final String KEY_PLMN_LIST_REGARDED_AS_DOMESTIC_ROAMING_STRING_ARRAY = |
| "plmn_list_regarded_as_domestic_roaming_string_array"; |
| |
| private static final SparseArray<QnsCarrierConfigManager> mQnsCarrierConfigManagers = |
| new SparseArray<>(); |
| |
| static HashMap<Integer, String> accessnetworkMap = |
| new HashMap<Integer, String>() { |
| { |
| put(AccessNetworkConstants.AccessNetworkType.EUTRAN, "eutran"); |
| put(AccessNetworkConstants.AccessNetworkType.UTRAN, "utran"); |
| put(AccessNetworkConstants.AccessNetworkType.NGRAN, "ngran"); |
| put(AccessNetworkConstants.AccessNetworkType.GERAN, "geran"); |
| put(AccessNetworkConstants.AccessNetworkType.IWLAN, "wifi"); |
| } |
| }; |
| |
| static HashMap<Integer, String> measTypeMap = |
| new HashMap<Integer, String>() { |
| { |
| put(SIGNAL_MEASUREMENT_TYPE_RSRP, "rsrp"); |
| put(SIGNAL_MEASUREMENT_TYPE_RSRQ, "rsrq"); |
| put(SIGNAL_MEASUREMENT_TYPE_RSSNR, "rssnr"); |
| put(SIGNAL_MEASUREMENT_TYPE_SSRSRP, "ssrsrp"); |
| put(SIGNAL_MEASUREMENT_TYPE_SSRSRQ, "ssrsrq"); |
| put(SIGNAL_MEASUREMENT_TYPE_SSSINR, "sssinr"); |
| put(SIGNAL_MEASUREMENT_TYPE_RSCP, "rscp"); |
| put(SIGNAL_MEASUREMENT_TYPE_RSSI, "rssi"); |
| put(SIGNAL_MEASUREMENT_TYPE_ECNO, "ecno"); |
| } |
| }; |
| |
| static HashMap<Integer, String> callTypeMap = |
| new HashMap<Integer, String>() { |
| { |
| put(QnsConstants.CALL_TYPE_IDLE, "idle"); |
| put(QnsConstants.CALL_TYPE_VOICE, "voice"); |
| put(QnsConstants.CALL_TYPE_VIDEO, "video"); |
| } |
| }; |
| |
| private final String LOG_TAG; |
| private final int mSlotIndex; |
| private final Context mContext; |
| protected int mSubId; |
| protected int mCurrCarrierId; |
| private final QnsEventDispatcher mQnsEventDispatcher; |
| private final QnsCarrierAnspSupportConfig mAnspConfigMgr; |
| @VisibleForTesting final Handler mHandler; |
| |
| private boolean mIsWfcInAirplaneModeOnSupport; |
| private boolean mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported; |
| private boolean mIsHoGuardOnPreferenceSupport; |
| private boolean mIsServiceBarringCheckSupport; |
| private boolean mIsVideoOverIWLANWithCellularCheckSupport; |
| private boolean mIsRoveOutWifiBadGuardTimerConditionsSupported; |
| private boolean mIsAllowImsOverIwlanCellularLimitedCase; |
| private boolean mIsBlockIwlanInInternationalRoamWithoutWwan; |
| private boolean mIsBlockIpv6OnlyWifi; |
| private boolean mIsVolteRoamingSupported; |
| private final boolean[] anspSupportConfigArray = new boolean[3]; |
| |
| private int mWifiThresBackHaulTimer; |
| private int mCellularThresBackHaulTimer; |
| private int mQnsImsTransportType; |
| private int mQnsSosTransportType; |
| private int mQnsMmsTransportType; |
| private int mQnsXcapTransportType; |
| private int mQnsCbsTransportType; |
| private int mXcapRatPreference; |
| private int mSosRatPreference; |
| private int mMmsRatPreference; |
| private int mCbsRatPreference; |
| private int mNetworkEnableHysteresisTimer; |
| |
| private int[] mWwanHysteresisTimer; |
| private int[] mWlanHysteresisTimer; |
| private int[] mNonImsWwanHysteresisTimer; |
| private int[] mNonImsWlanHysteresisTimer; |
| private int[] mRTPMetricsData; |
| private int[] mWaitingTimerForPreferredTransport; |
| private int[] mAllowMaxIwlanHoCountOnReason; |
| private int[] mHoRestrictTimeOnRtpQuality; |
| private int[] mIsMmtelCapabilityRequired; |
| private int[] mIsWfcPreferredTransportRequired; |
| |
| private String[] mImsAllowedRats; |
| private String[] mRoveInGuardTimerConditionThresholdGaps; |
| private String[] mApnTypesInternationalRoamingCheck; |
| private String[] mPlmnsRegardedAsDomesticRoaming; |
| private String[] mPlmnsRegardedAsInternationalRoaming; |
| private String[] mFallbackOnInitialConnectionFailure; |
| |
| private @NonNull final List<FallbackRule> mFallbackWwanRuleWithImsUnregistered = |
| new ArrayList<>(); |
| private @NonNull final List<FallbackRule> mFallbackWwanRuleWithImsHoRegisterFail = |
| new ArrayList<>(); |
| |
| /** Rules for handover between IWLAN and cellular network. */ |
| private @NonNull List<HandoverRule> mHandoverRuleList = new ArrayList<>(); |
| |
| protected RegistrantList mQnsCarrierConfigLoadedRegistrants = new RegistrantList(); |
| protected RegistrantList mQnsCarrierConfigChangedRegistrants = new RegistrantList(); |
| |
| protected QnsProvisioningListener.QnsProvisioningInfo mQnsProvisioningInfo = |
| new QnsProvisioningListener.QnsProvisioningInfo(); |
| |
| public void setQnsProvisioningInfo(QnsProvisioningListener.QnsProvisioningInfo info) { |
| mQnsProvisioningInfo = info; |
| } |
| |
| private QnsConfigArray applyProvisioningInfo( |
| QnsConfigArray thresholds, int accessNetwork, int measurementType, int callType) { |
| |
| if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_1) |
| && thresholds.mBad != QnsConfigArray.INVALID |
| && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN |
| && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) { |
| int bad = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_1); |
| Log.d(LOG_TAG, "provisioning bad THLTE1 old:" + thresholds.mBad + " new:" + bad); |
| thresholds.mBad = bad; |
| } |
| if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_2) |
| && thresholds.mWorst != QnsConfigArray.INVALID |
| && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN |
| && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) { |
| int worst = |
| mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_2); |
| Log.d(LOG_TAG, "provisioning worst THLTE2 old:" + thresholds.mWorst + " new:" + worst); |
| thresholds.mWorst = worst; |
| } |
| if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_THRESHOLD_3) |
| && thresholds.mGood != QnsConfigArray.INVALID |
| && accessNetwork == AccessNetworkConstants.AccessNetworkType.EUTRAN |
| && measurementType == SIGNAL_MEASUREMENT_TYPE_RSRP) { |
| int good = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_THRESHOLD_3); |
| Log.d(LOG_TAG, "provisioning good THLTE3 old:" + thresholds.mGood + " new:" + good); |
| thresholds.mGood = good; |
| } |
| if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_THRESHOLD_A) |
| && thresholds.mGood != QnsConfigArray.INVALID |
| && accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN |
| && measurementType == SIGNAL_MEASUREMENT_TYPE_RSSI) { |
| int good = |
| mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_THRESHOLD_A); |
| Log.d(LOG_TAG, "provisioning good VOWT_A old:" + thresholds.mGood + " new:" + good); |
| thresholds.mGood = good; |
| } |
| if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_THRESHOLD_B) |
| && thresholds.mBad != QnsConfigArray.INVALID |
| && accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN |
| && measurementType == SIGNAL_MEASUREMENT_TYPE_RSSI) { |
| int bad = mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_THRESHOLD_B); |
| Log.d(LOG_TAG, "provisioning bad VOWT_B old:" + thresholds.mBad + " new:" + bad); |
| thresholds.mBad = bad; |
| // TODO : make video threshold gap config, and move in getThreshold...() |
| if (getCarrierId() == 1839 && callType == QnsConstants.CALL_TYPE_VIDEO) { |
| thresholds.mBad = bad + 5; |
| } |
| } |
| |
| return thresholds; |
| } |
| |
| public static class FallbackRule { |
| /** Key : IMS registration fail reason, value : fallback time in millis */ |
| final Set<Integer> mReasons; |
| |
| final int mBackoffTimeMillis; |
| final int mPreferenceMode; |
| |
| FallbackRule(Set<Integer> reasons, int backoffTimeMillis, int preferenceMode) { |
| mReasons = reasons; |
| mBackoffTimeMillis = backoffTimeMillis; |
| mPreferenceMode = preferenceMode; |
| } |
| |
| int getFallBackTime(int reason) { |
| if (mReasons.contains(reason)) { |
| return mBackoffTimeMillis; |
| } else { |
| return 0; |
| } |
| } |
| |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| builder.append("FallbackRule time:" + mBackoffTimeMillis); |
| if (mPreferenceMode == -1) { |
| builder.append(" "); |
| } else if (mPreferenceMode == QnsConstants.CELL_PREF) { |
| builder.append(" " + "CELL_PREF_MODE"); |
| } else if (mPreferenceMode == QnsConstants.WIFI_PREF) { |
| builder.append(" " + "WIFI_PREF_MODE"); |
| } |
| builder.append(" reasons:"); |
| for (Integer i : mReasons) { |
| builder.append(i + " "); |
| } |
| return builder.toString(); |
| } |
| } |
| |
| public static class HandoverRule { |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"RULE_TYPE_"}, |
| value = { |
| RULE_TYPE_ALLOWED, |
| RULE_TYPE_DISALLOWED, |
| }) |
| public @interface HandoverRuleType {} |
| |
| /** Indicating this rule is for allowing handover. */ |
| public static final int RULE_TYPE_ALLOWED = 1; |
| |
| /** Indicating this rule is for disallowing handover. */ |
| public static final int RULE_TYPE_DISALLOWED = 2; |
| |
| private static final String RULE_TAG_SOURCE_ACCESS_NETWORKS = "source"; |
| |
| private static final String RULE_TAG_TARGET_ACCESS_NETWORKS = "target"; |
| |
| private static final String RULE_TAG_TYPE = "type"; |
| |
| private static final String RULE_TAG_CAPABILITIES = "capabilities"; |
| |
| private static final String RULE_TAG_ROAMING = "roaming"; |
| |
| /** Handover rule type. */ |
| public final @HandoverRuleType int type; |
| |
| /** The applicable source access networks for handover. */ |
| public final @NonNull @AccessNetworkConstants.RadioAccessNetworkType Set<Integer> |
| sourceAccessNetworks; |
| |
| /** The applicable target access networks for handover. */ |
| public final @NonNull @AccessNetworkConstants.RadioAccessNetworkType Set<Integer> |
| targetAccessNetworks; |
| |
| /** |
| * The network capabilities to any of which this handover rule applies. If is empty, then |
| * capability is ignored as a rule matcher. |
| */ |
| public final @NonNull @NetCapability Set<Integer> networkCapabilities; |
| |
| /** {@code true} indicates this policy is only applicable when the device is roaming. */ |
| public final boolean isOnlyForRoaming; |
| |
| /** |
| * Constructor |
| * |
| * @param ruleString The rule in string format. |
| * @see CarrierConfigManager#KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY |
| */ |
| public HandoverRule(@NonNull String ruleString) { |
| if (TextUtils.isEmpty(ruleString)) { |
| throw new IllegalArgumentException("illegal rule " + ruleString); |
| } |
| |
| Set<Integer> source = null, target = null, capabilities = Collections.emptySet(); |
| int type = 0; |
| boolean roaming = false; |
| |
| ruleString = ruleString.trim().toLowerCase(Locale.ROOT); |
| String[] expressions = ruleString.split("\\s*,\\s*"); |
| for (String expression : expressions) { |
| String[] tokens = expression.trim().split("\\s*=\\s*"); |
| if (tokens.length != 2) { |
| throw new IllegalArgumentException( |
| "illegal rule " + ruleString + ", tokens=" + Arrays.toString(tokens)); |
| } |
| String key = tokens[0].trim(); |
| String value = tokens[1].trim(); |
| try { |
| switch (key) { |
| case RULE_TAG_SOURCE_ACCESS_NETWORKS: |
| source = |
| Arrays.stream(value.split("\\s*\\|\\s*")) |
| .map(String::trim) |
| .map(QnsConstants::accessNetworkTypeFromString) |
| .collect(Collectors.toSet()); |
| break; |
| case RULE_TAG_TARGET_ACCESS_NETWORKS: |
| target = |
| Arrays.stream(value.split("\\s*\\|\\s*")) |
| .map(String::trim) |
| .map(QnsConstants::accessNetworkTypeFromString) |
| .collect(Collectors.toSet()); |
| break; |
| case RULE_TAG_TYPE: |
| if (value.toLowerCase(Locale.ROOT).equals("allowed")) { |
| type = RULE_TYPE_ALLOWED; |
| } else if (value.toLowerCase(Locale.ROOT).equals("disallowed")) { |
| type = RULE_TYPE_DISALLOWED; |
| } else { |
| throw new IllegalArgumentException("unexpected rule type " + value); |
| } |
| break; |
| case RULE_TAG_CAPABILITIES: |
| capabilities = QnsUtils.getNetworkCapabilitiesFromString(value); |
| break; |
| case RULE_TAG_ROAMING: |
| roaming = Boolean.parseBoolean(value); |
| break; |
| default: |
| throw new IllegalArgumentException("unexpected key " + key); |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| throw new IllegalArgumentException( |
| "illegal rule \"" + ruleString + "\", e=" + e); |
| } |
| } |
| |
| if (source == null || target == null || source.isEmpty() || target.isEmpty()) { |
| throw new IllegalArgumentException( |
| "Need to specify both source and target. " + "\"" + ruleString + "\""); |
| } |
| |
| if (source.contains(AccessNetworkConstants.AccessNetworkType.UNKNOWN)) { |
| throw new IllegalArgumentException( |
| "Source access networks contains unknown. " + "\"" + ruleString + "\""); |
| } |
| |
| if (target.contains(AccessNetworkConstants.AccessNetworkType.UNKNOWN)) { |
| throw new IllegalArgumentException( |
| "Target access networks contains unknown. " + "\"" + ruleString + "\""); |
| } |
| |
| if (type == 0) { |
| throw new IllegalArgumentException( |
| "Rule type is not specified correctly. " + "\"" + ruleString + "\""); |
| } |
| |
| if (capabilities != null && capabilities.contains(-1)) { |
| throw new IllegalArgumentException( |
| "Network capabilities contains unknown. " + "\"" + ruleString + "\""); |
| } |
| |
| if (!source.contains(AccessNetworkConstants.AccessNetworkType.IWLAN) |
| && !target.contains(AccessNetworkConstants.AccessNetworkType.IWLAN)) { |
| throw new IllegalArgumentException( |
| "IWLAN must be specified in either source or " |
| + "target access networks.\"" |
| + ruleString |
| + "\""); |
| } |
| |
| sourceAccessNetworks = source; |
| targetAccessNetworks = target; |
| this.type = type; |
| networkCapabilities = capabilities; |
| isOnlyForRoaming = roaming; |
| } |
| |
| @Override |
| public String toString() { |
| return "[HandoverRule: type=" |
| + (type == RULE_TYPE_ALLOWED ? "allowed" : "disallowed") |
| + ", source=" |
| + sourceAccessNetworks.stream() |
| .map(QnsConstants::accessNetworkTypeToString) |
| .collect(Collectors.joining("|")) |
| + ", target=" |
| + targetAccessNetworks.stream() |
| .map(QnsConstants::accessNetworkTypeToString) |
| .collect(Collectors.joining("|")) |
| + ", isRoaming=" |
| + isOnlyForRoaming |
| + ", capabilities=" |
| + QnsUtils.networkCapabilitiesToString(networkCapabilities) |
| + "]"; |
| } |
| } |
| |
| private class QnsCarrierConfigChangeHandler extends Handler { |
| public QnsCarrierConfigChangeHandler(Looper looper) { |
| super(looper); |
| } |
| |
| @Override |
| public void handleMessage(Message message) { |
| switch (message.what) { |
| case QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED: |
| Log.d(LOG_TAG, "Event Received QNS_EVENT_CARRIER_CONFIG_CHANGED"); |
| if (SubscriptionManager.isValidSubscriptionId(getSubId())) { |
| int mNewCarrierID = getCarrierId(); |
| Log.d(LOG_TAG, "new carrier id " + mNewCarrierID); |
| Log.d(LOG_TAG, "current carrier id " + mCurrCarrierId); |
| if (mNewCarrierID != 0 && mNewCarrierID != UNKNOWN_CARRIER_ID) { |
| if (mCurrCarrierId != mNewCarrierID) { |
| mCurrCarrierId = mNewCarrierID; |
| loadQnsConfigurations(); |
| notifyLoadQnsConfigurationsCompleted(); |
| } else { |
| if (isQnsConfigChanged()) { |
| Log.d(LOG_TAG, "Qns Carrier config updated found"); |
| notifyQnsConfigurationsChanged(); |
| } |
| } |
| } |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Constructor to Initial Slot and Context whose carrier config ID needs to be loaded along with |
| * initialising the Action Intent on which Carrier Config ID to be loaded. |
| * |
| * @param slotIndex : Constructor for initialising the current Slot ID |
| * @param context : Constructor for initialising the current context |
| */ |
| private QnsCarrierConfigManager(int slotIndex, Context context) { |
| LOG_TAG = |
| QnsConstants.QNS_TAG |
| + "_" |
| + QnsCarrierConfigManager.class.getSimpleName() |
| + "_" |
| + slotIndex; |
| mQnsEventDispatcher = QnsEventDispatcher.getInstance(context, slotIndex); |
| mAnspConfigMgr = QnsCarrierAnspSupportConfig.getInstance(context, slotIndex); |
| mSlotIndex = slotIndex; |
| mContext = context; |
| |
| HandlerThread handlerThread = new HandlerThread(LOG_TAG); |
| handlerThread.start(); |
| mHandler = |
| new QnsCarrierConfigManager.QnsCarrierConfigChangeHandler( |
| handlerThread.getLooper()); |
| |
| List<Integer> events = new ArrayList<>(); |
| events.add(QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED); |
| mQnsEventDispatcher.registerEvent(events, mHandler); |
| |
| // sending empty message when new object created; as actual event will not be received in |
| // case QNS restarts. |
| // This EVENT will not be processed in bootup case since carrier id will be invalid until |
| // actual event received from QnsEventDispatcher. |
| mHandler.sendEmptyMessage(QnsEventDispatcher.QNS_EVENT_CARRIER_CONFIG_CHANGED); |
| |
| // To do : Update based on xml version Changes handling |
| // To do : Operator Update on Threshold changes handling |
| } |
| |
| /** |
| * Below API is exposed to other classes in QNS package to register for carrier config Loading |
| * corresponding key items from xml/bundle date based on NetworkProviderImpl |
| * |
| * @param context : Context at which QNSCarrierConfigManager instance to be created |
| * @param slotIndex : slot ID at which QNSCarrierConfigManager instance to be created |
| */ |
| public static QnsCarrierConfigManager getInstance(Context context, int slotIndex) { |
| QnsCarrierConfigManager qnsCarrierConfigManager = mQnsCarrierConfigManagers.get(slotIndex); |
| if (qnsCarrierConfigManager != null) { |
| return qnsCarrierConfigManager; |
| } |
| qnsCarrierConfigManager = new QnsCarrierConfigManager(slotIndex, context); |
| mQnsCarrierConfigManagers.put(slotIndex, qnsCarrierConfigManager); |
| return qnsCarrierConfigManager; |
| } |
| |
| /** |
| * Below API is exposed to other classes in QNS package, to close QNS carrier config manager |
| * mapped to slot index & remove the Access Network Selection Policies |
| * |
| * @param slotIndex : slot ID at which QNSCarrierConfigManager to be cloed |
| */ |
| public static void closeQnsCarrierConfigManager(int slotIndex) { |
| QnsCarrierConfigManager cm = mQnsCarrierConfigManagers.get(slotIndex); |
| if (cm != null) { |
| mQnsCarrierConfigManagers.remove(slotIndex); |
| cm.close(); |
| } |
| } |
| |
| /** Below API clears the current Access Network selection Policies */ |
| public void close() { |
| if (mHandler != null) mQnsEventDispatcher.unregisterEvent(mHandler); |
| mAnspConfigMgr.close(); |
| mQnsCarrierConfigManagers.remove(mSlotIndex); |
| } |
| |
| public synchronized PersistableBundle readFromCarrierConfigManager( |
| Context context, int slotidx) { |
| PersistableBundle carrierConfigbundle = new PersistableBundle(); |
| CarrierConfigManager carrierConfigManager = |
| context.getSystemService(CarrierConfigManager.class); |
| |
| if (carrierConfigManager == null) { |
| throw new IllegalStateException("Carrier config manager is null."); |
| } |
| carrierConfigbundle = carrierConfigManager.getConfigForSubId(getSubId()); |
| |
| return carrierConfigbundle; |
| } |
| |
| public synchronized PersistableBundle readFromAssets(Context context, int slotidx) { |
| PersistableBundle assetBundle = new PersistableBundle(); |
| |
| assetBundle = QnsUtils.readQnsDefaultConfigFromAssets(context, mCurrCarrierId); |
| |
| if (assetBundle == null) { |
| throw new IllegalStateException("Carrier config manager is null."); |
| } |
| |
| return assetBundle; |
| } |
| |
| /** Below API is used for Loading the carrier configurations based on Current Carrier ID */ |
| public void loadQnsConfigurations() { |
| |
| PersistableBundle carrierConfigBundle = readFromCarrierConfigManager(mContext, mSlotIndex); |
| Log.d(LOG_TAG, "CarrierConfig Bundle for Slot: " + mSlotIndex + carrierConfigBundle); |
| |
| PersistableBundle assetConfigBundle = readFromAssets(mContext, mSlotIndex); |
| Log.d(LOG_TAG, "AssetConfig Bundle for Slot: " + mSlotIndex + assetConfigBundle); |
| |
| // load configurations supporting ANE |
| loadQnsAneSupportConfigurations(carrierConfigBundle, assetConfigBundle); |
| |
| // load qns Ansp (Access Network Selection Policy) carrier Support Configurations |
| // for building Internal ANSP Policies |
| loadAnspCarrierSupportConfigs(carrierConfigBundle, assetConfigBundle); |
| |
| mAnspConfigMgr.loadQnsAnspSupportArray(carrierConfigBundle, assetConfigBundle); |
| |
| // Load configs using Carrier Config Manager Keys |
| loadDirectFromCarrierConfigManagerKey(carrierConfigBundle); |
| } |
| |
| /** |
| * Below API takes care of loading the configuration based on the carrier config Manager |
| * available for given carrier config manager keys. |
| */ |
| public void loadDirectFromCarrierConfigManagerKey(PersistableBundle bundleCarrier) { |
| loadHandoverRules( |
| bundleCarrier, null, CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY); |
| loadCarrierConfig(bundleCarrier, null); |
| } |
| |
| /** |
| * Below API takes care of validating the configs (Threshold & HO rules) Updates after loading |
| * Qns configurations, for the current operator in use, in case of config update scenario |
| * |
| * @return : true/false |
| */ |
| public synchronized boolean isQnsConfigChanged() { |
| PersistableBundle carrierConfigBundle = readFromCarrierConfigManager(mContext, mSlotIndex); |
| Log.d( |
| LOG_TAG, |
| "Check carrier config for Qns item changefor_slot: " |
| + mSlotIndex |
| + "_" |
| + carrierConfigBundle); |
| PersistableBundle assetConfigBundle = readFromAssets(mContext, mSlotIndex); |
| Log.d( |
| LOG_TAG, |
| "Check Asset config for Qns item changefor_slot: " |
| + mSlotIndex |
| + "_" |
| + assetConfigBundle); |
| |
| boolean isThresholdConfigChanged = |
| checkThresholdConfigChange(carrierConfigBundle, assetConfigBundle); |
| boolean isHandoverRulesChanged = |
| checkHandoverRuleConfigChange( |
| carrierConfigBundle, |
| null, |
| CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY); |
| Log.d( |
| LOG_TAG, |
| "Threshold config changed = " |
| + isThresholdConfigChanged |
| + ", IMS handover rule changed = " |
| + isHandoverRulesChanged); |
| |
| return (isThresholdConfigChanged || isHandoverRulesChanged); |
| } |
| |
| /** |
| * Below API takes to check if current HO rules as any difference with existing HO rules Updated |
| * based on Event Carrier config change event received after initial loading @Param |
| * PersistableBundle : configBundle |
| * |
| * @return true/false |
| */ |
| public synchronized boolean checkHandoverRuleConfigChange( |
| PersistableBundle carrierConfigBundle, |
| PersistableBundle assetConfigBundle, |
| String key) { |
| List<HandoverRule> handoverUpdateRuleList = |
| updateHandoverRules(carrierConfigBundle, assetConfigBundle, key); |
| |
| Log.d(LOG_TAG, "New rule:" + handoverUpdateRuleList.toString()); |
| Log.d(LOG_TAG, "Existing rule:" + mHandoverRuleList.toString()); |
| |
| if (mHandoverRuleList.toString().equals(handoverUpdateRuleList.toString()) |
| || handoverUpdateRuleList.isEmpty() |
| || mHandoverRuleList.isEmpty()) { |
| handoverUpdateRuleList.clear(); |
| return false; |
| } else { |
| mHandoverRuleList = new ArrayList<>(handoverUpdateRuleList); |
| Log.d(LOG_TAG, "New rule Updated:" + mHandoverRuleList.toString()); |
| handoverUpdateRuleList.clear(); |
| return true; |
| } |
| } |
| |
| /** |
| * Below API takes to check if ANSP threshold configs was Updated based on Event Carrier config |
| * change event received after initial Qns configuration loading is completed |
| */ |
| public synchronized boolean checkThresholdConfigChange( |
| PersistableBundle carrierConfigBundle, PersistableBundle assetConfigBundle) { |
| |
| return mAnspConfigMgr.checkQnsAnspConfigChange(carrierConfigBundle, assetConfigBundle); |
| } |
| |
| /** |
| * Below API takes care of loading the configuration based on the Bundle data built based on |
| * asset folder xml file . (Except reading Key item of threshold & ANSP |
| */ |
| public void loadQnsAneSupportConfigurations( |
| PersistableBundle bundleCarrier, PersistableBundle bundleAsset) { |
| |
| mIsWfcInAirplaneModeOnSupport = |
| getConfig( |
| bundleCarrier, bundleAsset, KEY_QNS_SUPPORT_WFC_DURING_AIRPLANE_MODE_BOOL); |
| mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_IN_CALL_HO_DECISION_WLAN_TO_WWAN_WITHOUT_VOPS_CONDITION_BOOL); |
| mIsHoGuardOnPreferenceSupport = |
| getConfig(bundleCarrier, bundleAsset, KEY_QNS_HO_GUARDING_BY_PREFERENCE_BOOL); |
| mIsServiceBarringCheckSupport = |
| getConfig(bundleCarrier, bundleAsset, KEY_QNS_SUPPORT_SERVICE_BARRING_CHECK_BOOL); |
| mIsVideoOverIWLANWithCellularCheckSupport = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_ALLOW_VIDEO_OVER_IWLAN_WITH_CELLULAR_LIMITED_CASE_BOOL); |
| mIsRoveOutWifiBadGuardTimerConditionsSupported = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_ROVE_OUT_POLICY_WITH_WIFI_BAD_GUARDTIMER_CONDITIONS_BOOL); |
| mIsAllowImsOverIwlanCellularLimitedCase = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_ALLOW_IMS_OVER_IWLAN_CELLULAR_LIMITED_CASE_BOOL); |
| mIsBlockIwlanInInternationalRoamWithoutWwan = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_BLOCK_IWLAN_IN_INTERNATIONAL_ROAMING_WITHOUT_WWAN_BOOL); |
| mIsBlockIpv6OnlyWifi = getConfig(bundleCarrier, bundleAsset, KEY_BLOCK_IPV6_ONLY_WIFI_BOOL); |
| |
| mWifiThresBackHaulTimer = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_WIFI_RSSI_THRESHOLDBACKHAUL_TIMER_MS_INT); |
| mCellularThresBackHaulTimer = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_CELLULAR_SS_THRESHOLDBACKHAUL_TIMER_MS_INT); |
| mQnsImsTransportType = |
| getConfig(bundleCarrier, bundleAsset, KEY_QNS_IMS_TRANSPORT_TYPE_INT); |
| mQnsSosTransportType = |
| getConfig(bundleCarrier, bundleAsset, KEY_QNS_SOS_TRANSPORT_TYPE_INT); |
| mQnsMmsTransportType = |
| getConfig(bundleCarrier, bundleAsset, KEY_QNS_MMS_TRANSPORT_TYPE_INT); |
| mQnsXcapTransportType = |
| getConfig(bundleCarrier, bundleAsset, KEY_QNS_XCAP_TRANSPORT_TYPE_INT); |
| mQnsCbsTransportType = |
| getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_TRANSPORT_TYPE_INT); |
| mQnsCbsTransportType = |
| getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_TRANSPORT_TYPE_INT); |
| mXcapRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_XCAP_RAT_PREFERENCE_INT); |
| mSosRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_SOS_RAT_PREFERENCE_INT); |
| mMmsRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_MMS_RAT_PREFERENCE_INT); |
| mCbsRatPreference = getConfig(bundleCarrier, bundleAsset, KEY_QNS_CBS_RAT_PREFERENCE_INT); |
| mNetworkEnableHysteresisTimer = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_IMS_NETWORK_ENABLE_HO_HYSTERESIS_TIMER_INT); |
| |
| mWwanHysteresisTimer = |
| getConfig(bundleCarrier, bundleAsset, KEY_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY); |
| mWlanHysteresisTimer = |
| getConfig(bundleCarrier, bundleAsset, KEY_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY); |
| mNonImsWwanHysteresisTimer = |
| getConfig( |
| bundleCarrier, bundleAsset, KEY_NON_IMS_WWAN_HYSTERESIS_TIMER_MS_INT_ARRAY); |
| mNonImsWlanHysteresisTimer = |
| getConfig( |
| bundleCarrier, bundleAsset, KEY_NON_IMS_WLAN_HYSTERESIS_TIMER_MS_INT_ARRAY); |
| mWaitingTimerForPreferredTransport = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_WAITING_TIME_FOR_PREFERRED_TRANSPORT_WHEN_POWER_ON_INT_ARRAY); |
| mAllowMaxIwlanHoCountOnReason = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_IN_CALL_ROVEIN_ALLOWED_COUNT_AND_FALLBACK_REASON_INT_ARRAY); |
| mHoRestrictTimeOnRtpQuality = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_HO_RESTRICT_TIME_WITH_LOW_RTP_QUALITY_MILLIS_INT_ARRAY); |
| mRTPMetricsData = getConfig(bundleCarrier, bundleAsset, KEY_QNS_RTP_METRICS_INT_ARRAY); |
| |
| mFallbackOnInitialConnectionFailure = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_FALLBACK_ON_INITIAL_CONNECTION_FAILURE_STRING_ARRAY); |
| mImsAllowedRats = |
| getConfig(bundleCarrier, bundleAsset, KEY_IMS_CELLULAR_ALLOWED_RAT_STRING_ARRAY); |
| mRoveInGuardTimerConditionThresholdGaps = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_QNS_ROVEIN_THRESHOLD_GAP_WITH_GUARD_TIMER_STRING_ARRAY); |
| mApnTypesInternationalRoamingCheck = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_APN_TYPES_WITH_INTERNATIONAL_ROAMING_CONDITION_STRING_ARRAY); |
| mPlmnsRegardedAsInternationalRoaming = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_PLMN_LIST_REGARDED_AS_INTERNATIONAL_ROAMING_STRING_ARRAY); |
| mPlmnsRegardedAsDomesticRoaming = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_PLMN_LIST_REGARDED_AS_DOMESTIC_ROAMING_STRING_ARRAY); |
| |
| loadFallbackPolicyWithImsRegiFail(bundleCarrier, bundleAsset); |
| } |
| |
| @VisibleForTesting |
| void loadFallbackPolicyWithImsRegiFail(PersistableBundle carrier, PersistableBundle asset) { |
| synchronized (this) { |
| mFallbackWwanRuleWithImsUnregistered.clear(); |
| String[] fallbackRulesStrings = |
| getConfig( |
| carrier, |
| asset, |
| KEY_QNS_FALLBACK_WWAN_IMS_UNREGISTRATION_REASON_STRING_ARRAY); |
| if (fallbackRulesStrings != null) { |
| Log.d(LOG_TAG, "loadFallbackPolicyWithImsRegiFail" + fallbackRulesStrings.length); |
| for (String ruleString : fallbackRulesStrings) { |
| Log.d(LOG_TAG, " ruleString1:" + ruleString); |
| FallbackRule rule = parseFallbackRule(ruleString); |
| if (rule != null) { |
| mFallbackWwanRuleWithImsUnregistered.add(rule); |
| } |
| } |
| } else { |
| Log.d(LOG_TAG, "Config FallbackWwanRuleWithImsUnregistered is null"); |
| } |
| mFallbackWwanRuleWithImsHoRegisterFail.clear(); |
| fallbackRulesStrings = |
| getConfig( |
| carrier, |
| asset, |
| KEY_QNS_FALLBACK_WWAN_IMS_HO_REGISTER_FAIL_REASON_STRING_ARRAY); |
| if (fallbackRulesStrings != null) { |
| Log.d(LOG_TAG, "loadFallbackPolicyWithImsRegiFail2:" + fallbackRulesStrings.length); |
| for (String ruleString : fallbackRulesStrings) { |
| Log.d(LOG_TAG, " ruleString2:" + ruleString); |
| FallbackRule rule = parseFallbackRule(ruleString); |
| if (rule != null) { |
| mFallbackWwanRuleWithImsHoRegisterFail.add(rule); |
| } |
| } |
| } else { |
| Log.d(LOG_TAG, "Config mFallbackWwanRuleWithImsHoRegisterFail is null"); |
| } |
| } |
| } |
| |
| private FallbackRule parseFallbackRule(String ruleString) { |
| if (TextUtils.isEmpty(ruleString)) { |
| throw new IllegalArgumentException("illegal rule " + ruleString); |
| } |
| Set<Integer> reasons = new ArraySet<>(); |
| int time = 0; |
| int preferenceMode = -1; |
| ruleString = ruleString.trim().toLowerCase(Locale.ROOT); |
| String[] expressions = ruleString.split("\\s*,\\s*"); |
| for (String expression : expressions) { |
| String[] tokens = expression.trim().split("\\s*=\\s*"); |
| if (tokens.length != 2) { |
| throw new IllegalArgumentException( |
| "illegal rule " + ruleString + ", tokens=" + Arrays.toString(tokens)); |
| } |
| String key = tokens[0].trim(); |
| String value = tokens[1].trim(); |
| |
| try { |
| switch (key) { |
| case "cause": |
| String[] cause = value.trim().split("\\s*\\|\\s*"); |
| for (String c : cause) { |
| if (c.indexOf("~") == -1) { |
| reasons.add(Integer.parseInt(c)); |
| } else { |
| String tok[] = c.trim().split("\\s*~\\s*"); |
| if (tokens.length != 2) { |
| throw new IllegalArgumentException( |
| "illegal cause range " |
| + ruleString |
| + ", tokens=" |
| + Arrays.toString(tok)); |
| } |
| int start = Integer.valueOf(tok[0]); |
| int end = Integer.valueOf(tok[1]); |
| for (int i = start; i <= end; i++) { |
| reasons.add(i); |
| } |
| } |
| } |
| break; |
| case "time": |
| time = Integer.valueOf(value); |
| break; |
| case "preference": |
| if (value.equals("cell")) { |
| preferenceMode = QnsConstants.CELL_PREF; |
| } else if (value.equals("wifi")) { |
| preferenceMode = QnsConstants.WIFI_PREF; |
| } |
| break; |
| |
| default: |
| throw new IllegalArgumentException("unexpected key " + key); |
| } |
| |
| } catch (Exception e) { |
| e.printStackTrace(); |
| throw new IllegalArgumentException("illegal rule \"" + ruleString + "\", e=" + e); |
| } |
| } |
| if (reasons.size() > 0) { |
| return new FallbackRule(reasons, time, preferenceMode); |
| } else { |
| return null; |
| } |
| } |
| |
| private synchronized <T> T getConfig( |
| PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String configKey) { |
| return QnsUtils.getConfig(bundleCarrier, bundleAsset, configKey); |
| } |
| |
| /** Load handover rules from carrier config. */ |
| @VisibleForTesting |
| void loadHandoverRules( |
| PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key) { |
| synchronized (this) { |
| mHandoverRuleList.clear(); |
| String[] handoverRulesStrings = getConfig(bundleCarrier, bundleAsset, key); |
| if (handoverRulesStrings != null) { |
| for (String ruleString : handoverRulesStrings) { |
| Log.d(LOG_TAG, "loadHandoverRules: " + ruleString); |
| try { |
| mHandoverRuleList.add(new HandoverRule(ruleString)); |
| } catch (IllegalArgumentException e) { |
| Log.d(LOG_TAG, "loadHandoverRules: " + e.getMessage()); |
| } |
| } |
| } |
| } |
| } |
| |
| /** Updated handover rules from carrier config. */ |
| @VisibleForTesting |
| public List<HandoverRule> updateHandoverRules( |
| PersistableBundle bundleCarrier, PersistableBundle bundleAsset, String key) { |
| List<HandoverRule> readNewHandoverRuleList = new ArrayList<>(); |
| synchronized (this) { |
| readNewHandoverRuleList.clear(); |
| String[] handoverRulesStrings = getConfig(bundleCarrier, bundleAsset, key); |
| if (handoverRulesStrings != null) { |
| for (String ruleString : handoverRulesStrings) { |
| Log.d(LOG_TAG, "UpdateHandoverRules: " + ruleString); |
| try { |
| Log.d(LOG_TAG, "Rule Updated"); |
| readNewHandoverRuleList.add(new HandoverRule(ruleString)); |
| } catch (IllegalArgumentException e) { |
| Log.d(LOG_TAG, "UpdateHandoverRules: " + e.getMessage()); |
| } |
| } |
| } |
| } |
| return readNewHandoverRuleList; |
| } |
| |
| /** Load carrier config. */ |
| @VisibleForTesting |
| void loadCarrierConfig(PersistableBundle bundleCarrier, PersistableBundle bundleAsset) { |
| mIsMmtelCapabilityRequired = |
| getConfig( |
| bundleCarrier, |
| null, |
| CarrierConfigManager.Ims.KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY); |
| mIsVolteRoamingSupported = |
| getConfig( |
| bundleCarrier, |
| null, |
| CarrierConfigManager.ImsVoice.KEY_CARRIER_VOLTE_ROAMING_AVAILABLE_BOOL); |
| } |
| |
| /** |
| * To read the current Carrier ID based on the Slot ID and Context info |
| * |
| * @return : Current Carrier ID |
| */ |
| public int getCarrierId() { |
| TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); |
| if (tm != null) { |
| tm = tm.createForSubscriptionId(QnsUtils.getSubId(mContext, mSlotIndex)); |
| return tm.getSimCarrierId(); |
| } |
| return 0; |
| } |
| |
| /** |
| * To read the current Subscription ID based on the Slot ID and Context info Output : Current |
| * Carrier ID |
| */ |
| public int getSubId() { |
| mSubId = QnsUtils.getSubId(mContext, mSlotIndex); |
| return mSubId; |
| } |
| |
| /** Notify all the registrants of the Slot loaded after carrier config loading is Completed */ |
| protected void notifyLoadQnsConfigurationsCompleted() { |
| |
| if (mQnsCarrierConfigLoadedRegistrants != null) { |
| mQnsCarrierConfigLoadedRegistrants.notifyRegistrants(); |
| } else { |
| Log.d(LOG_TAG, "notifyLoadQNSConfigurationsCompleted. no Registrant."); |
| } |
| } |
| |
| /** Notify all the registrants of the Slot loaded after carrier config loading is Completed */ |
| protected void notifyQnsConfigurationsChanged() { |
| |
| if (mQnsCarrierConfigChangedRegistrants != null) { |
| mQnsCarrierConfigChangedRegistrants.notifyRegistrants(); |
| } else { |
| Log.d(LOG_TAG, "notifyQnsConfigurationschanged. no Registrant."); |
| } |
| } |
| |
| /** |
| * API exposed for other classes to register for notification with handlers on Carrier |
| * Configuration Loaded |
| * |
| * @param h Handler to receive event |
| * @param what Event on which to be handled |
| */ |
| public void registerForConfigurationLoaded(Handler h, int what) { |
| mQnsCarrierConfigLoadedRegistrants.addUnique(h, what, null); |
| } |
| |
| /** |
| * API exposed for other classes to register for notification with handlers on Carrier |
| * Configuration changed |
| * |
| * @param h Handler to receive event |
| * @param what Event on which to be handled |
| */ |
| public void registerForConfigurationChanged(Handler h, int what) { |
| mQnsCarrierConfigChangedRegistrants.addUnique(h, what, null); |
| } |
| |
| /** |
| * API exposed for other classes to unregister for notification of QNS Configuration loaded with |
| * handlers |
| * |
| * @param h Handler to Unregister receiving event Output : Void |
| */ |
| public void unregisterForConfigurationLoaded(Handler h) { |
| mQnsCarrierConfigLoadedRegistrants.remove(h); |
| } |
| |
| /** |
| * API exposed for other classes to unregister for notification of QNS Configuration changed |
| * with handlers |
| * |
| * @param h Handler to Unregister receiving event Output : Void |
| */ |
| public void unregisterForConfigurationChanged(Handler h) { |
| mQnsCarrierConfigChangedRegistrants.remove(h); |
| } |
| |
| /** |
| * This method returns if WFC is supported in Airplane Mode On |
| * |
| * @return : boolean (True/False) |
| */ |
| public boolean allowWFCOnAirplaneModeOn() { |
| |
| return mIsWfcInAirplaneModeOnSupport; |
| } |
| |
| /** |
| * This method returns if in-call handover decision from WLAN to WWAN should not consider VoPS |
| * status. |
| * |
| * @return True if in-call handover decision from WLAN to WWAN should not consider VoPS status, |
| * otherwise false. |
| */ |
| public boolean isInCallHoDecisionWlanToWwanWithoutVopsCondition() { |
| return mIsInCallHoDecisionWlanToWwanWithoutVopsConditionSupported; |
| } |
| |
| /** |
| * This method returns VOPS/VONR bit is required for WWAN availability. |
| * |
| * @return : boolean (True/False) |
| */ |
| public boolean isMmtelCapabilityRequired(int coverage) { |
| if (mIsMmtelCapabilityRequired == null || mIsMmtelCapabilityRequired.length == 0) { |
| return true; |
| } |
| for (int i : mIsMmtelCapabilityRequired) { |
| if ((i == CarrierConfigManager.Ims.NETWORK_TYPE_HOME |
| && coverage == QnsConstants.COVERAGE_HOME) |
| || (i == CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING |
| && coverage == QnsConstants.COVERAGE_ROAM)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * This method returns if VoLTE roaming is supported by a carrier. |
| * |
| * @return True if VoLTE roaming is supported or UE is in home network, otherwise false. |
| */ |
| public boolean isVolteRoamingSupported(@QnsConstants.CellularCoverage int coverage) { |
| if (coverage == QnsConstants.COVERAGE_ROAM) { |
| return mIsVolteRoamingSupported; |
| } |
| return true; |
| } |
| |
| /** |
| * This method returns Video call over WFC with wfc off & LTE preconditions met |
| * |
| * @return : boolean (True/False) |
| */ |
| public boolean allowVideoOverIWLANWithCellularLimitedCase() { |
| return mIsVideoOverIWLANWithCellularCheckSupport; |
| } |
| |
| /** |
| * This method returns if handover is allowed by policy |
| * |
| * @return True if handover is allowed by policy, otherwise false. |
| */ |
| public boolean isHandoverAllowedByPolicy( |
| int apnType, int srcAn, int destAn, @QnsConstants.CellularCoverage int coverage) { |
| Log.d( |
| LOG_TAG, |
| "isHandoverAllowedByPolicy apnType: " |
| + ApnSetting.getApnTypeString(apnType) |
| + " srcAccessNetwork:" |
| + QnsConstants.accessNetworkTypeToString(srcAn) |
| + " destAccessNetwork:" |
| + QnsConstants.accessNetworkTypeToString(destAn) |
| + " " |
| + QnsConstants.coverageToString(coverage)); |
| @NetCapability int capability = QnsUtils.apnTypeToNetworkCapability(apnType); |
| // check Telephony handover policy. |
| // Matching the rules by the configured order. Bail out if find first matching rule. |
| for (HandoverRule rule : mHandoverRuleList) { |
| if (rule.isOnlyForRoaming && coverage != QnsConstants.COVERAGE_ROAM) continue; |
| |
| if (rule.sourceAccessNetworks.contains(srcAn) |
| && rule.targetAccessNetworks.contains(destAn)) { |
| // if no capability rule specified, data network capability is considered matched. |
| // otherwise, any capabilities overlap is also considered matched. |
| if (rule.networkCapabilities.isEmpty() |
| || rule.networkCapabilities.contains(capability)) { |
| if (rule.type == HandoverRule.RULE_TYPE_DISALLOWED) { |
| Log.d(LOG_TAG, "isHandoverAllowedByPolicy:Not allowed by policy " + rule); |
| return false; |
| } else { |
| Log.d(LOG_TAG, "isHandoverAllowedByPolicy: allowed by policy " + rule); |
| return true; |
| } |
| } |
| } |
| } |
| |
| Log.d(LOG_TAG, "isHandoverAllowedByPolicy: Did not find matching rule. "); |
| // Disallow handover for non-IMS APNs anyway if no rule is found. |
| if (apnType != ApnSetting.TYPE_IMS) return false; |
| |
| // Allow handover for IMS APN anyway if no rule is found. |
| return true; |
| } |
| |
| /** |
| * This method returns if Service Barring Check for HO decision is Supported |
| * |
| * @return : boolean (True/False) |
| */ |
| public boolean isServiceBarringCheckSupported() { |
| |
| return mIsServiceBarringCheckSupport; |
| } |
| |
| /** |
| * This method returns if the Guard timer (Ping Pong) hysterisis is preference specific |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * True / False |
| */ |
| public boolean isGuardTimerHystersisOnPrefSupported() { |
| |
| return mIsHoGuardOnPreferenceSupport; |
| } |
| |
| /** |
| * This method returns if the network(HOME or ROAM) requires handover guard timer. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * True / False |
| */ |
| public boolean isHysteresisTimerEnabled(int coverage) { |
| if (mNetworkEnableHysteresisTimer == QnsConstants.COVERAGE_BOTH |
| || mNetworkEnableHysteresisTimer == coverage) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Get carrier config for the KEY_ROAM_TRANSPORT_TYPE_SELECTION_WITHOUT_SIGNAL_STRENGTH_BOOL if |
| * true, It ignores all thresholds needed to only refer to availability. |
| * |
| * @return true for key value is true. False for otherwise. |
| */ |
| public boolean isTransportTypeSelWithoutSSInRoamSupported() { |
| |
| return anspSupportConfigArray[0]; |
| } |
| |
| /* |
| * get carrierconfig for KEY_PREFER_CURRENT_TRANSPORT_TYPE_IN_VOICE_CALL |
| * true: Prefer current transport type during voice call. |
| * |
| * @return true for key value is true. False for otherwise. |
| */ |
| public boolean isCurrentTransportTypeInVoiceCallSupported() { |
| |
| return anspSupportConfigArray[1]; |
| } |
| |
| /** |
| * Get carrierconfig for KEY_POLICY_OVERRIDE_CELL_PREF_TO_IMS_PREF_HOME_BOOL |
| * true: Use IMS Preferred when WFC Mode is Cellular Preferred at Home Network. |
| * |
| * @return true for key value is true. False for otherwise. |
| */ |
| public boolean isOverrideImsPreferenceSupported() { |
| return anspSupportConfigArray[2]; |
| } |
| |
| /** |
| * The method is to return if choose WFC prferred transport in both WWAN and WLAN are bad |
| * conditions. It is controlled by |
| * KEY_CHOOSE_WFC_PREFERRED_TRANSPORT_IN_BOTH_BAD_CONDITION_INT_ARRAY. |
| * |
| * @return : boolean (True/False) |
| */ |
| public boolean isChooseWfcPreferredTransportInBothBadCondition(int wfcMode) { |
| if (mIsWfcPreferredTransportRequired == null |
| || mIsWfcPreferredTransportRequired.length == 0) { |
| return false; |
| } |
| for (int i : mIsWfcPreferredTransportRequired) { |
| if (wfcMode == i) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * This method returns whether the rove out(to Cellular) policy includes a Wi-Fi bad condition |
| * at handover guarding time. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * True / False |
| */ |
| public boolean isRoveOutWithWiFiLowQualityAtGuardingTime() { |
| |
| return mIsRoveOutWifiBadGuardTimerConditionsSupported; |
| } |
| |
| /** |
| * This method returns the waiting time for the preferred transport type at power up. |
| * |
| * @return : A timer in millisecond |
| */ |
| public int getWaitingTimerForPreferredTransportOnPowerOn(int transportType) { |
| switch (transportType) { |
| case TRANSPORT_TYPE_WWAN: |
| return mWaitingTimerForPreferredTransport[0]; |
| case TRANSPORT_TYPE_WLAN: |
| return mWaitingTimerForPreferredTransport[1]; |
| default: |
| Log.d(LOG_TAG, "Invalid transport type, return the default timer."); |
| return QnsConstants.KEY_DEFAULT_VALUE; |
| } |
| } |
| |
| /** |
| * This method returns the Transport type Preference on Power On. |
| * |
| * @return : Based on Carrier Config Settings Possible values (3000msec:Default or operator |
| * customisation. |
| */ |
| public int getWIFIRssiBackHaulTimer() { |
| return mWifiThresBackHaulTimer; |
| } |
| |
| /** |
| * This method returns Cellular SS Backhaul Timer. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values ( 0 |
| * : Invalid or 320ms) |
| */ |
| public int getCellularSSBackHaulTimer() { |
| |
| return mCellularThresBackHaulTimer; |
| } |
| |
| /** |
| * This method returns IWLAN HO Avoid time due to Low RTP Quality Backhaul Timer. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values ( 0 |
| * : or operator requirement) |
| */ |
| public int getHoRestrictedTimeOnLowRTPQuality( |
| @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork) { |
| |
| if (accessNetwork == TRANSPORT_TYPE_WLAN) return mHoRestrictTimeOnRtpQuality[0]; |
| else if (accessNetwork == TRANSPORT_TYPE_WWAN) return mHoRestrictTimeOnRtpQuality[1]; |
| else return QnsConstants.KEY_DEFAULT_VALUE; |
| } |
| |
| /** |
| * This method returns QNS preferred transport type for APN types / Services |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * TRANSPORT_TYPE_ALLOWED_WWAN = 0 TRANSPORT_TYPE_ALLOWED_IWLAN = 1 |
| * TRANSPORT_TYPE_ALLOWED_BOTH = 2 |
| */ |
| public int getQnsSupportedTransportType(int apnType) { |
| |
| if (apnType == ApnTypes.IMS) { |
| return mQnsImsTransportType; |
| } else if (apnType == ApnTypes.EMERGENCY) { |
| return mQnsSosTransportType; |
| } else if (apnType == ApnTypes.MMS) { |
| return mQnsMmsTransportType; |
| } else if (apnType == ApnTypes.XCAP) { |
| return mQnsXcapTransportType; |
| } else if (apnType == ApnTypes.CBS) { |
| return mQnsCbsTransportType; |
| } else { |
| return QnsConstants.INVALID_ID; |
| } |
| } |
| |
| /** |
| * This method returns the hysteresis timer when handover from WLAN to WWAN. |
| * |
| * @return : the hysteresis timer |
| */ |
| public int getWwanHysteresisTimer(int apnType, @QnsConstants.QnsCallType int callType) { |
| if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC)) { |
| return mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC); |
| } |
| switch (apnType) { |
| case ApnTypes.IMS: |
| case ApnTypes.EMERGENCY: |
| if (callType == QnsConstants.CALL_TYPE_IDLE) { |
| return mWwanHysteresisTimer[0]; |
| } else if (callType == QnsConstants.CALL_TYPE_VOICE) { |
| return mWwanHysteresisTimer[1]; |
| } else if (callType == QnsConstants.CALL_TYPE_VIDEO) { |
| return mWwanHysteresisTimer[2]; |
| } else { |
| return QnsConstants.KEY_DEFAULT_VALUE; |
| } |
| case ApnTypes.MMS: |
| case ApnTypes.XCAP: |
| case ApnTypes.CBS: |
| if (callType == QnsConstants.CALL_TYPE_IDLE) { |
| return mNonImsWwanHysteresisTimer[0]; |
| } else { |
| return mNonImsWwanHysteresisTimer[1]; |
| } |
| default: |
| return QnsConstants.KEY_DEFAULT_VALUE; |
| } |
| } |
| |
| /** |
| * This method returns the hysteresis timer when handover from WWAN to WLAN. |
| * |
| * @return : the hysteresis timer |
| */ |
| public int getWlanHysteresisTimer(int apnType, @QnsConstants.QnsCallType int callType) { |
| if (mQnsProvisioningInfo.hasItem(ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC)) { |
| return mQnsProvisioningInfo.getIntegerItem(ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC); |
| } |
| switch (apnType) { |
| case ApnTypes.IMS: |
| case ApnTypes.EMERGENCY: |
| if (callType == QnsConstants.CALL_TYPE_IDLE) { |
| return mWlanHysteresisTimer[0]; |
| } else if (callType == QnsConstants.CALL_TYPE_VOICE) { |
| return mWlanHysteresisTimer[1]; |
| } else if (callType == QnsConstants.CALL_TYPE_VIDEO) { |
| return mWlanHysteresisTimer[2]; |
| } else { |
| return QnsConstants.KEY_DEFAULT_VALUE; |
| } |
| case ApnTypes.MMS: |
| case ApnTypes.XCAP: |
| case ApnTypes.CBS: |
| if (callType == QnsConstants.CALL_TYPE_IDLE) { |
| return mNonImsWlanHysteresisTimer[0]; |
| } else { |
| return mNonImsWlanHysteresisTimer[1]; |
| } |
| default: |
| return QnsConstants.KEY_DEFAULT_VALUE; |
| } |
| } |
| |
| /** |
| * This method returns the Threshold gap offset based on which threshold to be registered during |
| * Guard timer Running / Expired conditions from Evaluator |
| * |
| * @return : Based on Carrier Config Settings & operator requirement Default Value : 0 gap |
| * offset (Means different threshold for Guard timer conditions not enabled) |
| */ |
| public int getThresholdGapWithGuardTimer( |
| @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, int meas_type) { |
| |
| if (mRoveInGuardTimerConditionThresholdGaps == null) { |
| return QnsConstants.KEY_DEFAULT_VALUE; |
| } |
| if (!mRoveInGuardTimerConditionThresholdGaps[0].isEmpty()) { |
| for (String check_offset : mRoveInGuardTimerConditionThresholdGaps) { |
| String[] gap = check_offset.split(":"); |
| String access_network = accessnetworkMap.get(accessNetwork); |
| String measurement_Type = measTypeMap.get(meas_type); |
| |
| try { |
| if (gap[0].equalsIgnoreCase(access_network) |
| && gap[1].equalsIgnoreCase(measurement_Type)) |
| return Integer.parseInt(gap[2]); |
| } catch (Exception e) { |
| } |
| } |
| } |
| return QnsConstants.KEY_DEFAULT_VALUE; |
| } |
| |
| public boolean hasThresholdGapWithGuardTimer() { |
| if (mRoveInGuardTimerConditionThresholdGaps == null) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * This method returns Access Network Selection Policy based on APN type |
| * |
| * @param targetTransportType : WWAN/WLAN |
| * @return : Target transport mapped to string |
| */ |
| public static String transportNetworkToString(int targetTransportType) { |
| switch (targetTransportType) { |
| case TRANSPORT_TYPE_WWAN: |
| return "CELLULAR"; |
| case TRANSPORT_TYPE_WLAN: |
| return "WIFI"; |
| } |
| return ""; |
| } |
| |
| /** |
| * Finds and returns a threshold config that meets the given parameter condition. |
| * |
| * @param accessNetwork (EUTRAN/UTRAN/NGRAN/GERAN/IWLAN) |
| * @param callType (IDLE/VOICE/VIDEO) |
| * @param measurementType (RSRP/RSRQ/RSSNR/SSRSP/SSRSQ/RSCP/RSSI) |
| * @return QnsConfigArray for good, bad and worst thresholds. If the value does not exist or is |
| * not supported, it is filled with invalid (0x0000FFFF). Note, for the wifi case, the worst |
| * in thresholds will be invalid. |
| * @return IVALID VALUE(to do description, if not found item or exceptions) |
| */ |
| public QnsConfigArray getThreshold( |
| @AccessNetworkConstants.RadioAccessNetworkType int accessNetwork, |
| int callType, |
| int measurementType) { |
| int[] thresholdList = new int[] {0x0000FFFF, 0x0000FFFF, 0x0000FFFF}; |
| if (accessNetwork == AccessNetworkConstants.AccessNetworkType.UNKNOWN |
| || measurementType == SIGNAL_MEASUREMENT_TYPE_UNKNOWN) { |
| return null; |
| } |
| |
| String access_network = accessnetworkMap.get(accessNetwork); |
| String measurement_Type = measTypeMap.get(measurementType); |
| String call_Type = callTypeMap.get(callType); |
| |
| if (access_network != null && measurement_Type != null && call_Type != null) { |
| String key = |
| "qns." |
| + call_Type |
| + "_" |
| + access_network |
| + "_" |
| + measurement_Type |
| + "_" |
| + "int_array"; |
| |
| thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key); |
| |
| if (thresholdList != null && thresholdList.length > 1) { |
| if (AccessNetworkConstants.AccessNetworkType.IWLAN == accessNetwork |
| || thresholdList.length == 2) { |
| return new QnsConfigArray(thresholdList[0], thresholdList[1]); |
| } else { |
| return new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]); |
| } |
| } else { |
| thresholdList = new int[] {0x0000FFFF, 0x0000FFFF, 0x0000FFFF}; |
| } |
| } |
| return new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]); |
| } |
| |
| public QnsConfigArray getThresholdByPref( |
| int accessNetwork, int callType, int measurementType, int preference) { |
| if (accessNetwork == AccessNetworkConstants.AccessNetworkType.UNKNOWN |
| || measurementType == SIGNAL_MEASUREMENT_TYPE_UNKNOWN) { |
| return null; |
| } |
| |
| int[] thresholdList = null; |
| String access_network = accessnetworkMap.get(accessNetwork); |
| String measurement_Type = measTypeMap.get(measurementType); |
| String call_Type = callTypeMap.get(callType); |
| |
| if (access_network == null || measurement_Type == null || call_Type == null) { |
| return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF); |
| } |
| |
| if (accessNetwork == AccessNetworkConstants.AccessNetworkType.IWLAN |
| && preference == QnsConstants.WIFI_PREF) { |
| String overrideKey = |
| "qns.override_wifi_pref_" |
| + call_Type |
| + "_" |
| + access_network |
| + "_" |
| + measurement_Type |
| + "_int_array"; |
| thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(overrideKey); |
| } |
| |
| if (thresholdList == null || thresholdList.length < 2) { |
| String key = |
| "qns." |
| + call_Type |
| + "_" |
| + access_network |
| + "_" |
| + measurement_Type |
| + "_int_array"; |
| thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key); |
| } |
| if (thresholdList == null || thresholdList.length < 2) { |
| return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF); |
| } |
| |
| if (AccessNetworkConstants.AccessNetworkType.IWLAN == accessNetwork |
| || thresholdList.length == 2) { |
| QnsConfigArray qnsConfigArray = new QnsConfigArray(thresholdList[0], thresholdList[1]); |
| return applyProvisioningInfo(qnsConfigArray, accessNetwork, measurementType, callType); |
| } |
| |
| QnsConfigArray qnsConfigArray = |
| new QnsConfigArray(thresholdList[0], thresholdList[1], thresholdList[2]); |
| return applyProvisioningInfo(qnsConfigArray, accessNetwork, measurementType, callType); |
| } |
| |
| public QnsConfigArray getWifiRssiThresholdWithoutCellular(int callType) { |
| int[] thresholdList = null; |
| String call_Type = callTypeMap.get(callType); |
| |
| if (call_Type == null) { |
| return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF); |
| } |
| |
| String key = "qns." + call_Type + "_wifi_rssi_without_cellular_int_array"; |
| thresholdList = mAnspConfigMgr.getAnspCarrierThreshold(key); |
| |
| if (thresholdList == null || thresholdList.length < 2) { |
| return new QnsConfigArray(0x0000FFFF, 0x0000FFFF, 0x0000FFFF); |
| } |
| |
| return new QnsConfigArray(thresholdList[0], thresholdList[1]); |
| } |
| |
| /** |
| * Finds and returns a policy config that meets the given parameter condition. |
| * |
| * @param direction (ROVE_IN / ROVE_OUT) |
| * @param preCondition (Types of CALL, PREFERENCE, COVERAGE and so on) |
| * @return QnsConfigArray for good, bad and worst policy. If the value does not exist or is not |
| * supported, it is filled with invalid. (0x0000FFFF). Note, for the wifi case, the worst in |
| * thresholds will be invalid. |
| * @return null (to do description, if not found item or exceptions) |
| */ |
| public String[] getPolicy( |
| @QnsConstants.RoveDirection int direction, |
| AccessNetworkSelectionPolicy.PreCondition preCondition) { |
| |
| String key = |
| "qns.condition_" |
| + QnsConstants.directionToString(direction).toLowerCase() |
| + "_" |
| + QnsConstants.callTypeToString(preCondition.getCallType()).toLowerCase() |
| + "_" |
| + QnsConstants.preferenceToString(preCondition.getPreference()) |
| .toLowerCase() |
| + "_" |
| + QnsConstants.coverageToString(preCondition.getCoverage()).toLowerCase() |
| + "_"; |
| |
| if (preCondition instanceof AccessNetworkSelectionPolicy.GuardingPreCondition) { |
| AccessNetworkSelectionPolicy.GuardingPreCondition guardingCondition = |
| (AccessNetworkSelectionPolicy.GuardingPreCondition) preCondition; |
| String guardingKey = |
| key |
| + QnsConstants.guardingToString(guardingCondition.getGuarding()) |
| .toLowerCase() |
| + "_string_array"; |
| String[] guardingPolicy = mAnspConfigMgr.getAnspCarrierPolicy(guardingKey); |
| if (guardingPolicy != null) { |
| return guardingPolicy; |
| } |
| } |
| key = key + "string_array"; |
| return mAnspConfigMgr.getAnspCarrierPolicy(key); |
| } |
| |
| /** |
| * This method returns RTP Metrics data of Carrier for HO decision making |
| * |
| * @return : config of RTP metrics. refer {@link RtpMetricsConfig} |
| */ |
| @VisibleForTesting |
| public RtpMetricsConfig getRTPMetricsData() { |
| |
| return new RtpMetricsConfig( |
| mRTPMetricsData[0], mRTPMetricsData[1], mRTPMetricsData[2], mRTPMetricsData[3]); |
| } |
| |
| /** |
| * This retrieves fallback timer to WWAN with the reason of IMS unregistered. |
| * |
| * @param reason |
| * @param preferMode |
| * @return fallback time in millis. |
| */ |
| @VisibleForTesting |
| public int getFallbackTimeImsUnreigstered(int reason, int preferMode) { |
| Log.d( |
| LOG_TAG, |
| "getFallbackTimeImsUnreigstered reason:" + reason + " prefMode:" + preferMode); |
| for (FallbackRule rule : mFallbackWwanRuleWithImsUnregistered) { |
| Log.d(LOG_TAG, rule.toString()); |
| if (preferMode != QnsConstants.WIFI_ONLY |
| && (rule.mPreferenceMode == -1 || rule.mPreferenceMode == preferMode)) { |
| int time = rule.getFallBackTime(reason); |
| if (time > 0) { |
| Log.d(LOG_TAG, "getFallbackTimeImsUnreigstered fallbackTime:" + time); |
| return time; |
| } |
| } |
| } |
| Log.d(LOG_TAG, "getFallbackTimeImsUnreigstered fallbackTime:" + 0); |
| return 0; |
| } |
| |
| /** |
| * This retrieves fallback timer to WWAN with the reason of IMS HO register fail. |
| * |
| * @param reason |
| * @param preferMode |
| * @return fallback time in millis. |
| */ |
| @VisibleForTesting |
| public int getFallbackTimeImsHoRegisterFailed(int reason, int preferMode) { |
| Log.d( |
| LOG_TAG, |
| "getFallbackTimeImsHoRegisterFailed reason:" + reason + " prefMode:" + preferMode); |
| for (FallbackRule rule : mFallbackWwanRuleWithImsHoRegisterFail) { |
| if (preferMode != QnsConstants.WIFI_ONLY |
| && (rule.mPreferenceMode == -1 || rule.mPreferenceMode == preferMode)) { |
| Log.d(LOG_TAG, rule.toString()); |
| int time = rule.getFallBackTime(reason); |
| Log.d(LOG_TAG, "getFallbackTimeImsHoRegisterFailed fallback time: " + time); |
| if (time > 0) return time; |
| } |
| } |
| Log.d(LOG_TAG, "getFallbackTimeImsHoRegisterFailed fallback time: " + 0); |
| return 0; |
| } |
| |
| /** |
| * This method returns Access Network Selection Policy Support configurations with boolean array |
| * list type |
| * |
| * @return: Boolean array as a list of Boolean Type |
| */ |
| public void loadAnspCarrierSupportConfigs( |
| PersistableBundle bundleCarrier, PersistableBundle bundleAsset) { |
| int i = 0; |
| String[] anspConfigs = { |
| KEY_ROAM_TRANSPORT_TYPE_SELECTION_WITHOUT_SIGNAL_STRENGTH_BOOL, |
| KEY_PREFER_CURRENT_TRANSPORT_TYPE_IN_VOICE_CALL_BOOL, |
| KEY_POLICY_OVERRIDE_CELL_PREF_TO_IMS_PREF_HOME_BOOL |
| }; |
| |
| for (String key : anspConfigs) { |
| anspSupportConfigArray[i] = getConfig(bundleCarrier, bundleAsset, key); |
| i += 1; |
| } |
| |
| mIsWfcPreferredTransportRequired = |
| getConfig( |
| bundleCarrier, |
| bundleAsset, |
| KEY_CHOOSE_WFC_PREFERRED_TRANSPORT_IN_BOTH_BAD_CONDITION_INT_ARRAY); |
| } |
| |
| /** |
| * This method gives the APN types supported based on |
| * KEY_QNS_<apnType></apnType>_TRANSPORT_TYPE_INT |
| * |
| * @return : Supported APN types |
| */ |
| public int getQnsSupportedApnTypes() { |
| int apnTypeMask = ApnSetting.TYPE_NONE; |
| |
| if (mQnsImsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN |
| || mQnsImsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) |
| apnTypeMask = apnTypeMask | ApnSetting.TYPE_IMS; |
| |
| if (mQnsSosTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN |
| || mQnsSosTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) |
| apnTypeMask = apnTypeMask | ApnSetting.TYPE_EMERGENCY; |
| |
| if (mQnsMmsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN |
| || mQnsMmsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) |
| apnTypeMask = apnTypeMask | ApnSetting.TYPE_MMS; |
| |
| if (mQnsXcapTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN |
| || mQnsXcapTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) |
| apnTypeMask = apnTypeMask | ApnSetting.TYPE_XCAP; |
| |
| if (mQnsCbsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_IWLAN |
| || mQnsCbsTransportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_BOTH) |
| apnTypeMask = apnTypeMask | ApnSetting.TYPE_CBS; |
| |
| return apnTypeMask; |
| } |
| |
| /** |
| * This method returns Allowed cellular RAT for IMS |
| * |
| * @param accessNetwork , apnType : EUTRAN / NGRAN / UTRAN/ GERAN |
| * @return : True or False based on configuration |
| */ |
| public boolean isAccessNetworkAllowed(int accessNetwork, int apnType) { |
| |
| // cases to be enhanced for different key items when added |
| if (apnType == ApnTypes.IMS) { |
| if (mImsAllowedRats != null) { |
| for (String cellularRatType : mImsAllowedRats) { |
| if ((cellularRatType.contains("LTE") |
| && accessNetwork |
| == AccessNetworkConstants.AccessNetworkType.EUTRAN) |
| || (cellularRatType.contains("NR") |
| && accessNetwork |
| == AccessNetworkConstants.AccessNetworkType.NGRAN) |
| || (cellularRatType.contains("3G") |
| && accessNetwork |
| == AccessNetworkConstants.AccessNetworkType.UTRAN) |
| || (cellularRatType.contains("2G") |
| && accessNetwork |
| == AccessNetworkConstants.AccessNetworkType.GERAN)) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * This method returns max HO Back to IWLAN count value with Fallback reason to Rove Out |
| * |
| * @return : int array (Ex: -1,-1 or 1,2 or 3,1 etc... ) |
| */ |
| public int getQnsMaxIwlanHoCountDuringCall() { |
| |
| if (mAllowMaxIwlanHoCountOnReason[0] <= 0) |
| mAllowMaxIwlanHoCountOnReason[0] = MAX_COUNT_INVALID; |
| |
| return mAllowMaxIwlanHoCountOnReason[0]; |
| } |
| |
| /** |
| * This method returns Supported Fallback reason to Rove Out from IWLAN |
| * |
| * @return : int array (Ex: -1,-1 or 1,2 or 3,1 etc... ) |
| */ |
| public int getQnsIwlanHoRestrictReason() { |
| if (mAllowMaxIwlanHoCountOnReason[1] <= 0) |
| mAllowMaxIwlanHoCountOnReason[1] = FALLBACK_REASON_INVALID; |
| |
| return mAllowMaxIwlanHoCountOnReason[1]; |
| } |
| |
| /** |
| * This method returns to allow enabled Wi-Fi calling based on exceptional cellular state, even |
| * when Wi-Fi calling is disabled. |
| * |
| * <p>Enable Wi-Fi calling If the call state is idle and the cellular network the UE is staying |
| * on does not allow ims pdn. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * True / False |
| */ |
| public boolean allowImsOverIwlanCellularLimitedCase() { |
| return mIsAllowImsOverIwlanCellularLimitedCase; |
| } |
| |
| /** |
| * This method returns if Iwlan is not allowed when UE is in no WWAN coverage and the last |
| * stored country code is outside the home country. |
| * |
| * @return True if need to block Iwlan, otherwise false. |
| */ |
| public boolean blockIwlanInInternationalRoamWithoutWwan() { |
| return mIsBlockIwlanInInternationalRoamWithoutWwan; |
| } |
| |
| /** |
| * This method returns if IPv6 only WiFi is allowed |
| * |
| * @return True if need to block IPv6 only WiFi, otherwise false. |
| */ |
| public boolean blockIpv6OnlyWifi() { |
| return mIsBlockIpv6OnlyWifi; |
| } |
| |
| /** |
| * This method returns whether the IMS Registration state option is added when reporting a |
| * qualified Wi-Fi network for APN types other than ims. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * True / False |
| */ |
| public int getRatPreference(int apnType) { |
| switch (apnType) { |
| case ApnSetting.TYPE_XCAP: |
| return mXcapRatPreference; |
| case ApnSetting.TYPE_EMERGENCY: |
| return mSosRatPreference; |
| case ApnSetting.TYPE_MMS: |
| return mMmsRatPreference; |
| case ApnSetting.TYPE_CBS: |
| return mCbsRatPreference; |
| } |
| return QnsConstants.RAT_PREFERENCE_DEFAULT; |
| } |
| |
| /** |
| * This method returns whether the APN type check roaming condition with International Roaming |
| * or not. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * True / False |
| */ |
| public boolean needToCheckInternationalRoaming(int apnType) { |
| if (mApnTypesInternationalRoamingCheck != null |
| && mApnTypesInternationalRoamingCheck.length > 0) { |
| String apnName = ApnSetting.getApnTypeString(apnType); |
| for (String apn : mApnTypesInternationalRoamingCheck) { |
| Log.d(LOG_TAG, apn + " needs International roaming check."); |
| if (apn.equals(apnName)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * This method returns whether input plmn needs to be regarded as international roaming or not. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * True / False |
| */ |
| public boolean isDefinedInternationalRoamingPlmn(String plmn) { |
| if (mPlmnsRegardedAsInternationalRoaming != null |
| && mPlmnsRegardedAsInternationalRoaming.length > 0) { |
| for (String configuredPlmn : mPlmnsRegardedAsInternationalRoaming) { |
| Log.d( |
| LOG_TAG, |
| "isDefinedInternationalRoamingPlmn" |
| + configuredPlmn |
| + " is match with " |
| + plmn); |
| if (configuredPlmn.length() == 3 && plmn.startsWith(configuredPlmn)) { |
| return true; |
| } else if (configuredPlmn.length() > 4 && configuredPlmn.length() <= 6) { |
| if ((Integer.valueOf(configuredPlmn.substring(0, 3)) |
| .equals(Integer.valueOf(plmn.substring(0, 3)))) |
| && (Integer.valueOf(configuredPlmn.substring(3))) |
| .equals(Integer.valueOf(plmn.substring(3)))) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * If fallback for Initial connection failure for the apn type is met is supported , this method |
| * provides information about the failure retry count or retry timer or both if supported until |
| * fallback to other transport. |
| * |
| * @param apnType : (ims,sos,mms,xcap,cbs) |
| * @return : <APNSupportforFallback>:<retry_count>:<retry_timer> |
| */ |
| public int[] getInitialDataConnectionFallbackConfig(int apnType) { |
| |
| int[] fallbackConfigOnDataFail = new int[4]; |
| String[] fallback_config = getFallbackConfigForApn(apnType); |
| |
| if (fallback_config != null |
| && fallback_config[0] != null |
| && fallback_config[0].length() > 0) { |
| // APN Availability Status |
| fallbackConfigOnDataFail[0] = 1; |
| |
| // Retry Count : && fallback_config[1].length() > 0 |
| if (fallback_config.length > 1 |
| && fallback_config[1] != null |
| && !fallback_config[1].isEmpty()) { |
| fallbackConfigOnDataFail[1] = Integer.parseInt(fallback_config[1]); |
| } |
| |
| // Retry timer |
| if (fallback_config.length > 2 |
| && fallback_config[2] != null |
| && !fallback_config[2].isEmpty()) { |
| fallbackConfigOnDataFail[2] = Integer.parseInt(fallback_config[2]); |
| } |
| |
| // Max fallback count |
| if (fallback_config.length > 4 |
| && fallback_config[4] != null |
| && !fallback_config[4].isEmpty()) { |
| fallbackConfigOnDataFail[3] = Integer.parseInt(fallback_config[4]); |
| |
| } |
| } |
| return fallbackConfigOnDataFail; |
| } |
| |
| /** |
| * This method returns the fall back timer to be starting the restriction , for no. of retries |
| * when met with the pdn fail fallback causes |
| * |
| * @param apnType : (ims,sos,mms,xcap,cbs) |
| * @return : Fallback Guard timer to be set on starting the fallback restrict @ RestrictManager |
| */ |
| public int getFallbackGuardTimerOnInitialConnectionFail(int apnType) { |
| String[] fallback_guard_timer = getFallbackConfigForApn(apnType); |
| |
| if (fallback_guard_timer != null |
| && fallback_guard_timer[0] != null |
| && fallback_guard_timer[0].length() > 0 |
| && ((fallback_guard_timer.length > 1 |
| && fallback_guard_timer[1] != null |
| && !fallback_guard_timer[1].isEmpty()) |
| || (fallback_guard_timer.length > 2 |
| && fallback_guard_timer[2] != null |
| && !fallback_guard_timer[2].isEmpty())) |
| && (fallback_guard_timer.length > 3 |
| && fallback_guard_timer[3] != null |
| && !fallback_guard_timer[3].isEmpty())) { |
| return Integer.parseInt(fallback_guard_timer[3]); |
| } else { |
| return 0; |
| } |
| } |
| |
| /* To support find the right Initial Pdn connection failure fallback config based on apn type*/ |
| private String[] getFallbackConfigForApn(int apnType) { |
| if (mFallbackOnInitialConnectionFailure != null |
| && mFallbackOnInitialConnectionFailure.length > 0) { |
| String apnName = ApnSetting.getApnTypeString(apnType); |
| for (String apn : mFallbackOnInitialConnectionFailure) { |
| Log.d(LOG_TAG, "Fallback On Initial Failure enabled for" + apn); |
| if (apn.contains(apnName)) { |
| return apn.split(":"); |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * This method returns whether input plmn needs to be regarded as domestic roaming or not. |
| * |
| * @return : Based on Carrier Config Settings based on operator requirement possible values: |
| * True / False |
| */ |
| public boolean isDefinedDomesticRoamingPlmn(String plmn) { |
| if (mPlmnsRegardedAsDomesticRoaming != null && mPlmnsRegardedAsDomesticRoaming.length > 0) { |
| for (String configuredPlmn : mPlmnsRegardedAsDomesticRoaming) { |
| Log.d( |
| LOG_TAG, |
| "isDefinedDomesticRoamingPlmn" + configuredPlmn + " is match with " + plmn); |
| if (configuredPlmn.length() == 3 && plmn.startsWith(configuredPlmn)) { |
| return true; |
| } else if (configuredPlmn.length() > 4 && configuredPlmn.length() <= 6) { |
| if ((Integer.valueOf(configuredPlmn.substring(0, 3)) |
| .equals(Integer.valueOf(plmn.substring(0, 3)))) |
| && (Integer.valueOf(configuredPlmn.substring(3))) |
| .equals(Integer.valueOf(plmn.substring(3)))) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| public static class QnsConfigArray { |
| |
| /* |
| * static invalid |
| */ |
| public static final int INVALID = 0x0000FFFF; |
| /* |
| * Thresholds, A signal value of good strength to enter. |
| */ |
| public int mGood = INVALID; |
| /* |
| * Thresholds, A signal value of bad strength to leave. |
| */ |
| public int mBad = INVALID; |
| /* |
| * Thresholds, A signal value of worst strength to enter. |
| * The worst strength is only applicable for cellular. |
| */ |
| public int mWorst = INVALID; |
| |
| public QnsConfigArray(int good, int bad, int worst) { |
| set(good, bad, worst); |
| } |
| |
| public QnsConfigArray(int good, int bad) { |
| set(good, bad, INVALID); |
| } |
| |
| public void set(int good, int bad, int worst) { |
| mGood = good; |
| mBad = bad; |
| mWorst = worst; |
| } |
| |
| @Override |
| public String toString() { |
| return "QnsConfigArray{" |
| + "Good=" |
| + mGood |
| + ", Bad=" |
| + mBad |
| + ", Worst=" |
| + mWorst |
| + '}'; |
| } |
| } |
| |
| @VisibleForTesting |
| public static class RtpMetricsConfig { |
| /** Maximum jitter */ |
| public final int mJitter; |
| |
| /** RTP packet loss rate in percentage */ |
| public final int mPktLossRate; |
| |
| /** Time interval of RTP packet loss rate */ |
| public final int mPktLossTime; |
| |
| /** No RTP interval in seconds */ |
| public final int mNoRtpInterval; |
| |
| public RtpMetricsConfig(int jitter, int pktLossRate, int pktLossTime, int noRtpInterval) { |
| this.mJitter = jitter; |
| this.mPktLossRate = pktLossRate; |
| this.mPktLossTime = pktLossTime; |
| this.mNoRtpInterval = noRtpInterval; |
| } |
| |
| @Override |
| public String toString() { |
| return "RtpMetricsConfig{" |
| + "mJitter=" |
| + mJitter |
| + ", mPktLossRate=" |
| + mPktLossRate |
| + ", mPktLossTime=" |
| + mPktLossTime |
| + ", mNoRtpInterval=" |
| + mNoRtpInterval |
| + '}'; |
| } |
| } |
| } |