blob: e133d5e53f4256a599db24d40e2841dc914cde43 [file] [log] [blame]
paulhu845456e2021-03-17 17:19:09 +08001/*
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
17package android.net;
18
paulhu94430952021-03-23 00:24:50 +080019import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
20import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
21import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
22import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
23import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
24import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
25
paulhuc9925e02021-03-17 20:30:33 +080026import android.annotation.IntDef;
paulhu94430952021-03-23 00:24:50 +080027import android.annotation.IntRange;
28import android.annotation.NonNull;
29import android.annotation.Nullable;
30import android.annotation.SystemApi;
31import android.content.Context;
32import android.net.ConnectivityManager.MultipathPreference;
33import android.net.ConnectivityManager.PrivateDnsMode;
34import android.provider.Settings;
35import android.text.TextUtils;
36import android.util.Range;
37
38import com.android.net.module.util.ProxyUtils;
paulhuc9925e02021-03-17 20:30:33 +080039
40import java.lang.annotation.Retention;
41import java.lang.annotation.RetentionPolicy;
paulhu94430952021-03-23 00:24:50 +080042import java.time.Duration;
43import java.util.List;
paulhuc9925e02021-03-17 20:30:33 +080044
paulhu845456e2021-03-17 17:19:09 +080045/**
46 * A manager class for connectivity module settings.
47 *
48 * @hide
49 */
paulhu94430952021-03-23 00:24:50 +080050@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
paulhu845456e2021-03-17 17:19:09 +080051public class ConnectivitySettingsManager {
52
53 private ConnectivitySettingsManager() {}
54
paulhuc9925e02021-03-17 20:30:33 +080055 /** Data activity timeout settings */
56
57 /**
58 * Inactivity timeout to track mobile data activity.
59 *
60 * If set to a positive integer, it indicates the inactivity timeout value in seconds to
61 * infer the data activity of mobile network. After a period of no activity on mobile
62 * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
63 * intent is fired to indicate a transition of network status from "active" to "idle". Any
64 * subsequent activity on mobile networks triggers the firing of {@code
65 * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
66 *
67 * Network activity refers to transmitting or receiving data on the network interfaces.
68 *
69 * Tracking is disabled if set to zero or negative value.
paulhu94430952021-03-23 00:24:50 +080070 *
71 * @hide
paulhuc9925e02021-03-17 20:30:33 +080072 */
73 public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
74
75 /**
76 * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
77 * but for Wifi network.
paulhu94430952021-03-23 00:24:50 +080078 *
79 * @hide
paulhuc9925e02021-03-17 20:30:33 +080080 */
81 public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
82
83 /** Dns resolver settings */
84
85 /**
86 * Sample validity in seconds to configure for the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +080087 *
88 * @hide
paulhuc9925e02021-03-17 20:30:33 +080089 */
90 public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
91 "dns_resolver_sample_validity_seconds";
92
93 /**
94 * Success threshold in percent for use with the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +080095 *
96 * @hide
paulhuc9925e02021-03-17 20:30:33 +080097 */
98 public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
99 "dns_resolver_success_threshold_percent";
100
101 /**
102 * Minimum number of samples needed for statistics to be considered meaningful in the
103 * system DNS resolver.
paulhu94430952021-03-23 00:24:50 +0800104 *
105 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800106 */
107 public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
108
109 /**
110 * Maximum number taken into account for statistics purposes in the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +0800111 *
112 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800113 */
114 public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
115
paulhu94430952021-03-23 00:24:50 +0800116 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
117 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
118
paulhuc9925e02021-03-17 20:30:33 +0800119 /** Network switch notification settings */
120
121 /**
122 * The maximum number of notifications shown in 24 hours when switching networks.
paulhu94430952021-03-23 00:24:50 +0800123 *
124 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800125 */
126 public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
127 "network_switch_notification_daily_limit";
128
129 /**
130 * The minimum time in milliseconds between notifications when switching networks.
paulhu94430952021-03-23 00:24:50 +0800131 *
132 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800133 */
134 public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
135 "network_switch_notification_rate_limit_millis";
136
137 /** Captive portal settings */
138
139 /**
140 * The URL used for HTTP captive portal detection upon a new connection.
141 * A 204 response code from the server is used for validation.
paulhu94430952021-03-23 00:24:50 +0800142 *
143 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800144 */
145 public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
146
147 /**
148 * What to do when connecting a network that presents a captive portal.
paulhu94430952021-03-23 00:24:50 +0800149 * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
paulhuc9925e02021-03-17 20:30:33 +0800150 *
151 * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
paulhu94430952021-03-23 00:24:50 +0800152 *
153 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800154 */
155 public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
156
157 /**
158 * Don't attempt to detect captive portals.
159 */
160 public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
161
162 /**
163 * When detecting a captive portal, display a notification that
164 * prompts the user to sign in.
165 */
166 public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
167
168 /**
169 * When detecting a captive portal, immediately disconnect from the
170 * network and do not reconnect to that network in the future.
171 */
172 public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
173
174 /** @hide */
175 @Retention(RetentionPolicy.SOURCE)
176 @IntDef(value = {
177 CAPTIVE_PORTAL_MODE_IGNORE,
178 CAPTIVE_PORTAL_MODE_PROMPT,
179 CAPTIVE_PORTAL_MODE_AVOID,
180 })
181 public @interface CaptivePortalMode {}
182
183 /** Global http proxy settings */
184
185 /**
186 * Host name for global http proxy. Set via ConnectivityManager.
paulhu94430952021-03-23 00:24:50 +0800187 *
188 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800189 */
190 public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
191
192 /**
193 * Integer host port for global http proxy. Set via ConnectivityManager.
paulhu94430952021-03-23 00:24:50 +0800194 *
195 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800196 */
197 public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
198
199 /**
200 * Exclusion list for global proxy. This string contains a list of
201 * comma-separated domains where the global proxy does not apply.
202 * Domains should be listed in a comma- separated list. Example of
203 * acceptable formats: ".domain1.com,my.domain2.com" Use
204 * ConnectivityManager to set/get.
paulhu94430952021-03-23 00:24:50 +0800205 *
206 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800207 */
208 public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
209 "global_http_proxy_exclusion_list";
210
211 /**
212 * The location PAC File for the proxy.
paulhu94430952021-03-23 00:24:50 +0800213 *
214 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800215 */
216 public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
217
218 /** Private dns settings */
219
220 /**
221 * The requested Private DNS mode (string), and an accompanying specifier (string).
222 *
223 * Currently, the specifier holds the chosen provider name when the mode requests
224 * a specific provider. It may be used to store the provider name even when the
225 * mode changes so that temporarily disabling and re-enabling the specific
226 * provider mode does not necessitate retyping the provider hostname.
paulhu94430952021-03-23 00:24:50 +0800227 *
228 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800229 */
230 public static final String PRIVATE_DNS_MODE = "private_dns_mode";
231
232 /**
233 * The specific Private DNS provider name.
paulhu94430952021-03-23 00:24:50 +0800234 *
235 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800236 */
237 public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
238
239 /**
240 * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
241 * This allows changing the default mode without effectively disabling other modes,
242 * all of which require explicit user action to enable/configure. See also b/79719289.
243 *
244 * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
paulhu94430952021-03-23 00:24:50 +0800245 *
246 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800247 */
248 public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
249
250 /** Other settings */
251
252 /**
253 * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
254 * the receivers of the PendingIntent an opportunity to make a new network request before
255 * the Network satisfying the request is potentially removed.
paulhu94430952021-03-23 00:24:50 +0800256 *
257 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800258 */
259 public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
260 "connectivity_release_pending_intent_delay_ms";
261
262 /**
263 * Whether the mobile data connection should remain active even when higher
264 * priority networks like WiFi are active, to help make network switching faster.
265 *
266 * See ConnectivityService for more info.
267 *
268 * (0 = disabled, 1 = enabled)
paulhu94430952021-03-23 00:24:50 +0800269 *
270 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800271 */
272 public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
273
274 /**
275 * Whether the wifi data connection should remain active even when higher
276 * priority networks like Ethernet are active, to keep both networks.
277 * In the case where higher priority networks are connected, wifi will be
278 * unused unless an application explicitly requests to use it.
279 *
280 * See ConnectivityService for more info.
281 *
282 * (0 = disabled, 1 = enabled)
paulhu94430952021-03-23 00:24:50 +0800283 *
284 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800285 */
286 public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
287
paulhu845456e2021-03-17 17:19:09 +0800288 /**
289 * Whether to automatically switch away from wifi networks that lose Internet access.
290 * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
291 * avoids such networks. Valid values are:
292 *
293 * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
294 * null: Ask the user whether to switch away from bad wifi.
295 * 1: Avoid bad wifi.
paulhu94430952021-03-23 00:24:50 +0800296 *
297 * @hide
paulhu845456e2021-03-17 17:19:09 +0800298 */
299 public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
300
301 /**
paulhu94430952021-03-23 00:24:50 +0800302 * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
303 */
304 public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
305
306 /**
307 * Ask the user whether to switch away from bad wifi.
308 */
309 public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
310
311 /**
312 * Avoid bad wifi.
313 */
314 public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
315
316 /** @hide */
317 @Retention(RetentionPolicy.SOURCE)
318 @IntDef(value = {
319 NETWORK_AVOID_BAD_WIFI_IGNORE,
320 NETWORK_AVOID_BAD_WIFI_PROMPT,
321 NETWORK_AVOID_BAD_WIFI_AVOID,
322 })
323 public @interface NetworkAvoidBadWifi {}
324
325 /**
paulhu845456e2021-03-17 17:19:09 +0800326 * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
327 * overridden by the system based on device or application state. If null, the value
328 * specified by config_networkMeteredMultipathPreference is used.
paulhu94430952021-03-23 00:24:50 +0800329 *
330 * @hide
paulhu845456e2021-03-17 17:19:09 +0800331 */
332 public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
333 "network_metered_multipath_preference";
paulhu94430952021-03-23 00:24:50 +0800334
335 /**
336 * Get mobile data activity timeout from {@link Settings}.
337 *
338 * @param context The {@link Context} to query the setting.
339 * @param def The default timeout if no setting value.
340 * @return The {@link Duration} of timeout to track mobile data activity.
341 */
342 @NonNull
343 public static Duration getMobileDataActivityTimeout(@NonNull Context context,
344 @NonNull Duration def) {
345 final int timeout = Settings.Global.getInt(
346 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
347 return Duration.ofSeconds(timeout);
348 }
349
350 /**
351 * Set mobile data activity timeout to {@link Settings}.
352 * Tracking is disabled if set to zero or negative value.
353 *
354 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
355 * ignored.
356 *
357 * @param context The {@link Context} to set the setting.
358 * @param timeout The mobile data activity timeout.
359 */
360 public static void setMobileDataActivityTimeout(@NonNull Context context,
361 @NonNull Duration timeout) {
362 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
363 (int) timeout.getSeconds());
364 }
365
366 /**
367 * Get wifi data activity timeout from {@link Settings}.
368 *
369 * @param context The {@link Context} to query the setting.
370 * @param def The default timeout if no setting value.
371 * @return The {@link Duration} of timeout to track wifi data activity.
372 */
373 @NonNull
374 public static Duration getWifiDataActivityTimeout(@NonNull Context context,
375 @NonNull Duration def) {
376 final int timeout = Settings.Global.getInt(
377 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
378 return Duration.ofSeconds(timeout);
379 }
380
381 /**
382 * Set wifi data activity timeout to {@link Settings}.
383 * Tracking is disabled if set to zero or negative value.
384 *
385 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
386 * ignored.
387 *
388 * @param context The {@link Context} to set the setting.
389 * @param timeout The wifi data activity timeout.
390 */
391 public static void setWifiDataActivityTimeout(@NonNull Context context,
392 @NonNull Duration timeout) {
393 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
394 (int) timeout.getSeconds());
395 }
396
397 /**
398 * Get dns resolver sample validity duration from {@link Settings}.
399 *
400 * @param context The {@link Context} to query the setting.
401 * @param def The default duration if no setting value.
402 * @return The {@link Duration} of sample validity duration to configure for the system DNS
403 * resolver.
404 */
405 @NonNull
406 public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
407 @NonNull Duration def) {
408 final int duration = Settings.Global.getInt(context.getContentResolver(),
409 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
410 return Duration.ofSeconds(duration);
411 }
412
413 /**
414 * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
415 * positive number of seconds.
416 *
417 * @param context The {@link Context} to set the setting.
418 * @param duration The sample validity duration.
419 */
420 public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
421 @NonNull Duration duration) {
422 final int time = (int) duration.getSeconds();
423 if (time <= 0) {
424 throw new IllegalArgumentException("Invalid duration");
425 }
426 Settings.Global.putInt(
427 context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
428 }
429
430 /**
431 * Get dns resolver success threshold percent from {@link Settings}.
432 *
433 * @param context The {@link Context} to query the setting.
434 * @param def The default value if no setting value.
435 * @return The success threshold in percent for use with the system DNS resolver.
436 */
437 public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
438 return Settings.Global.getInt(
439 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
440 }
441
442 /**
443 * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
444 * be 0~100.
445 *
446 * @param context The {@link Context} to set the setting.
447 * @param percent The success threshold percent.
448 */
449 public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
450 @IntRange(from = 0, to = 100) int percent) {
451 if (percent < 0 || percent > 100) {
452 throw new IllegalArgumentException("Percent must be 0~100");
453 }
454 Settings.Global.putInt(
455 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
456 }
457
458 /**
459 * Get dns resolver samples range from {@link Settings}.
460 *
461 * @param context The {@link Context} to query the setting.
462 * @return The {@link Range<Integer>} of samples needed for statistics to be considered
463 * meaningful in the system DNS resolver.
464 */
465 @NonNull
466 public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
467 final int minSamples = Settings.Global.getInt(context.getContentResolver(),
468 DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
469 final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
470 DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
471 return new Range<>(minSamples, maxSamples);
472 }
473
474 /**
475 * Set dns resolver samples range to {@link Settings}.
476 *
477 * @param context The {@link Context} to set the setting.
478 * @param range The samples range. The minimum number should be more than 0 and the maximum
479 * number should be less that 64.
480 */
481 public static void setDnsResolverSampleRanges(@NonNull Context context,
482 @NonNull Range<Integer> range) {
483 if (range.getLower() < 0 || range.getUpper() > 64) {
484 throw new IllegalArgumentException("Argument must be 0~64");
485 }
486 Settings.Global.putInt(
487 context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
488 Settings.Global.putInt(
489 context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
490 }
491
492 /**
493 * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
494 * hours.
495 *
496 * @param context The {@link Context} to query the setting.
497 * @param def The default value if no setting value.
498 * @return The maximum count of notifications shown in 24 hours when switching networks.
499 */
500 public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
501 int def) {
502 return Settings.Global.getInt(
503 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
504 }
505
506 /**
507 * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
508 * The count must be at least 0.
509 *
510 * @param context The {@link Context} to set the setting.
511 * @param count The maximum count of switching network notifications shown in 24 hours.
512 */
513 public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
514 @IntRange(from = 0) int count) {
515 if (count < 0) {
516 throw new IllegalArgumentException("Count must be 0~10.");
517 }
518 Settings.Global.putInt(
519 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
520 }
521
522 /**
523 * Get minimum duration (from {@link Settings}) between each switching network notifications.
524 *
525 * @param context The {@link Context} to query the setting.
526 * @param def The default time if no setting value.
527 * @return The minimum duration between notifications when switching networks.
528 */
529 @NonNull
530 public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
531 @NonNull Duration def) {
532 final int duration = Settings.Global.getInt(context.getContentResolver(),
533 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
534 return Duration.ofMillis(duration);
535 }
536
537 /**
538 * Set minimum duration (to {@link Settings}) between each switching network notifications.
539 *
540 * @param context The {@link Context} to set the setting.
541 * @param duration The minimum duration between notifications when switching networks.
542 */
543 public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
544 @NonNull Duration duration) {
545 final int time = (int) duration.toMillis();
546 if (time < 0) {
547 throw new IllegalArgumentException("Invalid duration.");
548 }
549 Settings.Global.putInt(context.getContentResolver(),
550 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
551 }
552
553 /**
554 * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
555 *
556 * @param context The {@link Context} to query the setting.
557 * @return The URL used for HTTP captive portal detection upon a new connection.
558 */
559 @Nullable
560 public static String getCaptivePortalHttpUrl(@NonNull Context context) {
561 return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
562 }
563
564 /**
565 * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
566 * This URL should respond with a 204 response to a GET request to indicate no captive portal is
567 * present. And this URL must be HTTP as redirect responses are used to find captive portal
568 * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal
569 * detection failed and lost the connection.
570 *
571 * @param context The {@link Context} to set the setting.
572 * @param url The URL used for HTTP captive portal detection upon a new connection.
573 */
574 public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
575 Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
576 }
577
578 /**
579 * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
580 *
581 * @param context The {@link Context} to query the setting.
582 * @param def The default mode if no setting value.
583 * @return The mode when connecting a network that presents a captive portal.
584 */
585 @CaptivePortalMode
586 public static int getCaptivePortalMode(@NonNull Context context,
587 @CaptivePortalMode int def) {
588 return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
589 }
590
591 /**
592 * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
593 *
594 * @param context The {@link Context} to set the setting.
595 * @param mode The mode when connecting a network that presents a captive portal.
596 */
597 public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
598 if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
599 || mode == CAPTIVE_PORTAL_MODE_PROMPT
600 || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
601 throw new IllegalArgumentException("Invalid captive portal mode");
602 }
603 Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
604 }
605
606 /**
607 * Get the global HTTP proxy applied to the device, or null if none.
608 *
609 * @param context The {@link Context} to query the setting.
610 * @return The {@link ProxyInfo} which build from global http proxy settings.
611 */
612 @Nullable
613 public static ProxyInfo getGlobalProxy(@NonNull Context context) {
614 final String host = Settings.Global.getString(
615 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
616 final int port = Settings.Global.getInt(
617 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
618 final String exclusionList = Settings.Global.getString(
619 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
620 final String pacFileUrl = Settings.Global.getString(
621 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
622
623 if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
624 return null; // No global proxy.
625 }
626
627 if (TextUtils.isEmpty(pacFileUrl)) {
628 return ProxyInfo.buildDirectProxy(
629 host, port, ProxyUtils.exclusionStringAsList(exclusionList));
630 } else {
631 return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
632 }
633 }
634
635 /**
636 * Set global http proxy settings from given {@link ProxyInfo}.
637 *
638 * @param context The {@link Context} to set the setting.
639 * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
640 * {@link ProxyInfo#buildPacProxy(Uri)} or
641 * {@link ProxyInfo#buildDirectProxy(String, int, List)}
642 */
643 public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
644 final String host = proxyInfo.getHost();
645 final int port = proxyInfo.getPort();
646 final String exclusionList = proxyInfo.getExclusionListAsString();
647 final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
648
649 if (TextUtils.isEmpty(pacFileUrl)) {
650 Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
651 Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
652 Settings.Global.putString(
653 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
654 Settings.Global.putString(
655 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
656 } else {
657 Settings.Global.putString(
658 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
659 Settings.Global.putString(
660 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
661 Settings.Global.putInt(
662 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
663 Settings.Global.putString(
664 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
665 }
666 }
667
668 /**
669 * Clear all global http proxy settings.
670 *
671 * @param context The {@link Context} to set the setting.
672 */
673 public static void clearGlobalProxy(@NonNull Context context) {
674 Settings.Global.putString(
675 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
676 Settings.Global.putInt(
677 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
678 Settings.Global.putString(
679 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
680 Settings.Global.putString(
681 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
682 }
683
684 /**
685 * Get specific private dns provider name from {@link Settings}.
686 *
687 * @param context The {@link Context} to query the setting.
688 * @return The specific private dns provider name, or null if no setting value.
689 */
690 @Nullable
691 public static String getPrivateDnsHostname(@NonNull Context context) {
692 return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER);
693 }
694
695 /**
696 * Set specific private dns provider name to {@link Settings}.
697 *
698 * @param context The {@link Context} to set the setting.
699 * @param specifier The specific private dns provider name.
700 */
701 public static void setPrivateDnsHostname(@NonNull Context context,
702 @Nullable String specifier) {
703 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier);
704 }
705
706 /**
707 * Get default private dns mode from {@link Settings}.
708 *
709 * @param context The {@link Context} to query the setting.
710 * @return The default private dns mode.
711 */
712 @PrivateDnsMode
713 @NonNull
714 public static String getPrivateDnsDefaultMode(@NonNull Context context) {
715 return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
716 }
717
718 /**
719 * Set default private dns mode to {@link Settings}.
720 *
721 * @param context The {@link Context} to set the setting.
722 * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
723 * constants.
724 */
725 public static void setPrivateDnsDefaultMode(@NonNull Context context,
726 @NonNull @PrivateDnsMode String mode) {
727 if (!(mode == PRIVATE_DNS_MODE_OFF
728 || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
729 || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
730 throw new IllegalArgumentException("Invalid private dns mode");
731 }
732 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode);
733 }
734
735 /**
736 * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
737 *
738 * @param context The {@link Context} to query the setting.
739 * @param def The default duration if no setting value.
740 * @return The duration to keep a PendingIntent-based request.
741 */
742 @NonNull
743 public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
744 @NonNull Duration def) {
745 final int duration = Settings.Secure.getInt(context.getContentResolver(),
746 CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
747 return Duration.ofMillis(duration);
748 }
749
750 /**
751 * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
752 *
753 * @param context The {@link Context} to set the setting.
754 * @param duration The duration to keep a PendingIntent-based request.
755 */
756 public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
757 @NonNull Duration duration) {
758 final int time = (int) duration.toMillis();
759 if (time < 0) {
760 throw new IllegalArgumentException("Invalid duration.");
761 }
762 Settings.Secure.putInt(
763 context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
764 }
765
766 /**
767 * Read from {@link Settings} whether the mobile data connection should remain active
768 * even when higher priority networks are active.
769 *
770 * @param context The {@link Context} to query the setting.
771 * @param def The default value if no setting value.
772 * @return Whether the mobile data connection should remain active even when higher
773 * priority networks are active.
774 */
775 public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
776 final int enable = Settings.Global.getInt(
777 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
778 return (enable != 0) ? true : false;
779 }
780
781 /**
782 * Write into {@link Settings} whether the mobile data connection should remain active
783 * even when higher priority networks are active.
784 *
785 * @param context The {@link Context} to set the setting.
786 * @param enable Whether the mobile data connection should remain active even when higher
787 * priority networks are active.
788 */
789 public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
790 Settings.Global.putInt(
791 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
792 }
793
794 /**
795 * Read from {@link Settings} whether the wifi data connection should remain active
796 * even when higher priority networks are active.
797 *
798 * @param context The {@link Context} to query the setting.
799 * @param def The default value if no setting value.
800 * @return Whether the wifi data connection should remain active even when higher
801 * priority networks are active.
802 */
803 public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
804 final int enable = Settings.Global.getInt(
805 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
806 return (enable != 0) ? true : false;
807 }
808
809 /**
810 * Write into {@link Settings} whether the wifi data connection should remain active
811 * even when higher priority networks are active.
812 *
813 * @param context The {@link Context} to set the setting.
814 * @param enable Whether the wifi data connection should remain active even when higher
815 * priority networks are active
816 */
817 public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
818 Settings.Global.putInt(
819 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
820 }
821
822 /**
823 * Get avoid bad wifi setting from {@link Settings}.
824 *
825 * @param context The {@link Context} to query the setting.
826 * @return The setting whether to automatically switch away from wifi networks that lose
827 * internet access.
828 */
829 @NetworkAvoidBadWifi
830 public static int getNetworkAvoidBadWifi(@NonNull Context context) {
831 final String setting =
832 Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
833 if ("0".equals(setting)) {
834 return NETWORK_AVOID_BAD_WIFI_IGNORE;
835 } else if ("1".equals(setting)) {
836 return NETWORK_AVOID_BAD_WIFI_AVOID;
837 } else {
838 return NETWORK_AVOID_BAD_WIFI_PROMPT;
839 }
840 }
841
842 /**
843 * Set avoid bad wifi setting to {@link Settings}.
844 *
845 * @param context The {@link Context} to set the setting.
846 * @param value Whether to automatically switch away from wifi networks that lose internet
847 * access.
848 */
849 public static void setNetworkAvoidBadWifi(@NonNull Context context,
850 @NetworkAvoidBadWifi int value) {
851 final String setting;
852 if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
853 setting = "0";
854 } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
855 setting = "1";
856 } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
857 setting = null;
858 } else {
859 throw new IllegalArgumentException("Invalid avoid bad wifi setting");
860 }
861 Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
862 }
863
864 /**
865 * Get network metered multipath preference from {@link Settings}.
866 *
867 * @param context The {@link Context} to query the setting.
868 * @return The network metered multipath preference which should be one of
869 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
870 * by config_networkMeteredMultipathPreference is used.
871 */
872 @Nullable
873 public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
874 return Settings.Global.getString(
875 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
876 }
877
878 /**
879 * Set network metered multipath preference to {@link Settings}.
880 *
881 * @param context The {@link Context} to set the setting.
882 * @param preference The network metered multipath preference which should be one of
883 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
884 * specified by config_networkMeteredMultipathPreference is used.
885 */
886 public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
887 @NonNull @MultipathPreference String preference) {
888 if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
889 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
890 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
891 throw new IllegalArgumentException("Invalid private dns mode");
892 }
893 Settings.Global.putString(
894 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
895 }
paulhu845456e2021-03-17 17:19:09 +0800896}