1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net; 18 19 import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER; 20 import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE; 21 import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY; 22 23 import static com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString; 24 25 import android.annotation.IntDef; 26 import android.annotation.IntRange; 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.annotation.SystemApi; 30 import android.content.Context; 31 import android.content.pm.PackageManager; 32 import android.net.ConnectivityManager.MultipathPreference; 33 import android.os.Binder; 34 import android.os.Build; 35 import android.os.Process; 36 import android.os.UserHandle; 37 import android.provider.Settings; 38 import android.text.TextUtils; 39 import android.util.ArraySet; 40 import android.util.Log; 41 import android.util.Range; 42 43 import com.android.net.module.util.ConnectivitySettingsUtils; 44 import com.android.net.module.util.ProxyUtils; 45 46 import java.lang.annotation.Retention; 47 import java.lang.annotation.RetentionPolicy; 48 import java.time.Duration; 49 import java.util.List; 50 import java.util.Set; 51 import java.util.StringJoiner; 52 53 /** 54 * A manager class for connectivity module settings. 55 * 56 * @hide 57 */ 58 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 59 public class ConnectivitySettingsManager { 60 private static final String TAG = ConnectivitySettingsManager.class.getSimpleName(); 61 ConnectivitySettingsManager()62 private ConnectivitySettingsManager() {} 63 64 /** Data activity timeout settings */ 65 66 /** 67 * Inactivity timeout to track mobile data activity. 68 * 69 * If set to a positive integer, it indicates the inactivity timeout value in seconds to 70 * infer the data activity of mobile network. After a period of no activity on mobile 71 * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE} 72 * intent is fired to indicate a transition of network status from "active" to "idle". Any 73 * subsequent activity on mobile networks triggers the firing of {@code 74 * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active". 75 * 76 * Network activity refers to transmitting or receiving data on the network interfaces. 77 * 78 * Tracking is disabled if set to zero or negative value. 79 * 80 * @hide 81 */ 82 public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile"; 83 84 /** 85 * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE} 86 * but for Wifi network. 87 * 88 * @hide 89 */ 90 public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi"; 91 92 /** Dns resolver settings */ 93 94 /** 95 * Sample validity in seconds to configure for the system DNS resolver. 96 * 97 * @hide 98 */ 99 public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS = 100 "dns_resolver_sample_validity_seconds"; 101 102 /** 103 * Success threshold in percent for use with the system DNS resolver. 104 * 105 * @hide 106 */ 107 public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT = 108 "dns_resolver_success_threshold_percent"; 109 110 /** 111 * Minimum number of samples needed for statistics to be considered meaningful in the 112 * system DNS resolver. 113 * 114 * @hide 115 */ 116 public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples"; 117 118 /** 119 * Maximum number taken into account for statistics purposes in the system DNS resolver. 120 * 121 * @hide 122 */ 123 public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples"; 124 125 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8; 126 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64; 127 128 /** Network switch notification settings */ 129 130 /** 131 * The maximum number of notifications shown in 24 hours when switching networks. 132 * 133 * @hide 134 */ 135 public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT = 136 "network_switch_notification_daily_limit"; 137 138 /** 139 * The minimum time in milliseconds between notifications when switching networks. 140 * 141 * @hide 142 */ 143 public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS = 144 "network_switch_notification_rate_limit_millis"; 145 146 /** Captive portal settings */ 147 148 /** 149 * The URL used for HTTP captive portal detection upon a new connection. 150 * A 204 response code from the server is used for validation. 151 * 152 * @hide 153 */ 154 public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url"; 155 156 /** 157 * What to do when connecting a network that presents a captive portal. 158 * Must be one of the CAPTIVE_PORTAL_MODE_* constants below. 159 * 160 * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT. 161 * 162 * @hide 163 */ 164 public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode"; 165 166 /** 167 * Don't attempt to detect captive portals. 168 */ 169 public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; 170 171 /** 172 * When detecting a captive portal, display a notification that 173 * prompts the user to sign in. 174 */ 175 public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; 176 177 /** 178 * When detecting a captive portal, immediately disconnect from the 179 * network and do not reconnect to that network in the future; except 180 * on Wear platform companion proxy networks (transport BLUETOOTH) 181 * will stay behind captive portal. 182 */ 183 public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; 184 185 /** @hide */ 186 @Retention(RetentionPolicy.SOURCE) 187 @IntDef(value = { 188 CAPTIVE_PORTAL_MODE_IGNORE, 189 CAPTIVE_PORTAL_MODE_PROMPT, 190 CAPTIVE_PORTAL_MODE_AVOID, 191 }) 192 public @interface CaptivePortalMode {} 193 194 /** Global http proxy settings */ 195 196 /** 197 * Host name for global http proxy. Set via ConnectivityManager. 198 * 199 * @hide 200 */ 201 public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host"; 202 203 /** 204 * Integer host port for global http proxy. Set via ConnectivityManager. 205 * 206 * @hide 207 */ 208 public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port"; 209 210 /** 211 * Exclusion list for global proxy. This string contains a list of 212 * comma-separated domains where the global proxy does not apply. 213 * Domains should be listed in a comma- separated list. Example of 214 * acceptable formats: ".domain1.com,my.domain2.com" Use 215 * ConnectivityManager to set/get. 216 * 217 * @hide 218 */ 219 public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST = 220 "global_http_proxy_exclusion_list"; 221 222 /** 223 * The location PAC File for the proxy. 224 * 225 * @hide 226 */ 227 public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url"; 228 229 /** Private dns settings */ 230 231 /** 232 * The requested Private DNS mode (string), and an accompanying specifier (string). 233 * 234 * Currently, the specifier holds the chosen provider name when the mode requests 235 * a specific provider. It may be used to store the provider name even when the 236 * mode changes so that temporarily disabling and re-enabling the specific 237 * provider mode does not necessitate retyping the provider hostname. 238 * 239 * @hide 240 */ 241 public static final String PRIVATE_DNS_MODE = "private_dns_mode"; 242 243 /** 244 * The specific Private DNS provider name. 245 * 246 * @hide 247 */ 248 public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier"; 249 250 /** 251 * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic"). 252 * This allows changing the default mode without effectively disabling other modes, 253 * all of which require explicit user action to enable/configure. See also b/79719289. 254 * 255 * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above. 256 * 257 * @hide 258 */ 259 public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode"; 260 261 /** Other settings */ 262 263 /** 264 * The number of milliseconds to hold on to a PendingIntent based request. This delay gives 265 * the receivers of the PendingIntent an opportunity to make a new network request before 266 * the Network satisfying the request is potentially removed. 267 * 268 * @hide 269 */ 270 public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS = 271 "connectivity_release_pending_intent_delay_ms"; 272 273 /** 274 * Whether the mobile data connection should remain active even when higher 275 * priority networks like WiFi are active, to help make network switching faster. 276 * 277 * See ConnectivityService for more info. 278 * 279 * (0 = disabled, 1 = enabled) 280 * 281 * @hide 282 */ 283 public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on"; 284 285 /** 286 * Whether the wifi data connection should remain active even when higher 287 * priority networks like Ethernet are active, to keep both networks. 288 * In the case where higher priority networks are connected, wifi will be 289 * unused unless an application explicitly requests to use it. 290 * 291 * See ConnectivityService for more info. 292 * 293 * (0 = disabled, 1 = enabled) 294 * 295 * @hide 296 */ 297 public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested"; 298 299 /** 300 * Whether to automatically switch away from wifi networks that lose Internet access. 301 * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always 302 * avoids such networks. Valid values are: 303 * 304 * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013. 305 * null: Ask the user whether to switch away from bad wifi. 306 * 1: Avoid bad wifi. 307 * 308 * @hide 309 */ 310 public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi"; 311 312 /** 313 * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013. 314 */ 315 public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; 316 317 /** 318 * Ask the user whether to switch away from bad wifi. 319 */ 320 public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; 321 322 /** 323 * Avoid bad wifi. 324 */ 325 public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; 326 327 /** @hide */ 328 @Retention(RetentionPolicy.SOURCE) 329 @IntDef(value = { 330 NETWORK_AVOID_BAD_WIFI_IGNORE, 331 NETWORK_AVOID_BAD_WIFI_PROMPT, 332 NETWORK_AVOID_BAD_WIFI_AVOID, 333 }) 334 public @interface NetworkAvoidBadWifi {} 335 336 /** 337 * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be 338 * overridden by the system based on device or application state. If null, the value 339 * specified by config_networkMeteredMultipathPreference is used. 340 * 341 * @hide 342 */ 343 public static final String NETWORK_METERED_MULTIPATH_PREFERENCE = 344 "network_metered_multipath_preference"; 345 346 /** 347 * A list of uids that should go on cellular networks in preference even when higher-priority 348 * networks are connected. 349 * 350 * @hide 351 */ 352 public static final String MOBILE_DATA_PREFERRED_UIDS = "mobile_data_preferred_uids"; 353 354 /** 355 * One of the private DNS modes that indicates the private DNS mode is off. 356 */ 357 public static final int PRIVATE_DNS_MODE_OFF = ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OFF; 358 359 /** 360 * One of the private DNS modes that indicates the private DNS mode is automatic, which 361 * will try to use the current DNS as private DNS. 362 */ 363 public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 364 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OPPORTUNISTIC; 365 366 /** 367 * One of the private DNS modes that indicates the private DNS mode is strict and the 368 * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of 369 * {@link #PRIVATE_DNS_SPECIFIER} as private DNS. 370 */ 371 public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 372 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; 373 374 /** @hide */ 375 @Retention(RetentionPolicy.SOURCE) 376 @IntDef(value = { 377 PRIVATE_DNS_MODE_OFF, 378 PRIVATE_DNS_MODE_OPPORTUNISTIC, 379 PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, 380 }) 381 public @interface PrivateDnsMode {} 382 383 /** 384 * A list of uids that is allowed to use restricted networks. 385 * 386 * @hide 387 */ 388 public static final String UIDS_ALLOWED_ON_RESTRICTED_NETWORKS = 389 "uids_allowed_on_restricted_networks"; 390 391 /** 392 * A global rate limit that applies to all networks with NET_CAPABILITY_INTERNET when enabled. 393 * 394 * @hide 395 */ 396 public static final String INGRESS_RATE_LIMIT_BYTES_PER_SECOND = 397 "ingress_rate_limit_bytes_per_second"; 398 399 /** 400 * Get mobile data activity timeout from {@link Settings}. 401 * 402 * @param context The {@link Context} to query the setting. 403 * @param def The default timeout if no setting value. 404 * @return The {@link Duration} of timeout to track mobile data activity. 405 */ 406 @NonNull getMobileDataActivityTimeout(@onNull Context context, @NonNull Duration def)407 public static Duration getMobileDataActivityTimeout(@NonNull Context context, 408 @NonNull Duration def) { 409 final int timeout = Settings.Global.getInt( 410 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds()); 411 return Duration.ofSeconds(timeout); 412 } 413 414 /** 415 * Set mobile data activity timeout to {@link Settings}. 416 * Tracking is disabled if set to zero or negative value. 417 * 418 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be 419 * ignored. 420 * 421 * @param context The {@link Context} to set the setting. 422 * @param timeout The mobile data activity timeout. 423 */ setMobileDataActivityTimeout(@onNull Context context, @NonNull Duration timeout)424 public static void setMobileDataActivityTimeout(@NonNull Context context, 425 @NonNull Duration timeout) { 426 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, 427 (int) timeout.getSeconds()); 428 } 429 430 /** 431 * Get wifi data activity timeout from {@link Settings}. 432 * 433 * @param context The {@link Context} to query the setting. 434 * @param def The default timeout if no setting value. 435 * @return The {@link Duration} of timeout to track wifi data activity. 436 */ 437 @NonNull getWifiDataActivityTimeout(@onNull Context context, @NonNull Duration def)438 public static Duration getWifiDataActivityTimeout(@NonNull Context context, 439 @NonNull Duration def) { 440 final int timeout = Settings.Global.getInt( 441 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds()); 442 return Duration.ofSeconds(timeout); 443 } 444 445 /** 446 * Set wifi data activity timeout to {@link Settings}. 447 * Tracking is disabled if set to zero or negative value. 448 * 449 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be 450 * ignored. 451 * 452 * @param context The {@link Context} to set the setting. 453 * @param timeout The wifi data activity timeout. 454 */ setWifiDataActivityTimeout(@onNull Context context, @NonNull Duration timeout)455 public static void setWifiDataActivityTimeout(@NonNull Context context, 456 @NonNull Duration timeout) { 457 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, 458 (int) timeout.getSeconds()); 459 } 460 461 /** 462 * Get dns resolver sample validity duration from {@link Settings}. 463 * 464 * @param context The {@link Context} to query the setting. 465 * @param def The default duration if no setting value. 466 * @return The {@link Duration} of sample validity duration to configure for the system DNS 467 * resolver. 468 */ 469 @NonNull getDnsResolverSampleValidityDuration(@onNull Context context, @NonNull Duration def)470 public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context, 471 @NonNull Duration def) { 472 final int duration = Settings.Global.getInt(context.getContentResolver(), 473 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds()); 474 return Duration.ofSeconds(duration); 475 } 476 477 /** 478 * Set dns resolver sample validity duration to {@link Settings}. The duration must be a 479 * positive number of seconds. 480 * 481 * @param context The {@link Context} to set the setting. 482 * @param duration The sample validity duration. 483 */ setDnsResolverSampleValidityDuration(@onNull Context context, @NonNull Duration duration)484 public static void setDnsResolverSampleValidityDuration(@NonNull Context context, 485 @NonNull Duration duration) { 486 final int time = (int) duration.getSeconds(); 487 if (time <= 0) { 488 throw new IllegalArgumentException("Invalid duration"); 489 } 490 Settings.Global.putInt( 491 context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time); 492 } 493 494 /** 495 * Get dns resolver success threshold percent from {@link Settings}. 496 * 497 * @param context The {@link Context} to query the setting. 498 * @param def The default value if no setting value. 499 * @return The success threshold in percent for use with the system DNS resolver. 500 */ getDnsResolverSuccessThresholdPercent(@onNull Context context, int def)501 public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) { 502 return Settings.Global.getInt( 503 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def); 504 } 505 506 /** 507 * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must 508 * be 0~100. 509 * 510 * @param context The {@link Context} to set the setting. 511 * @param percent The success threshold percent. 512 */ setDnsResolverSuccessThresholdPercent(@onNull Context context, @IntRange(from = 0, to = 100) int percent)513 public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context, 514 @IntRange(from = 0, to = 100) int percent) { 515 if (percent < 0 || percent > 100) { 516 throw new IllegalArgumentException("Percent must be 0~100"); 517 } 518 Settings.Global.putInt( 519 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent); 520 } 521 522 /** 523 * Get dns resolver samples range from {@link Settings}. 524 * 525 * @param context The {@link Context} to query the setting. 526 * @return The {@link Range<Integer>} of samples needed for statistics to be considered 527 * meaningful in the system DNS resolver. 528 */ 529 @NonNull getDnsResolverSampleRanges(@onNull Context context)530 public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) { 531 final int minSamples = Settings.Global.getInt(context.getContentResolver(), 532 DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES); 533 final int maxSamples = Settings.Global.getInt(context.getContentResolver(), 534 DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES); 535 return new Range<>(minSamples, maxSamples); 536 } 537 538 /** 539 * Set dns resolver samples range to {@link Settings}. 540 * 541 * @param context The {@link Context} to set the setting. 542 * @param range The samples range. The minimum number should be more than 0 and the maximum 543 * number should be less that 64. 544 */ setDnsResolverSampleRanges(@onNull Context context, @NonNull Range<Integer> range)545 public static void setDnsResolverSampleRanges(@NonNull Context context, 546 @NonNull Range<Integer> range) { 547 if (range.getLower() < 0 || range.getUpper() > 64) { 548 throw new IllegalArgumentException("Argument must be 0~64"); 549 } 550 Settings.Global.putInt( 551 context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower()); 552 Settings.Global.putInt( 553 context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper()); 554 } 555 556 /** 557 * Get maximum count (from {@link Settings}) of switching network notifications shown in 24 558 * hours. 559 * 560 * @param context The {@link Context} to query the setting. 561 * @param def The default value if no setting value. 562 * @return The maximum count of notifications shown in 24 hours when switching networks. 563 */ getNetworkSwitchNotificationMaximumDailyCount(@onNull Context context, int def)564 public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context, 565 int def) { 566 return Settings.Global.getInt( 567 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def); 568 } 569 570 /** 571 * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours. 572 * The count must be at least 0. 573 * 574 * @param context The {@link Context} to set the setting. 575 * @param count The maximum count of switching network notifications shown in 24 hours. 576 */ setNetworkSwitchNotificationMaximumDailyCount(@onNull Context context, @IntRange(from = 0) int count)577 public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context, 578 @IntRange(from = 0) int count) { 579 if (count < 0) { 580 throw new IllegalArgumentException("Count must be more than 0."); 581 } 582 Settings.Global.putInt( 583 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count); 584 } 585 586 /** 587 * Get minimum duration (from {@link Settings}) between each switching network notifications. 588 * 589 * @param context The {@link Context} to query the setting. 590 * @param def The default time if no setting value. 591 * @return The minimum duration between notifications when switching networks. 592 */ 593 @NonNull getNetworkSwitchNotificationRateDuration(@onNull Context context, @NonNull Duration def)594 public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context, 595 @NonNull Duration def) { 596 final int duration = Settings.Global.getInt(context.getContentResolver(), 597 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis()); 598 return Duration.ofMillis(duration); 599 } 600 601 /** 602 * Set minimum duration (to {@link Settings}) between each switching network notifications. 603 * The duration will be rounded down to the next millisecond, and must be positive. 604 * 605 * @param context The {@link Context} to set the setting. 606 * @param duration The minimum duration between notifications when switching networks. 607 */ setNetworkSwitchNotificationRateDuration(@onNull Context context, @NonNull Duration duration)608 public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context, 609 @NonNull Duration duration) { 610 final int time = (int) duration.toMillis(); 611 if (time < 0) { 612 throw new IllegalArgumentException("Invalid duration."); 613 } 614 Settings.Global.putInt(context.getContentResolver(), 615 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time); 616 } 617 618 /** 619 * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection. 620 * 621 * @param context The {@link Context} to query the setting. 622 * @return The URL used for HTTP captive portal detection upon a new connection. 623 */ 624 @Nullable getCaptivePortalHttpUrl(@onNull Context context)625 public static String getCaptivePortalHttpUrl(@NonNull Context context) { 626 return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL); 627 } 628 629 /** 630 * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection. 631 * The URL is accessed to check for connectivity and presence of a captive portal on a network. 632 * The URL should respond with HTTP status 204 to a GET request, and the stack will use 633 * redirection status as a signal for captive portal detection. 634 * If the URL is set to null or is otherwise incorrect or inaccessible, the stack will fail to 635 * detect connectivity and portals. This will often result in loss of connectivity. 636 * 637 * @param context The {@link Context} to set the setting. 638 * @param url The URL used for HTTP captive portal detection upon a new connection. 639 */ setCaptivePortalHttpUrl(@onNull Context context, @Nullable String url)640 public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) { 641 Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url); 642 } 643 644 /** 645 * Get mode (from {@link Settings}) when connecting a network that presents a captive portal. 646 * 647 * @param context The {@link Context} to query the setting. 648 * @param def The default mode if no setting value. 649 * @return The mode when connecting a network that presents a captive portal. 650 */ 651 @CaptivePortalMode getCaptivePortalMode(@onNull Context context, @CaptivePortalMode int def)652 public static int getCaptivePortalMode(@NonNull Context context, 653 @CaptivePortalMode int def) { 654 return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def); 655 } 656 657 /** 658 * Set mode (to {@link Settings}) when connecting a network that presents a captive portal. 659 * 660 * @param context The {@link Context} to set the setting. 661 * @param mode The mode when connecting a network that presents a captive portal. 662 */ setCaptivePortalMode(@onNull Context context, @CaptivePortalMode int mode)663 public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) { 664 if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE 665 || mode == CAPTIVE_PORTAL_MODE_PROMPT 666 || mode == CAPTIVE_PORTAL_MODE_AVOID)) { 667 throw new IllegalArgumentException("Invalid captive portal mode"); 668 } 669 Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode); 670 } 671 672 /** 673 * Get the global HTTP proxy applied to the device, or null if none. 674 * 675 * @param context The {@link Context} to query the setting. 676 * @return The {@link ProxyInfo} which build from global http proxy settings. 677 */ 678 @Nullable getGlobalProxy(@onNull Context context)679 public static ProxyInfo getGlobalProxy(@NonNull Context context) { 680 final String host = Settings.Global.getString( 681 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST); 682 final int port = Settings.Global.getInt( 683 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */); 684 final String exclusionList = Settings.Global.getString( 685 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST); 686 final String pacFileUrl = Settings.Global.getString( 687 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC); 688 689 if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) { 690 return null; // No global proxy. 691 } 692 693 if (TextUtils.isEmpty(pacFileUrl)) { 694 return ProxyInfo.buildDirectProxy( 695 host, port, ProxyUtils.exclusionStringAsList(exclusionList)); 696 } else { 697 return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl)); 698 } 699 } 700 701 /** 702 * Set global http proxy settings from given {@link ProxyInfo}. 703 * 704 * <p class="note"> 705 * While a {@link ProxyInfo} for a PAC proxy can be specified, not all devices support 706 * PAC proxies. In particular, smaller devices like watches often do not have the capabilities 707 * necessary to interpret the PAC file. In such cases, calling this API with a PAC proxy 708 * results in undefined behavior, including possibly breaking networking for applications. 709 * You can test for this by checking for the presence of {@link PackageManager.FEATURE_WEBVIEW}. 710 * </p> 711 * 712 * @param context The {@link Context} to set the setting. 713 * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from 714 * {@link ProxyInfo#buildPacProxy(Uri)} or 715 * {@link ProxyInfo#buildDirectProxy(String, int, List)} 716 * @throws UnsupportedOperationException if |proxyInfo| codes for a PAC proxy but the system 717 * does not support PAC proxies. 718 */ setGlobalProxy(@onNull Context context, @NonNull ProxyInfo proxyInfo)719 public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) { 720 final String host = proxyInfo.getHost(); 721 final int port = proxyInfo.getPort(); 722 final String exclusionList = proxyInfo.getExclusionListAsString(); 723 final String pacFileUrl = proxyInfo.getPacFileUrl().toString(); 724 725 726 if (!TextUtils.isEmpty(pacFileUrl)) { 727 final PackageManager pm = context.getPackageManager(); 728 if (null != pm && !pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) { 729 Log.wtf(TAG, "PAC proxy can't be installed on a device without FEATURE_WEBVIEW"); 730 } 731 } 732 733 if (TextUtils.isEmpty(pacFileUrl)) { 734 Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host); 735 Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port); 736 Settings.Global.putString( 737 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList); 738 Settings.Global.putString( 739 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */); 740 } else { 741 Settings.Global.putString( 742 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl); 743 Settings.Global.putString( 744 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */); 745 Settings.Global.putInt( 746 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */); 747 Settings.Global.putString( 748 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */); 749 } 750 } 751 752 /** 753 * Clear all global http proxy settings. 754 * 755 * @param context The {@link Context} to set the setting. 756 */ clearGlobalProxy(@onNull Context context)757 public static void clearGlobalProxy(@NonNull Context context) { 758 Settings.Global.putString( 759 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */); 760 Settings.Global.putInt( 761 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */); 762 Settings.Global.putString( 763 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */); 764 Settings.Global.putString( 765 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */); 766 } 767 768 /** 769 * Get private DNS mode from settings. 770 * 771 * @param context The Context to query the private DNS mode from settings. 772 * @return A string of private DNS mode. 773 */ 774 @PrivateDnsMode getPrivateDnsMode(@onNull Context context)775 public static int getPrivateDnsMode(@NonNull Context context) { 776 return ConnectivitySettingsUtils.getPrivateDnsMode(context); 777 } 778 779 /** 780 * Set private DNS mode to settings. 781 * 782 * @param context The {@link Context} to set the private DNS mode. 783 * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. 784 */ setPrivateDnsMode(@onNull Context context, @PrivateDnsMode int mode)785 public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) { 786 ConnectivitySettingsUtils.setPrivateDnsMode(context, mode); 787 } 788 789 /** 790 * Get specific private dns provider name from {@link Settings}. 791 * 792 * @param context The {@link Context} to query the setting. 793 * @return The specific private dns provider name, or null if no setting value. 794 */ 795 @Nullable getPrivateDnsHostname(@onNull Context context)796 public static String getPrivateDnsHostname(@NonNull Context context) { 797 return ConnectivitySettingsUtils.getPrivateDnsHostname(context); 798 } 799 800 /** 801 * Set specific private dns provider name to {@link Settings}. 802 * 803 * @param context The {@link Context} to set the setting. 804 * @param specifier The specific private dns provider name. 805 */ setPrivateDnsHostname(@onNull Context context, @Nullable String specifier)806 public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) { 807 ConnectivitySettingsUtils.setPrivateDnsHostname(context, specifier); 808 } 809 810 /** 811 * Get default private dns mode from {@link Settings}. 812 * 813 * @param context The {@link Context} to query the setting. 814 * @return The default private dns mode. 815 */ 816 @PrivateDnsMode 817 @NonNull getPrivateDnsDefaultMode(@onNull Context context)818 public static String getPrivateDnsDefaultMode(@NonNull Context context) { 819 return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE); 820 } 821 822 /** 823 * Set default private dns mode to {@link Settings}. 824 * 825 * @param context The {@link Context} to set the setting. 826 * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_* 827 * constants. 828 */ setPrivateDnsDefaultMode(@onNull Context context, @NonNull @PrivateDnsMode int mode)829 public static void setPrivateDnsDefaultMode(@NonNull Context context, 830 @NonNull @PrivateDnsMode int mode) { 831 if (!(mode == PRIVATE_DNS_MODE_OFF 832 || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC 833 || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { 834 throw new IllegalArgumentException("Invalid private dns mode"); 835 } 836 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, 837 getPrivateDnsModeAsString(mode)); 838 } 839 840 /** 841 * Get duration (from {@link Settings}) to keep a PendingIntent-based request. 842 * 843 * @param context The {@link Context} to query the setting. 844 * @param def The default duration if no setting value. 845 * @return The duration to keep a PendingIntent-based request. 846 */ 847 @NonNull getConnectivityKeepPendingIntentDuration(@onNull Context context, @NonNull Duration def)848 public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context, 849 @NonNull Duration def) { 850 final int duration = Settings.Secure.getInt(context.getContentResolver(), 851 CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis()); 852 return Duration.ofMillis(duration); 853 } 854 855 /** 856 * Set duration (to {@link Settings}) to keep a PendingIntent-based request. 857 * The duration will be rounded down to the next millisecond, and must be positive. 858 * 859 * @param context The {@link Context} to set the setting. 860 * @param duration The duration to keep a PendingIntent-based request. 861 */ setConnectivityKeepPendingIntentDuration(@onNull Context context, @NonNull Duration duration)862 public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context, 863 @NonNull Duration duration) { 864 final int time = (int) duration.toMillis(); 865 if (time < 0) { 866 throw new IllegalArgumentException("Invalid duration."); 867 } 868 Settings.Secure.putInt( 869 context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time); 870 } 871 872 /** 873 * Read from {@link Settings} whether the mobile data connection should remain active 874 * even when higher priority networks are active. 875 * 876 * @param context The {@link Context} to query the setting. 877 * @param def The default value if no setting value. 878 * @return Whether the mobile data connection should remain active even when higher 879 * priority networks are active. 880 */ getMobileDataAlwaysOn(@onNull Context context, boolean def)881 public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) { 882 final int enable = Settings.Global.getInt( 883 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0)); 884 return (enable != 0) ? true : false; 885 } 886 887 /** 888 * Write into {@link Settings} whether the mobile data connection should remain active 889 * even when higher priority networks are active. 890 * 891 * @param context The {@link Context} to set the setting. 892 * @param enable Whether the mobile data connection should remain active even when higher 893 * priority networks are active. 894 */ setMobileDataAlwaysOn(@onNull Context context, boolean enable)895 public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) { 896 Settings.Global.putInt( 897 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0)); 898 } 899 900 /** 901 * Read from {@link Settings} whether the wifi data connection should remain active 902 * even when higher priority networks are active. 903 * 904 * @param context The {@link Context} to query the setting. 905 * @param def The default value if no setting value. 906 * @return Whether the wifi data connection should remain active even when higher 907 * priority networks are active. 908 */ getWifiAlwaysRequested(@onNull Context context, boolean def)909 public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) { 910 final int enable = Settings.Global.getInt( 911 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0)); 912 return (enable != 0) ? true : false; 913 } 914 915 /** 916 * Write into {@link Settings} whether the wifi data connection should remain active 917 * even when higher priority networks are active. 918 * 919 * @param context The {@link Context} to set the setting. 920 * @param enable Whether the wifi data connection should remain active even when higher 921 * priority networks are active 922 */ setWifiAlwaysRequested(@onNull Context context, boolean enable)923 public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) { 924 Settings.Global.putInt( 925 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0)); 926 } 927 928 /** 929 * Get avoid bad wifi setting from {@link Settings}. 930 * 931 * @param context The {@link Context} to query the setting. 932 * @return The setting whether to automatically switch away from wifi networks that lose 933 * internet access. 934 */ 935 @NetworkAvoidBadWifi getNetworkAvoidBadWifi(@onNull Context context)936 public static int getNetworkAvoidBadWifi(@NonNull Context context) { 937 final String setting = 938 Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI); 939 if ("0".equals(setting)) { 940 return NETWORK_AVOID_BAD_WIFI_IGNORE; 941 } else if ("1".equals(setting)) { 942 return NETWORK_AVOID_BAD_WIFI_AVOID; 943 } else { 944 return NETWORK_AVOID_BAD_WIFI_PROMPT; 945 } 946 } 947 948 /** 949 * Set avoid bad wifi setting to {@link Settings}. 950 * 951 * @param context The {@link Context} to set the setting. 952 * @param value Whether to automatically switch away from wifi networks that lose internet 953 * access. 954 */ setNetworkAvoidBadWifi(@onNull Context context, @NetworkAvoidBadWifi int value)955 public static void setNetworkAvoidBadWifi(@NonNull Context context, 956 @NetworkAvoidBadWifi int value) { 957 final String setting; 958 if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) { 959 setting = "0"; 960 } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) { 961 setting = "1"; 962 } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) { 963 setting = null; 964 } else { 965 throw new IllegalArgumentException("Invalid avoid bad wifi setting"); 966 } 967 Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting); 968 } 969 970 /** 971 * Get network metered multipath preference from {@link Settings}. 972 * 973 * @param context The {@link Context} to query the setting. 974 * @return The network metered multipath preference which should be one of 975 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified 976 * by config_networkMeteredMultipathPreference is used. 977 */ 978 @Nullable getNetworkMeteredMultipathPreference(@onNull Context context)979 public static String getNetworkMeteredMultipathPreference(@NonNull Context context) { 980 return Settings.Global.getString( 981 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE); 982 } 983 984 /** 985 * Set network metered multipath preference to {@link Settings}. 986 * 987 * @param context The {@link Context} to set the setting. 988 * @param preference The network metered multipath preference which should be one of 989 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value 990 * specified by config_networkMeteredMultipathPreference is used. 991 */ setNetworkMeteredMultipathPreference(@onNull Context context, @NonNull @MultipathPreference String preference)992 public static void setNetworkMeteredMultipathPreference(@NonNull Context context, 993 @NonNull @MultipathPreference String preference) { 994 if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER 995 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY 996 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) { 997 throw new IllegalArgumentException("Invalid private dns mode"); 998 } 999 Settings.Global.putString( 1000 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference); 1001 } 1002 getUidSetFromString(@ullable String uidList)1003 private static Set<Integer> getUidSetFromString(@Nullable String uidList) { 1004 final Set<Integer> uids = new ArraySet<>(); 1005 if (TextUtils.isEmpty(uidList)) { 1006 return uids; 1007 } 1008 for (String uid : uidList.split(";")) { 1009 uids.add(Integer.valueOf(uid)); 1010 } 1011 return uids; 1012 } 1013 getUidStringFromSet(@onNull Set<Integer> uidList)1014 private static String getUidStringFromSet(@NonNull Set<Integer> uidList) { 1015 final StringJoiner joiner = new StringJoiner(";"); 1016 for (Integer uid : uidList) { 1017 if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) { 1018 throw new IllegalArgumentException("Invalid uid"); 1019 } 1020 joiner.add(uid.toString()); 1021 } 1022 return joiner.toString(); 1023 } 1024 1025 /** 1026 * Get the list of uids(from {@link Settings}) that should go on cellular networks in preference 1027 * even when higher-priority networks are connected. 1028 * 1029 * @param context The {@link Context} to query the setting. 1030 * @return A list of uids that should go on cellular networks in preference even when 1031 * higher-priority networks are connected or null if no setting value. 1032 */ 1033 @NonNull getMobileDataPreferredUids(@onNull Context context)1034 public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) { 1035 final String uidList = Settings.Secure.getString( 1036 context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS); 1037 return getUidSetFromString(uidList); 1038 } 1039 1040 /** 1041 * Set the list of uids(to {@link Settings}) that should go on cellular networks in preference 1042 * even when higher-priority networks are connected. 1043 * 1044 * @param context The {@link Context} to set the setting. 1045 * @param uidList A list of uids that should go on cellular networks in preference even when 1046 * higher-priority networks are connected. 1047 */ setMobileDataPreferredUids(@onNull Context context, @NonNull Set<Integer> uidList)1048 public static void setMobileDataPreferredUids(@NonNull Context context, 1049 @NonNull Set<Integer> uidList) { 1050 final String uids = getUidStringFromSet(uidList); 1051 Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, uids); 1052 } 1053 1054 /** 1055 * Get the list of uids (from {@link Settings}) allowed to use restricted networks. 1056 * 1057 * Access to restricted networks is controlled by the (preinstalled-only) 1058 * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission, but highly privileged 1059 * callers can also set a list of uids that can access restricted networks. 1060 * 1061 * This is useful for example in some jurisdictions where government apps, 1062 * that can't be preinstalled, must still have access to emergency services. 1063 * 1064 * @param context The {@link Context} to query the setting. 1065 * @return A list of uids that is allowed to use restricted networks or null if no setting 1066 * value. 1067 */ 1068 @NonNull getUidsAllowedOnRestrictedNetworks(@onNull Context context)1069 public static Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) { 1070 final String uidList = Settings.Global.getString( 1071 context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS); 1072 return getUidSetFromString(uidList); 1073 } 1074 isCallingFromSystem()1075 private static boolean isCallingFromSystem() { 1076 final int uid = Binder.getCallingUid(); 1077 final int pid = Binder.getCallingPid(); 1078 if (uid == Process.SYSTEM_UID && pid == Process.myPid()) { 1079 return true; 1080 } 1081 return false; 1082 } 1083 1084 /** 1085 * Set the list of uids(from {@link Settings}) that is allowed to use restricted networks. 1086 * 1087 * @param context The {@link Context} to set the setting. 1088 * @param uidList A list of uids that is allowed to use restricted networks. 1089 */ setUidsAllowedOnRestrictedNetworks(@onNull Context context, @NonNull Set<Integer> uidList)1090 public static void setUidsAllowedOnRestrictedNetworks(@NonNull Context context, 1091 @NonNull Set<Integer> uidList) { 1092 final boolean calledFromSystem = isCallingFromSystem(); 1093 if (!calledFromSystem) { 1094 // Enforce NETWORK_SETTINGS check if it's debug build. This is for MTS test only. 1095 if (!Build.isDebuggable()) { 1096 throw new SecurityException("Only system can set this setting."); 1097 } 1098 context.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS, 1099 "Requires NETWORK_SETTINGS permission"); 1100 } 1101 final String uids = getUidStringFromSet(uidList); 1102 Settings.Global.putString(context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS, 1103 uids); 1104 } 1105 1106 /** 1107 * Get the network bandwidth ingress rate limit. 1108 * 1109 * The limit is only applicable to networks that provide internet connectivity. -1 codes for no 1110 * bandwidth limitation. 1111 * 1112 * @param context The {@link Context} to query the setting. 1113 * @return The rate limit in number of bytes per second or -1 if disabled. 1114 */ getIngressRateLimitInBytesPerSecond(@onNull Context context)1115 public static long getIngressRateLimitInBytesPerSecond(@NonNull Context context) { 1116 return Settings.Global.getLong(context.getContentResolver(), 1117 INGRESS_RATE_LIMIT_BYTES_PER_SECOND, -1); 1118 } 1119 1120 /** 1121 * Set the network bandwidth ingress rate limit. 1122 * 1123 * The limit is applied to all networks that provide internet connectivity. It is applied on a 1124 * per-network basis, meaning that global ingress rate could exceed the limit when communicating 1125 * on multiple networks simultaneously. 1126 * 1127 * @param context The {@link Context} to set the setting. 1128 * @param rateLimitInBytesPerSec The rate limit in number of bytes per second or -1 to disable. 1129 */ setIngressRateLimitInBytesPerSecond(@onNull Context context, @IntRange(from = -1L, to = 0xFFFFFFFFL) long rateLimitInBytesPerSec)1130 public static void setIngressRateLimitInBytesPerSecond(@NonNull Context context, 1131 @IntRange(from = -1L, to = 0xFFFFFFFFL) long rateLimitInBytesPerSec) { 1132 if (rateLimitInBytesPerSec < -1) { 1133 throw new IllegalArgumentException( 1134 "Rate limit must be within the range [-1, Integer.MAX_VALUE]"); 1135 } 1136 Settings.Global.putLong(context.getContentResolver(), 1137 INGRESS_RATE_LIMIT_BYTES_PER_SECOND, 1138 rateLimitInBytesPerSec); 1139 } 1140 } 1141