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:
parent
5548278f28
commit
92e23acebb
1 changed files with 809 additions and 72 deletions
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue