Introduce carrier-aware avoid bad Wi-Fi APIs

This commit introduces new system APIs to manage "avoid bad Wi-Fi" settings,
leveraging both global system settings and carrier configurations. This
enhancement allows for more granular control and visibility into how Wi-Fi
networks are managed, especially in multi-SIM environments.

The new `setNetworkAvoidBadWifi(Context, int subId)` method provides
the ability to programmatically control this setting based on carrier-specific
policies or user preferences. This complements `getNetworkAvoidBadWifi(Context, int subId)`,
which allows querying the setting for a specific subscription ID, ensuring the
system can accurately determine the avoid bad Wi-Fi status.

Additionally, `shouldShowAvoidBadWifiToggle(Context, int subId)` is introduced.
This method determines whether the 'Avoid Bad Wi-Fi' user interface toggle
should be displayed. It considers both global settings and carrier configurations,
allowing for dynamic UI adjustments based on carrier requirements or user preferences.

These changes provide greater flexibility for managing Wi-Fi network selection
and improve the user experience by offering more context-aware control over
cellular behavior.

Deprecated APIs:
- `setNetworkAvoidBadWifi(Context, int value)`
- `getNetworkAvoidBadWifi(Context)`
New APIs:
- `setNetworkAvoidBadWifi(Context, int subId, int value)`
- `getNetworkAvoidBadWifi(Context, int subId)`
- `shouldShowAvoidBadWifiToggle(Context, int subId)`

Flag: com.android.net.flags.carrier_aware_avoid_bad_wifi
Bug: 410976315
Test: atest ConnectivityCoverageTests:android.net.connectivity.android.net.ConnectivitySettingsManagerTest
Change-Id: I79469cfe865a585593219d226c8198206c06b589
This commit is contained in:
Jimi Chen 2025-06-02 13:25:24 +00:00
commit 92e23acebb
6 changed files with 809 additions and 72 deletions

View file

@ -208,3 +208,11 @@ flag {
bug: "419123367"
is_fixed_read_only: true
}
flag {
name: "carrier_aware_avoid_bad_wifi"
namespace: "android_core_networking"
description: "Flag for API to provide carrier-aware avoid bad Wi-Fi setting."
bug: "410976315"
is_fixed_read_only: true
}

View file

@ -90,6 +90,7 @@ java_defaults {
],
static_libs: [
"com.android.net.flags-aconfig-java",
"android.net.platform.flags-aconfig-java-export",
// Not using the latest stable version because all functions in the latest version of
// mdns_aidl_interface are deprecated.
"mdns_aidl_interface-V1-java",

View file

@ -93,7 +93,8 @@ package android.net {
method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
method @NonNull public static java.util.Set<java.lang.Integer> getMobileDataPreferredUids(@NonNull android.content.Context);
method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
method @Deprecated @FlaggedApi("com.android.net.flags.carrier_aware_avoid_bad_wifi") public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
method @FlaggedApi("com.android.net.flags.carrier_aware_avoid_bad_wifi") public static boolean getNetworkAvoidBadWifi(@NonNull android.content.Context, int);
method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
@ -114,7 +115,8 @@ package android.net {
method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
method public static void setMobileDataPreferredUids(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
method @Deprecated @FlaggedApi("com.android.net.flags.carrier_aware_avoid_bad_wifi") public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
method @FlaggedApi("com.android.net.flags.carrier_aware_avoid_bad_wifi") public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int, int);
method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
@ -124,6 +126,7 @@ package android.net {
method public static void setUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
method @FlaggedApi("com.android.net.flags.carrier_aware_avoid_bad_wifi") public static boolean shouldShowAvoidBadWifiToggle(@NonNull android.content.Context, int);
field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1

View file

@ -20,8 +20,15 @@ import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
import static com.android.net.module.util.ConnectivitySettingsUtils.getNetworkLegacyGlobalAvoidBadWifiSetting;
import static com.android.net.module.util.ConnectivitySettingsUtils.getNetworkAvoidBadWifiSetting;
import static com.android.net.module.util.ConnectivitySettingsUtils.convertCarrierAwareSettingsStringToMap;
import static com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString;
import static com.android.net.module.util.ConnectivitySettingsUtils.setNetworkLegacyGlobalAvoidBadWifiSetting;
import static com.android.net.module.util.ConnectivitySettingsUtils.setNetworkAvoidBadWifiSetting;
import static com.android.net.module.util.ConnectivitySettingsUtils.convertCarrierAwareSettingsMapToString;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@ -32,14 +39,17 @@ import android.content.pm.PackageManager;
import android.net.ConnectivityManager.MultipathPreference;
import android.os.Binder;
import android.os.Build;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Range;
import com.android.net.flags.Flags;
import com.android.net.module.util.ConnectivitySettingsUtils;
import com.android.net.module.util.ProxyUtils;
@ -47,6 +57,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
@ -61,6 +72,29 @@ public class ConnectivitySettingsManager {
private ConnectivitySettingsManager() {}
private static boolean isCarrierConfigValid(@Nullable PersistableBundle config) {
return config != null && !config.isEmpty()
&& CarrierConfigManager.isConfigForIdentifiedCarrier(config);
}
private static @NonNull PersistableBundle getConfigForSubId(
@NonNull CarrierConfigManager ccm, int subId, @NonNull String... keys) {
PersistableBundle config = null;
try {
config = ccm.getConfigForSubId(subId, keys);
} catch (RuntimeException e) {
Log.e(TAG, "Failed to get config from carrier config", e);
}
if (!isCarrierConfigValid(config)) {
// If the "avoid bad Wi-Fi" setting is not defined in the carrier-specific config,
// retrieve the default configuration.
config = CarrierConfigManager.getDefaultConfig();
}
return config;
}
/** Data activity timeout settings */
/**
@ -324,6 +358,32 @@ public class ConnectivitySettingsManager {
*/
public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
/**
* Per-carrier setting whether to switch away from wifi networks that lose access.
*
* When a device is connected to both mobile and wifi, and wifi loses Internet
* access, normally the device will switch to the mobile network.
* Carrier config can override this default behavior per-carrier.
* This setting, if defined, overrides both the default and carrier config
* for that particular carrier.
*
* The format is a semicolon-separated list of `subId,value` pairs, where:
*
* subId: The carrier subscription ID (integer).
* value: Controls the avoidance behavior for the corresponding `subId`.
*
* Valid values are:
* 0: Don't avoid bad Wi-Fi for this subscription, and don't prompt the user.
* 1: Avoid bad Wi-Fi for this subscription.
*
* For example: "1,1;2,0" would mean subId 1 avoids bad Wi-Fi, and subId 2 does not.
*
* @hide
*/
@FlaggedApi(Flags.FLAG_CARRIER_AWARE_AVOID_BAD_WIFI)
public static final String NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI =
"network_carrier_aware_avoid_bad_wifi";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
@ -931,11 +991,13 @@ public class ConnectivitySettingsManager {
* @param context The {@link Context} to query the setting.
* @return The setting whether to automatically switch away from wifi networks that lose
* internet access.
* @deprecated Use {@link #getNetworkAvoidBadWifi(Context, int)} instead.
*/
@FlaggedApi(Flags.FLAG_CARRIER_AWARE_AVOID_BAD_WIFI)
@Deprecated
@NetworkAvoidBadWifi
public static int getNetworkAvoidBadWifi(@NonNull Context context) {
final String setting =
Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
final String setting = getNetworkLegacyGlobalAvoidBadWifiSetting(context);
if ("0".equals(setting)) {
return NETWORK_AVOID_BAD_WIFI_IGNORE;
} else if ("1".equals(setting)) {
@ -951,7 +1013,10 @@ public class ConnectivitySettingsManager {
* @param context The {@link Context} to set the setting.
* @param value Whether to automatically switch away from wifi networks that lose internet
* access.
* @deprecated Use {@link #setNetworkAvoidBadWifi(Context, int, int)} instead.
*/
@FlaggedApi(Flags.FLAG_CARRIER_AWARE_AVOID_BAD_WIFI)
@Deprecated
public static void setNetworkAvoidBadWifi(@NonNull Context context,
@NetworkAvoidBadWifi int value) {
final String setting;
@ -964,7 +1029,141 @@ public class ConnectivitySettingsManager {
} else {
throw new IllegalArgumentException("Invalid avoid bad wifi setting");
}
Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
setNetworkLegacyGlobalAvoidBadWifiSetting(context, setting);
}
/**
* Set avoid bad wifi setting to {@link Settings} with specific subscription ID.
*
* @param context The {@link Context} to set the setting.
* @param subId The subscription ID to query carrier configurations for.
* @param value Whether to automatically switch away from wifi networks that lose internet
* access.
*/
@FlaggedApi(Flags.FLAG_CARRIER_AWARE_AVOID_BAD_WIFI)
public static void setNetworkAvoidBadWifi(@NonNull Context context, int subId,
@NetworkAvoidBadWifi int value) {
final String setting = getNetworkAvoidBadWifiSetting(context);
final Map<Integer, Boolean> settingMap =
convertCarrierAwareSettingsStringToMap(setting);
if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
settingMap.put(subId, false);
} else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
settingMap.put(subId, true);
} else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
settingMap.remove(subId);
} else {
throw new IllegalArgumentException("Invalid avoid bad wifi setting");
}
if (settingMap.isEmpty()) {
setNetworkAvoidBadWifiSetting(context, null);
} else {
setNetworkAvoidBadWifiSetting(
context,
convertCarrierAwareSettingsMapToString(context, settingMap)
);
}
// for backward compatibility, write to the old avoid bad wifi settings as well.
if (settingMap.containsKey(subId)) {
setNetworkLegacyGlobalAvoidBadWifiSetting(context, settingMap.get(subId) ? "1" : "0");
} else {
setNetworkLegacyGlobalAvoidBadWifiSetting(context, null);
}
}
/**
* Get avoid bad wifi setting from {@link Settings} with specific subscription ID.
*
* @param context The {@link Context} to query the setting and system services.
* @param subId The subscription ID to query carrier configurations for.
* @return The setting whether to automatically switch away from wifi networks that lose
* internet access.
*/
@FlaggedApi(Flags.FLAG_CARRIER_AWARE_AVOID_BAD_WIFI)
public static boolean getNetworkAvoidBadWifi(@NonNull Context context, int subId) {
final String setting =
getNetworkAvoidBadWifiSetting(context);
final boolean defaultConfig = true;
// check new avoid bad wifi setting first if it's set
if (setting != null) {
final Map<Integer, Boolean> settingMap =
convertCarrierAwareSettingsStringToMap(setting);
if (settingMap.containsKey(subId)) {
return settingMap.get(subId);
}
}
// for backward compatibility, read the old avoid bad wifi settings if new key is not set.
final String oldSetting = getNetworkLegacyGlobalAvoidBadWifiSetting(context);
if (oldSetting != null) {
if (oldSetting.equals("1")) {
return true;
} else if (oldSetting.equals("0")) {
return false;
}
}
// read carrier config if both new and old settings is not set.
final CarrierConfigManager ccm = context.getSystemService(CarrierConfigManager.class);
if (ccm == null) return defaultConfig;
final PersistableBundle config =
getConfigForSubId(ccm, subId, CarrierConfigManager.KEY_AVOID_BAD_WIFI_BOOL);
return config.getBoolean(CarrierConfigManager.KEY_AVOID_BAD_WIFI_BOOL, defaultConfig);
}
/**
* Determines whether the "Avoid Bad Wi-Fi" toggle should be displayed to the user.
*
* This method checks both global system settings and carrier configurations to decide
* if the option for automatically switching away from Wi-Fi networks with no internet
* access should be visible in the user interface.
*
* @param context The {@link Context} to query settings and system services.
* @param subId The subscription ID to query carrier configurations for.
* @return {@code true} if the "Avoid Bad Wi-Fi" toggle should be shown;
* {@code false} otherwise.
*/
@FlaggedApi(Flags.FLAG_CARRIER_AWARE_AVOID_BAD_WIFI)
public static boolean shouldShowAvoidBadWifiToggle(@NonNull Context context, int subId) {
final String setting =
getNetworkAvoidBadWifiSetting(context);
final CarrierConfigManager ccm = context.getSystemService(CarrierConfigManager.class);
final boolean defaultConfig = true;
final boolean defaultDisplay = false;
// check new avoid bad wifi setting first if it's set
if (setting != null) return true;
// for backward compatibility, read the old avoid bad wifi if new setting is not set.
final String oldSetting = getNetworkLegacyGlobalAvoidBadWifiSetting(context);
if (oldSetting != null) return true;
// default to false if system does not support CarrierConfigManager
if (ccm == null) return defaultDisplay;
final PersistableBundle config = getConfigForSubId(
ccm,
subId,
CarrierConfigManager.KEY_AVOID_BAD_WIFI_BOOL,
CarrierConfigManager.KEY_SHOW_AVOID_BAD_WIFI_TOGGLE_BOOL
);
if (!config.getBoolean(CarrierConfigManager.KEY_AVOID_BAD_WIFI_BOOL, defaultConfig)) {
// It should not be possible to force a device to be stuck on bad wifi
// and not give the user an option to change this, so if the device doesn't
// avoid bad wifi, show the toggle even if KEY_SHOW_AVOID_BAD_WIFI_TOGGLE_BOOL
// is false.
return true;
}
return config.getBoolean(
CarrierConfigManager.KEY_SHOW_AVOID_BAD_WIFI_TOGGLE_BOOL, defaultDisplay);
}
/**

View file

@ -22,6 +22,10 @@ import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import java.util.Map;
/**
* Collection of connectivity settings utilities.
@ -29,6 +33,7 @@ import android.text.TextUtils;
* @hide
*/
public class ConnectivitySettingsUtils {
public static final String TAG = ConnectivitySettingsUtils.class.getSimpleName();
public static final int PRIVATE_DNS_MODE_OFF = 1;
public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2;
public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3;
@ -40,6 +45,10 @@ public class ConnectivitySettingsUtils {
public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname";
public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
public static final String NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI =
"network_carrier_aware_avoid_bad_wifi";
/**
* Get private DNS mode as string.
*
@ -128,4 +137,135 @@ public class ConnectivitySettingsUtils {
public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) {
Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier);
}
/**
* Set legacy global avoid bad wifi to {@link Settings}.
*
* @param context The {@link Context} to set the setting.
* @param setting The desired setting value.
* "0": Don't avoid bad Wi-Fi.
* "1": Avoid bad Wi-Fi.
* {@code null}: Ask the user whether to switch away from bad Wi-Fi.
* @deprecated Use {@link #setNetworkAvoidBadWifiSetting(Context, String)} instead.
*/
@Deprecated
public static void setNetworkLegacyGlobalAvoidBadWifiSetting(
@NonNull Context context, @Nullable String setting) {
Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
}
/**
* Get legacy global avoid bad wifi to {@link Settings}.
*
* @param context The {@link Context} to query the setting.
* @return The current setting value, which can be "0", "1", or {@code null}.
* Returns {@code null} if the setting is not found.
* @deprecated Use {@link #getNetworkAvoidBadWifiSetting(Context)} instead.
*/
@Deprecated
@Nullable
public static String getNetworkLegacyGlobalAvoidBadWifiSetting(@NonNull Context context) {
return Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
}
/**
* Set the carrier-aware avoid bad wifi to {@link Settings}.
*
* @param context The {@link Context} to set the setting.
* @param setting The desired setting string, formatted as "subId1,value1;subId2,value2".
* subId: The carrier subscription ID (integer).
* value: "0" to not avoid bad Wi-Fi for this subscription, or "1" to avoid.
* {@code null}: Ask the user whether to switch away from bad Wi-Fi.
*/
public static void setNetworkAvoidBadWifiSetting(
@NonNull Context context, @Nullable String setting) {
Settings.Global.putString(
context.getContentResolver(), NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, setting);
}
/**
* Get the raw carrier-aware avoid bad wifi string from {@link Settings}.
* @see #convertCarrierAwareSettingsStringToMap(String)
*
* @param context The {@link Context} to set the setting.
* @return The current setting string, formatted as "subId1,value1;subId2,value2",
* or {@code null} if the setting is not set.
*/
@Nullable
public static String getNetworkAvoidBadWifiSetting(@NonNull Context context) {
return Settings.Global.getString(
context.getContentResolver(), NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI);
}
/**
* Parses the carrier-aware Wi-Fi avoid bad wifi setting string into a map.
*
* @param setting The setting string, typically retrieved from
* {@link #getNetworkAvoidBadWifiSetting(Context)}.
* Expected format is "subId1,value1;subId2,value2".
* @return A {@link Map} where keys are carrier subscription IDs ({@link Integer})
* and values are booleans indicating whether to avoid bad Wi-Fi ({@code true} for avoid,
* {@code false} for not avoid).
* Returns an empty map if the input setting is null or invalid.
*/
@NonNull
public static Map<Integer, Boolean> convertCarrierAwareSettingsStringToMap(
@Nullable String setting) {
final ArrayMap<Integer, Boolean> settingMap = new ArrayMap<>();
if (setting == null) {
return settingMap;
}
for (String entry: setting.split(";")) {
final String[] parts = entry.split(",");
if (parts.length != 2) {
Log.e(TAG, "invalid setting string: " + entry);
continue;
}
try {
int subId = Integer.parseInt(parts[0].trim());
boolean value = Integer.parseInt(parts[1].trim()) != 0;
settingMap.put(subId, value);
} catch (NumberFormatException e) {
Log.e(TAG, "invalid setting string " + entry);
}
}
return settingMap;
}
/**
* Converts a map of carrier subscription IDs to Wi-Fi avoidance preferences into a string.
*
* @param context The application context.
* @param settingMap A {@link Map} where keys are carrier subscription IDs ({@link Integer})
* and values are booleans indicating whether to avoid bad Wi-Fi ({@code true} for avoid,
* {@code false} for not avoid).
* This map will be converted into a "subId,value;subId2,value2" string format.
* @return A string representing the carrier-aware Wi-Fi avoidance settings,
* or {@code null} if the provided {@code settingMap} is empty.
* The format is "subId1,value1;subId2,value2".
*/
@Nullable
public static String convertCarrierAwareSettingsMapToString(
@NonNull Context context, @NonNull Map<Integer, Boolean> settingMap) {
if (settingMap.isEmpty()) return null;
final StringBuilder sb = new StringBuilder();
int index = 0;
for (Map.Entry<Integer, Boolean> entry: settingMap.entrySet()) {
final String valueStr = entry.getValue() ? "1" : "0";
sb.append(entry.getKey())
.append(",")
.append(valueStr);
if (index < settingMap.size() - 1) {
sb.append(";");
}
index++;
}
return sb.toString();
}
}

View file

@ -28,6 +28,8 @@ import android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES
import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS
import android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT
import android.net.ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON
import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
import android.net.ConnectivitySettingsManager.NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI
import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT
import android.net.ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS
import android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE
@ -42,6 +44,7 @@ import android.net.ConnectivitySettingsManager.getDnsResolverSuccessThresholdPer
import android.net.ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond
import android.net.ConnectivitySettingsManager.getMobileDataActivityTimeout
import android.net.ConnectivitySettingsManager.getMobileDataAlwaysOn
import android.net.ConnectivitySettingsManager.getNetworkAvoidBadWifi
import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationMaximumDailyCount
import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationRateDuration
import android.net.ConnectivitySettingsManager.getPrivateDnsDefaultMode
@ -55,27 +58,42 @@ import android.net.ConnectivitySettingsManager.setDnsResolverSuccessThresholdPer
import android.net.ConnectivitySettingsManager.setIngressRateLimitInBytesPerSecond
import android.net.ConnectivitySettingsManager.setMobileDataActivityTimeout
import android.net.ConnectivitySettingsManager.setMobileDataAlwaysOn
import android.net.ConnectivitySettingsManager.setNetworkAvoidBadWifi
import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationMaximumDailyCount
import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationRateDuration
import android.net.ConnectivitySettingsManager.setPrivateDnsDefaultMode
import android.net.ConnectivitySettingsManager.setWifiAlwaysRequested
import android.net.ConnectivitySettingsManager.setWifiDataActivityTimeout
import android.net.ConnectivitySettingsManager.shouldShowAvoidBadWifiToggle
import android.os.Build
import android.os.PersistableBundle
import android.platform.test.annotations.AppModeFull
import android.provider.Settings
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
import android.util.Range
import androidx.test.InstrumentationRegistry
import androidx.test.filters.SmallTest
import com.android.net.module.util.ConnectivitySettingsUtils.convertCarrierAwareSettingsStringToMap
import com.android.net.module.util.ConnectivitySettingsUtils.getNetworkAvoidBadWifiSetting
import com.android.net.module.util.ConnectivitySettingsUtils.getNetworkLegacyGlobalAvoidBadWifiSetting
import com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString
import com.android.net.module.util.ConnectivitySettingsUtils.setNetworkAvoidBadWifiSetting
import com.android.net.module.util.ConnectivitySettingsUtils.setNetworkLegacyGlobalAvoidBadWifiSetting
import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import junit.framework.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import com.android.testutils.com.android.testutils.CarrierConfigRule
import java.time.Duration
import java.util.Objects
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlin.test.assertFailsWith
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
/**
* Tests for [ConnectivitySettingsManager].
@ -98,12 +116,15 @@ class ConnectivitySettingsManagerTest {
private val settingsTypeGlobal = "global"
private val settingsTypeSecure = "secure"
private val defaultSubId = SubscriptionManager.getDefaultSubscriptionId()
/*** Reset setting value or delete setting if the setting was not existed before testing. */
private fun resetSettings(names: Array<String>, type: String, values: Array<String?>) {
for (i in names.indices) {
if (Objects.equals(values[i], null)) {
instrumentation.uiAutomation.executeShellCommand(
"settings delete $type ${names[i]}")
"settings delete $type ${names[i]}"
)
} else {
if (settingsTypeSecure.equals(type)) {
Settings.Secure.putString(resolver, names[i], values[i])
@ -114,6 +135,18 @@ class ConnectivitySettingsManagerTest {
}
}
private fun assertAvoidBadWifiSettingEquals(expected: String?, setting: String?) {
// The conversion is necessary because the strings may not be in the same order.
assertEquals(
convertCarrierAwareSettingsStringToMap(
expected
),
convertCarrierAwareSettingsStringToMap(
setting
)
)
}
fun <T> testIntSetting(
names: Array<String>,
type: String,
@ -148,32 +181,67 @@ class ConnectivitySettingsManagerTest {
}
}
fun overrideAvoidBadWifiCarrierConfig(
avoidBadWifi: Boolean? = null,
showAvoidBadWifiToggle: Boolean? = null
) {
// Override carrier config to ignore entitlement check.
val bundle = PersistableBundle()
avoidBadWifi?.let { value ->
bundle.putBoolean(CarrierConfigManager.KEY_AVOID_BAD_WIFI_BOOL, value)
}
showAvoidBadWifiToggle?.let { value ->
bundle.putBoolean(CarrierConfigManager.KEY_SHOW_AVOID_BAD_WIFI_TOGGLE_BOOL, value)
}
mCarrierConfigRule.addConfigOverrides(defaultSubId, bundle)
}
@get:Rule
val mCarrierConfigRule: CarrierConfigRule = CarrierConfigRule()
@get:Rule
val ignoreRule = DevSdkIgnoreRule()
@Test
fun testMobileDataActivityTimeout() {
testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_MOBILE), type = settingsTypeGlobal,
value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2),
getter = { getMobileDataActivityTimeout(context, defaultDuration) },
setter = { setMobileDataActivityTimeout(context, it) },
testIntValues = intArrayOf(testTime1.toInt()))
testIntSetting(
names = arrayOf(DATA_ACTIVITY_TIMEOUT_MOBILE),
type = settingsTypeGlobal,
value1 = Duration.ofSeconds(testTime1),
value2 = Duration.ofSeconds(testTime2),
getter = { getMobileDataActivityTimeout(context, defaultDuration) },
setter = { setMobileDataActivityTimeout(context, it) },
testIntValues = intArrayOf(testTime1.toInt())
)
}
@Test
fun testWifiDataActivityTimeout() {
testIntSetting(names = arrayOf(DATA_ACTIVITY_TIMEOUT_WIFI), type = settingsTypeGlobal,
value1 = Duration.ofSeconds(testTime1), value2 = Duration.ofSeconds(testTime2),
getter = { getWifiDataActivityTimeout(context, defaultDuration) },
setter = { setWifiDataActivityTimeout(context, it) },
testIntValues = intArrayOf(testTime1.toInt()))
testIntSetting(
names = arrayOf(DATA_ACTIVITY_TIMEOUT_WIFI),
type = settingsTypeGlobal,
value1 = Duration.ofSeconds(testTime1),
value2 = Duration.ofSeconds(testTime2),
getter = { getWifiDataActivityTimeout(context, defaultDuration) },
setter = { setWifiDataActivityTimeout(context, it) },
testIntValues = intArrayOf(testTime1.toInt())
)
}
@Test
fun testDnsResolverSampleValidityDuration() {
testIntSetting(names = arrayOf(DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS),
type = settingsTypeGlobal, value1 = Duration.ofSeconds(testTime1),
value2 = Duration.ofSeconds(testTime2),
getter = { getDnsResolverSampleValidityDuration(context, defaultDuration) },
setter = { setDnsResolverSampleValidityDuration(context, it) },
testIntValues = intArrayOf(testTime1.toInt()))
testIntSetting(
names = arrayOf(DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS),
type = settingsTypeGlobal,
value1 = Duration.ofSeconds(testTime1),
value2 = Duration.ofSeconds(testTime2),
getter = { getDnsResolverSampleValidityDuration(context, defaultDuration) },
setter = { setDnsResolverSampleValidityDuration(context, it) },
testIntValues = intArrayOf(testTime1.toInt())
)
assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
setDnsResolverSampleValidityDuration(context, Duration.ofSeconds(-1L)) }
@ -181,11 +249,15 @@ class ConnectivitySettingsManagerTest {
@Test
fun testDnsResolverSuccessThresholdPercent() {
testIntSetting(names = arrayOf(DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT),
type = settingsTypeGlobal, value1 = 5, value2 = 10,
getter = { getDnsResolverSuccessThresholdPercent(context, 0 /* def */) },
setter = { setDnsResolverSuccessThresholdPercent(context, it) },
testIntValues = intArrayOf(5))
testIntSetting(
names = arrayOf(DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT),
type = settingsTypeGlobal,
value1 = 5,
value2 = 10,
getter = { getDnsResolverSuccessThresholdPercent(context, 0 /* def */) },
setter = { setDnsResolverSuccessThresholdPercent(context, it) },
testIntValues = intArrayOf(5)
)
assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
setDnsResolverSuccessThresholdPercent(context, -1) }
@ -195,11 +267,15 @@ class ConnectivitySettingsManagerTest {
@Test
fun testDnsResolverSampleRanges() {
testIntSetting(names = arrayOf(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_MAX_SAMPLES),
type = settingsTypeGlobal, value1 = Range(1, 63), value2 = Range(2, 62),
getter = { getDnsResolverSampleRanges(context) },
setter = { setDnsResolverSampleRanges(context, it) },
testIntValues = intArrayOf(1, 63))
testIntSetting(
names = arrayOf(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_MAX_SAMPLES),
type = settingsTypeGlobal,
value1 = Range(1, 63),
value2 = Range(2, 62),
getter = { getDnsResolverSampleRanges(context) },
setter = { setDnsResolverSampleRanges(context, it) },
testIntValues = intArrayOf(1, 63)
)
assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
setDnsResolverSampleRanges(context, Range(-1, 62)) }
@ -209,11 +285,15 @@ class ConnectivitySettingsManagerTest {
@Test
fun testNetworkSwitchNotificationMaximumDailyCount() {
testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT),
type = settingsTypeGlobal, value1 = 5, value2 = 15,
getter = { getNetworkSwitchNotificationMaximumDailyCount(context, 0 /* def */) },
setter = { setNetworkSwitchNotificationMaximumDailyCount(context, it) },
testIntValues = intArrayOf(5))
testIntSetting(
names = arrayOf(NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT),
type = settingsTypeGlobal,
value1 = 5,
value2 = 15,
getter = { getNetworkSwitchNotificationMaximumDailyCount(context, 0 /* def */) },
setter = { setNetworkSwitchNotificationMaximumDailyCount(context, it) },
testIntValues = intArrayOf(5)
)
assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
setNetworkSwitchNotificationMaximumDailyCount(context, -1) }
@ -221,12 +301,15 @@ class ConnectivitySettingsManagerTest {
@Test
fun testNetworkSwitchNotificationRateDuration() {
testIntSetting(names = arrayOf(NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS),
type = settingsTypeGlobal, value1 = Duration.ofMillis(testTime1),
value2 = Duration.ofMillis(testTime2),
getter = { getNetworkSwitchNotificationRateDuration(context, defaultDuration) },
setter = { setNetworkSwitchNotificationRateDuration(context, it) },
testIntValues = intArrayOf(testTime1.toInt()))
testIntSetting(
names = arrayOf(NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS),
type = settingsTypeGlobal,
value1 = Duration.ofMillis(testTime1),
value2 = Duration.ofMillis(testTime2),
getter = { getNetworkSwitchNotificationRateDuration(context, defaultDuration) },
setter = { setNetworkSwitchNotificationRateDuration(context, it) },
testIntValues = intArrayOf(testTime1.toInt())
)
assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
setNetworkSwitchNotificationRateDuration(context, Duration.ofMillis(-1L)) }
@ -234,11 +317,15 @@ class ConnectivitySettingsManagerTest {
@Test
fun testCaptivePortalMode() {
testIntSetting(names = arrayOf(CAPTIVE_PORTAL_MODE), type = settingsTypeGlobal,
value1 = CAPTIVE_PORTAL_MODE_AVOID, value2 = CAPTIVE_PORTAL_MODE_PROMPT,
getter = { getCaptivePortalMode(context, CAPTIVE_PORTAL_MODE_IGNORE) },
setter = { setCaptivePortalMode(context, it) },
testIntValues = intArrayOf(CAPTIVE_PORTAL_MODE_AVOID))
testIntSetting(
names = arrayOf(CAPTIVE_PORTAL_MODE),
type = settingsTypeGlobal,
value1 = CAPTIVE_PORTAL_MODE_AVOID,
value2 = CAPTIVE_PORTAL_MODE_PROMPT,
getter = { getCaptivePortalMode(context, CAPTIVE_PORTAL_MODE_IGNORE) },
setter = { setCaptivePortalMode(context, it) },
testIntValues = intArrayOf(CAPTIVE_PORTAL_MODE_AVOID)
)
assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
setCaptivePortalMode(context, 5 /* mode */) }
@ -254,11 +341,16 @@ class ConnectivitySettingsManagerTest {
assertEquals(mode, getPrivateDnsDefaultMode(context))
setPrivateDnsDefaultMode(context, PRIVATE_DNS_MODE_OFF)
assertEquals(getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OFF),
getPrivateDnsDefaultMode(context))
assertEquals(
getPrivateDnsModeAsString(PRIVATE_DNS_MODE_OFF),
getPrivateDnsDefaultMode(context)
)
} finally {
resetSettings(names = arrayOf(PRIVATE_DNS_DEFAULT_MODE), type = settingsTypeGlobal,
values = arrayOf(original))
resetSettings(
names = arrayOf(PRIVATE_DNS_DEFAULT_MODE),
type = settingsTypeGlobal,
values = arrayOf(original)
)
}
assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
@ -267,12 +359,15 @@ class ConnectivitySettingsManagerTest {
@Test
fun testConnectivityKeepPendingIntentDuration() {
testIntSetting(names = arrayOf(CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS),
type = settingsTypeSecure, value1 = Duration.ofMillis(testTime1),
value2 = Duration.ofMillis(testTime2),
getter = { getConnectivityKeepPendingIntentDuration(context, defaultDuration) },
setter = { setConnectivityKeepPendingIntentDuration(context, it) },
testIntValues = intArrayOf(testTime1.toInt()))
testIntSetting(
names = arrayOf(CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS),
type = settingsTypeSecure,
value1 = Duration.ofMillis(testTime1),
value2 = Duration.ofMillis(testTime2),
getter = { getConnectivityKeepPendingIntentDuration(context, defaultDuration) },
setter = { setConnectivityKeepPendingIntentDuration(context, it) },
testIntValues = intArrayOf(testTime1.toInt())
)
assertFailsWith<IllegalArgumentException>("Expect fail but argument accepted.") {
setConnectivityKeepPendingIntentDuration(context, Duration.ofMillis(-1L)) }
@ -280,20 +375,28 @@ class ConnectivitySettingsManagerTest {
@Test
fun testMobileDataAlwaysOn() {
testIntSetting(names = arrayOf(MOBILE_DATA_ALWAYS_ON), type = settingsTypeGlobal,
value1 = false, value2 = true,
getter = { getMobileDataAlwaysOn(context, true /* def */) },
setter = { setMobileDataAlwaysOn(context, it) },
testIntValues = intArrayOf(0))
testIntSetting(
names = arrayOf(MOBILE_DATA_ALWAYS_ON),
type = settingsTypeGlobal,
value1 = false,
value2 = true,
getter = { getMobileDataAlwaysOn(context, true /* def */) },
setter = { setMobileDataAlwaysOn(context, it) },
testIntValues = intArrayOf(0)
)
}
@Test
fun testWifiAlwaysRequested() {
testIntSetting(names = arrayOf(WIFI_ALWAYS_REQUESTED), type = settingsTypeGlobal,
value1 = false, value2 = true,
getter = { getWifiAlwaysRequested(context, true /* def */) },
setter = { setWifiAlwaysRequested(context, it) },
testIntValues = intArrayOf(0))
testIntSetting(
names = arrayOf(WIFI_ALWAYS_REQUESTED),
type = settingsTypeGlobal,
value1 = false,
value2 = true,
getter = { getWifiAlwaysRequested(context, true /* def */) },
setter = { setWifiAlwaysRequested(context, it) },
testIntValues = intArrayOf(0)
)
}
@ConnectivityModuleTest // get/setIngressRateLimitInBytesPerSecond was added via module update
@ -311,4 +414,287 @@ class ConnectivitySettingsManagerTest {
setIngressRateLimitInBytesPerSecond(context, -10)
}
}
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.BAKLAVA)
fun testSetNetworkAvoidBadWifiWithSettings() {
val orgCarrierAwareSetting = getNetworkAvoidBadWifiSetting(context)
val orgSetting = getNetworkLegacyGlobalAvoidBadWifiSetting(context)
try {
// initialize NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI and NETWORK_AVOID_BAD_WIFI to null
setNetworkAvoidBadWifiSetting(context, null)
setNetworkLegacyGlobalAvoidBadWifiSetting(context, null)
val testSubId = 1000
// test with if new key NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI is set.
// format: "subId1,value1;subId2,value2;..."
// and if old key NETWORK_AVOID_BAD_WIFI is set as well.
// format: "value"
setNetworkAvoidBadWifi(
context,
defaultSubId,
ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_AVOID
)
assertAvoidBadWifiSettingEquals(
"$defaultSubId,1",
getNetworkAvoidBadWifiSetting(context)
)
assertEquals(
"1",
getNetworkLegacyGlobalAvoidBadWifiSetting(context)
)
setNetworkAvoidBadWifi(
context,
defaultSubId,
ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE
)
assertAvoidBadWifiSettingEquals(
"$defaultSubId,0",
getNetworkAvoidBadWifiSetting(context)
)
assertEquals(
"0",
getNetworkLegacyGlobalAvoidBadWifiSetting(context)
)
setNetworkAvoidBadWifi(
context,
testSubId,
ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_AVOID
)
assertAvoidBadWifiSettingEquals(
"$defaultSubId,0;$testSubId,1",
getNetworkAvoidBadWifiSetting(context)
)
assertEquals(
"1",
getNetworkLegacyGlobalAvoidBadWifiSetting(context)
)
setNetworkAvoidBadWifi(
context,
testSubId,
ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_IGNORE
)
assertAvoidBadWifiSettingEquals(
"$defaultSubId,0;$testSubId,0",
getNetworkAvoidBadWifiSetting(context)
)
assertEquals(
"0",
getNetworkLegacyGlobalAvoidBadWifiSetting(context)
)
setNetworkAvoidBadWifi(
context,
testSubId,
ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT
)
assertAvoidBadWifiSettingEquals(
"$defaultSubId,0",
getNetworkAvoidBadWifiSetting(context)
)
assertEquals(
null,
getNetworkLegacyGlobalAvoidBadWifiSetting(context)
)
setNetworkAvoidBadWifi(
context,
defaultSubId,
ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI_PROMPT
)
assertAvoidBadWifiSettingEquals(
null,
getNetworkAvoidBadWifiSetting(context)
)
assertEquals(
null,
getNetworkLegacyGlobalAvoidBadWifiSetting(context)
)
} finally {
resetSettings(
names = arrayOf(NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, NETWORK_AVOID_BAD_WIFI),
type = settingsTypeGlobal,
values = arrayOf(orgCarrierAwareSetting, orgSetting)
)
}
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.BAKLAVA)
fun testGetNetworkAvoidBadWifiWithCarrierAwareSettings() {
val original = getNetworkAvoidBadWifiSetting(context)
try {
setNetworkAvoidBadWifiSetting(context, "$defaultSubId,1")
assertTrue(getNetworkAvoidBadWifi(context, defaultSubId))
setNetworkAvoidBadWifiSetting(context, "$defaultSubId,0")
assertFalse(getNetworkAvoidBadWifi(context, defaultSubId))
val testSubId = 1000
setNetworkAvoidBadWifiSetting(context, "$defaultSubId,0;$testSubId,1")
assertFalse(getNetworkAvoidBadWifi(context, defaultSubId))
assertTrue(getNetworkAvoidBadWifi(context, testSubId))
setNetworkAvoidBadWifiSetting(context, "$defaultSubId,0;$testSubId,0")
assertFalse(getNetworkAvoidBadWifi(context, defaultSubId))
assertFalse(getNetworkAvoidBadWifi(context, testSubId))
setNetworkAvoidBadWifiSetting(context, "$defaultSubId,1;$testSubId,0")
assertTrue(getNetworkAvoidBadWifi(context, defaultSubId))
assertFalse(getNetworkAvoidBadWifi(context, testSubId))
setNetworkAvoidBadWifiSetting(context, "$defaultSubId,1;$testSubId,1")
assertTrue(getNetworkAvoidBadWifi(context, defaultSubId))
assertTrue(getNetworkAvoidBadWifi(context, testSubId))
} finally {
resetSettings(
names = arrayOf(NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI),
type = settingsTypeGlobal,
values = arrayOf(original)
)
}
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.BAKLAVA)
fun testGetNetworkAvoidBadWifiWithSettings() {
val orgCarrierAwareSetting = getNetworkAvoidBadWifiSetting(context)
val orgSetting = getNetworkLegacyGlobalAvoidBadWifiSetting(context)
try {
// test if NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI is not set,
// then it check NETWORK_AVOID_BAD_WIFI for backward compatibility.
setNetworkAvoidBadWifiSetting(context, null)
val testSubId = 1000
setNetworkLegacyGlobalAvoidBadWifiSetting(context, "0")
assertFalse(getNetworkAvoidBadWifi(context, defaultSubId))
assertFalse(getNetworkAvoidBadWifi(context, testSubId))
setNetworkLegacyGlobalAvoidBadWifiSetting(context, "1")
assertTrue(getNetworkAvoidBadWifi(context, defaultSubId))
assertTrue(getNetworkAvoidBadWifi(context, testSubId))
} finally {
resetSettings(
names = arrayOf(NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, NETWORK_AVOID_BAD_WIFI),
type = settingsTypeGlobal,
values = arrayOf(orgCarrierAwareSetting, orgSetting)
)
}
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.BAKLAVA)
fun testGetNetworkAvoidBadWifiWithCarrierConfig() {
val orgCarrierAwareSetting = getNetworkAvoidBadWifiSetting(context)
val orgSetting = getNetworkLegacyGlobalAvoidBadWifiSetting(context)
try {
// unset the global settings, then it depends on the carrier config
mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId)
setNetworkAvoidBadWifiSetting(context, null)
setNetworkLegacyGlobalAvoidBadWifiSetting(context, null)
// default should be true if no carrier config key is set
assertTrue(getNetworkAvoidBadWifi(context, defaultSubId))
overrideAvoidBadWifiCarrierConfig(avoidBadWifi = true)
assertTrue(getNetworkAvoidBadWifi(context, defaultSubId))
overrideAvoidBadWifiCarrierConfig(avoidBadWifi = false)
assertFalse(getNetworkAvoidBadWifi(context, defaultSubId))
} finally {
resetSettings(
names = arrayOf(NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, NETWORK_AVOID_BAD_WIFI),
type = settingsTypeGlobal,
values = arrayOf(orgCarrierAwareSetting, orgSetting)
)
}
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.BAKLAVA)
fun testShouldShowAvoidBadWifiToggleWithSettings() {
val orgCarrierAwareSetting = getNetworkAvoidBadWifiSetting(context)
val orgSetting = getNetworkLegacyGlobalAvoidBadWifiSetting(context)
try {
// unset the NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, and NETWORK_AVOID_BAD_WIFI,
// it should be false since no carrier config is set
setNetworkAvoidBadWifiSetting(context, null)
setNetworkLegacyGlobalAvoidBadWifiSetting(context, null)
assertFalse(shouldShowAvoidBadWifiToggle(context, defaultSubId))
// if any global settings is set, it should display the toggle.
setNetworkAvoidBadWifiSetting(context, "$defaultSubId,1")
assertTrue(shouldShowAvoidBadWifiToggle(context, defaultSubId))
setNetworkAvoidBadWifiSetting(context, "$defaultSubId,0")
assertTrue(shouldShowAvoidBadWifiToggle(context, defaultSubId))
// unset the NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI,
// then it check NETWORK_AVOID_BAD_WIFI for backward compatibility.
setNetworkAvoidBadWifiSetting(context, null)
setNetworkLegacyGlobalAvoidBadWifiSetting(context, "1")
assertTrue(shouldShowAvoidBadWifiToggle(context, defaultSubId))
setNetworkLegacyGlobalAvoidBadWifiSetting(context, "0")
assertTrue(shouldShowAvoidBadWifiToggle(context, defaultSubId))
} finally {
resetSettings(
names = arrayOf(NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, NETWORK_AVOID_BAD_WIFI),
type = settingsTypeGlobal,
values = arrayOf(orgCarrierAwareSetting, orgSetting)
)
}
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.BAKLAVA)
fun testShouldShowAvoidBadWifiToggleWithCarrierConfig() {
val orgCarrierAwareSetting = getNetworkAvoidBadWifiSetting(context)
val orgSetting = getNetworkLegacyGlobalAvoidBadWifiSetting(context)
try {
// unset both NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI and KEY_AVOID_BAD_WIFI_BOOL settings,
// then it depends on the carrier config
mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId)
setNetworkAvoidBadWifiSetting(context, null)
setNetworkLegacyGlobalAvoidBadWifiSetting(context, null)
// default should be false if KEY_AVOID_BAD_WIFI_BOOL is not set
assertFalse(shouldShowAvoidBadWifiToggle(context, defaultSubId))
// if KEY_AVOID_BAD_WIFI_BOOL is true, then check KEY_SHOW_AVOID_BAD_WIFI_TOGGLE_BOOL
// default should be false if KEY_SHOW_AVOID_BAD_WIFI_TOGGLE_BOOL is not set
overrideAvoidBadWifiCarrierConfig(avoidBadWifi = true)
assertFalse(shouldShowAvoidBadWifiToggle(context, defaultSubId))
// it should be true if KEY_AVOID_BAD_WIFI_BOOL is false
overrideAvoidBadWifiCarrierConfig(avoidBadWifi = false)
assertTrue(shouldShowAvoidBadWifiToggle(context, defaultSubId))
// Even if the carrier says not to show the toggle, when the carrier says
// not to avoid bad wifi it should be shown.
// This is because it should not be possible to force a device to be stuck on bad wifi
// and not give the user an option to change this.
overrideAvoidBadWifiCarrierConfig(avoidBadWifi = false, showAvoidBadWifiToggle = false)
assertTrue(shouldShowAvoidBadWifiToggle(context, defaultSubId))
overrideAvoidBadWifiCarrierConfig(avoidBadWifi = false, showAvoidBadWifiToggle = true)
assertTrue(shouldShowAvoidBadWifiToggle(context, defaultSubId))
// if KEY_AVOID_BAD_WIFI_BOOL is true, then check KEY_SHOW_AVOID_BAD_WIFI_TOGGLE_BOOL
overrideAvoidBadWifiCarrierConfig(avoidBadWifi = true, showAvoidBadWifiToggle = false)
assertFalse(shouldShowAvoidBadWifiToggle(context, defaultSubId))
overrideAvoidBadWifiCarrierConfig(avoidBadWifi = true, showAvoidBadWifiToggle = true)
assertTrue(shouldShowAvoidBadWifiToggle(context, defaultSubId))
} finally {
resetSettings(
names = arrayOf(NETWORK_CARRIER_AWARE_AVOID_BAD_WIFI, NETWORK_AVOID_BAD_WIFI),
type = settingsTypeGlobal,
values = arrayOf(orgCarrierAwareSetting, orgSetting)
)
}
}
}