blob: 01e0726ac492d3dfd14ff707e13a437b6400bb82 [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;
paulhu94430952021-03-23 00:24:50 +080022
lucaslin89621282021-06-21 16:39:08 +080023import static com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString;
24
paulhuc9925e02021-03-17 20:30:33 +080025import android.annotation.IntDef;
paulhu94430952021-03-23 00:24:50 +080026import android.annotation.IntRange;
27import android.annotation.NonNull;
28import android.annotation.Nullable;
29import android.annotation.SystemApi;
30import android.content.Context;
Chalard Jeanc8ef2192023-04-14 13:18:37 +090031import android.content.pm.PackageManager;
paulhu94430952021-03-23 00:24:50 +080032import android.net.ConnectivityManager.MultipathPreference;
paulhu92f128c2021-07-01 18:04:45 +080033import android.os.Binder;
34import android.os.Build;
paulhu344c1162021-05-11 09:42:50 +080035import android.os.Process;
36import android.os.UserHandle;
paulhu94430952021-03-23 00:24:50 +080037import android.provider.Settings;
38import android.text.TextUtils;
paulhu69afcd52021-04-27 00:14:47 +080039import android.util.ArraySet;
Chalard Jeanc8ef2192023-04-14 13:18:37 +090040import android.util.Log;
paulhu94430952021-03-23 00:24:50 +080041import android.util.Range;
42
lucaslin89621282021-06-21 16:39:08 +080043import com.android.net.module.util.ConnectivitySettingsUtils;
paulhu94430952021-03-23 00:24:50 +080044import com.android.net.module.util.ProxyUtils;
paulhuc9925e02021-03-17 20:30:33 +080045
46import java.lang.annotation.Retention;
47import java.lang.annotation.RetentionPolicy;
paulhu94430952021-03-23 00:24:50 +080048import java.time.Duration;
49import java.util.List;
paulhu69afcd52021-04-27 00:14:47 +080050import java.util.Set;
51import java.util.StringJoiner;
paulhuc9925e02021-03-17 20:30:33 +080052
paulhu845456e2021-03-17 17:19:09 +080053/**
54 * A manager class for connectivity module settings.
55 *
56 * @hide
57 */
paulhu94430952021-03-23 00:24:50 +080058@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
paulhu845456e2021-03-17 17:19:09 +080059public class ConnectivitySettingsManager {
Chalard Jeanc8ef2192023-04-14 13:18:37 +090060 private static final String TAG = ConnectivitySettingsManager.class.getSimpleName();
paulhu845456e2021-03-17 17:19:09 +080061
62 private ConnectivitySettingsManager() {}
63
paulhuc9925e02021-03-17 20:30:33 +080064 /** 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.
paulhu94430952021-03-23 00:24:50 +080079 *
80 * @hide
paulhuc9925e02021-03-17 20:30:33 +080081 */
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.
paulhu94430952021-03-23 00:24:50 +080087 *
88 * @hide
paulhuc9925e02021-03-17 20:30:33 +080089 */
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.
paulhu94430952021-03-23 00:24:50 +080096 *
97 * @hide
paulhuc9925e02021-03-17 20:30:33 +080098 */
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.
paulhu94430952021-03-23 00:24:50 +0800104 *
105 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800106 */
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.
paulhu94430952021-03-23 00:24:50 +0800113 *
114 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800115 */
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.
paulhu94430952021-03-23 00:24:50 +0800120 *
121 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800122 */
123 public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
124
paulhu94430952021-03-23 00:24:50 +0800125 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
126 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
127
paulhuc9925e02021-03-17 20:30:33 +0800128 /** Network switch notification settings */
129
130 /**
131 * The maximum number of notifications shown in 24 hours when switching networks.
paulhu94430952021-03-23 00:24:50 +0800132 *
133 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800134 */
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.
paulhu94430952021-03-23 00:24:50 +0800140 *
141 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800142 */
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.
paulhu94430952021-03-23 00:24:50 +0800151 *
152 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800153 */
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.
paulhu94430952021-03-23 00:24:50 +0800158 * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
paulhuc9925e02021-03-17 20:30:33 +0800159 *
160 * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
paulhu94430952021-03-23 00:24:50 +0800161 *
162 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800163 */
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
Andriy Naborskyyd032dd42023-09-26 02:03:18 +0000179 * 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.
paulhuc9925e02021-03-17 20:30:33 +0800182 */
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.
paulhu94430952021-03-23 00:24:50 +0800198 *
199 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800200 */
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.
paulhu94430952021-03-23 00:24:50 +0800205 *
206 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800207 */
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.
paulhu94430952021-03-23 00:24:50 +0800216 *
217 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800218 */
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.
paulhu94430952021-03-23 00:24:50 +0800224 *
225 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800226 */
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.
paulhu94430952021-03-23 00:24:50 +0800238 *
239 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800240 */
241 public static final String PRIVATE_DNS_MODE = "private_dns_mode";
242
243 /**
244 * The specific Private DNS provider name.
paulhu94430952021-03-23 00:24:50 +0800245 *
246 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800247 */
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.
paulhu94430952021-03-23 00:24:50 +0800256 *
257 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800258 */
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.
paulhu94430952021-03-23 00:24:50 +0800267 *
268 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800269 */
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)
paulhu94430952021-03-23 00:24:50 +0800280 *
281 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800282 */
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)
paulhu94430952021-03-23 00:24:50 +0800294 *
295 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800296 */
297 public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
298
paulhu845456e2021-03-17 17:19:09 +0800299 /**
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.
paulhu94430952021-03-23 00:24:50 +0800307 *
308 * @hide
paulhu845456e2021-03-17 17:19:09 +0800309 */
310 public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
311
312 /**
paulhu94430952021-03-23 00:24:50 +0800313 * 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 /**
paulhu845456e2021-03-17 17:19:09 +0800337 * 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.
paulhu94430952021-03-23 00:24:50 +0800340 *
341 * @hide
paulhu845456e2021-03-17 17:19:09 +0800342 */
343 public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
344 "network_metered_multipath_preference";
paulhu94430952021-03-23 00:24:50 +0800345
346 /**
paulhu344c1162021-05-11 09:42:50 +0800347 * A list of uids that should go on cellular networks in preference even when higher-priority
paulhu7a4eeed2021-03-25 13:17:58 +0800348 * networks are connected.
349 *
350 * @hide
351 */
paulhu344c1162021-05-11 09:42:50 +0800352 public static final String MOBILE_DATA_PREFERRED_UIDS = "mobile_data_preferred_uids";
paulhu7a4eeed2021-03-25 13:17:58 +0800353
354 /**
lucaslin57f9ba82021-04-23 21:03:39 +0800355 * One of the private DNS modes that indicates the private DNS mode is off.
356 */
lucaslin89621282021-06-21 16:39:08 +0800357 public static final int PRIVATE_DNS_MODE_OFF = ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OFF;
lucaslin57f9ba82021-04-23 21:03:39 +0800358
359 /**
Tad09fdd2b2021-12-21 05:13:40 +0530360 * @hide
361 */
362 public static final int PRIVATE_DNS_MODE_ADGUARD =
363 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_ADGUARD;
364
365 /**
366 * @hide
367 */
368 public static final int PRIVATE_DNS_MODE_APPLIEDPRIVACY =
369 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_APPLIEDPRIVACY;
370
371 /**
372 * @hide
373 */
374 public static final int PRIVATE_DNS_MODE_CLEANBROWSING =
375 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_CLEANBROWSING;
376
377 /**
378 * @hide
379 */
380 public static final int PRIVATE_DNS_MODE_CIRA =
381 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_CIRA;
382
383 /**
384 * @hide
385 */
386 public static final int PRIVATE_DNS_MODE_CZNIC =
387 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_CZNIC;
388
389 /**
390 * @hide
391 */
392 public static final int PRIVATE_DNS_MODE_CLOUDFLARE =
393 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_CLOUDFLARE;
394
395 /**
396 * @hide
397 */
398 public static final int PRIVATE_DNS_MODE_GOOGLE =
399 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_GOOGLE;
400
401 /**
402 * @hide
403 */
404 public static final int PRIVATE_DNS_MODE_MULLVAD =
405 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_MULLVAD;
406
407 /**
408 * @hide
409 */
410 public static final int PRIVATE_DNS_MODE_QUADNINE =
411 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_QUADNINE;
412
413 /**
414 * @hide
415 */
416 public static final int PRIVATE_DNS_MODE_RESTENA =
417 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_RESTENA;
418
419 /**
420 * @hide
421 */
422 public static final int PRIVATE_DNS_MODE_SWITCH =
423 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_SWITCH;
424
425 /**
426 * @hide
427 */
428 public static final int PRIVATE_DNS_MODE_TWNIC =
429 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_TWNIC;
430
431 /**
432 * @hide
433 */
434 public static final int PRIVATE_DNS_MODE_UNCENSOREDDNS =
435 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_UNCENSOREDDNS;
436
437 /**
lucaslin57f9ba82021-04-23 21:03:39 +0800438 * One of the private DNS modes that indicates the private DNS mode is automatic, which
439 * will try to use the current DNS as private DNS.
440 */
lucaslin89621282021-06-21 16:39:08 +0800441 public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC =
442 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OPPORTUNISTIC;
lucaslin57f9ba82021-04-23 21:03:39 +0800443
444 /**
445 * One of the private DNS modes that indicates the private DNS mode is strict and the
446 * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of
447 * {@link #PRIVATE_DNS_SPECIFIER} as private DNS.
448 */
lucaslin89621282021-06-21 16:39:08 +0800449 public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME =
450 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
lucaslin57f9ba82021-04-23 21:03:39 +0800451
Tad09fdd2b2021-12-21 05:13:40 +0530452 /**
453 * @hide
454 */
455 public static final String PRIVATE_DNS_SPECIFIER_ADGUARD = "dns.adguard.com";
456
457 /**
458 * @hide
459 */
460 public static final String PRIVATE_DNS_SPECIFIER_APPLIEDPRIVACY = "dot1.applied-privacy.net";
461
462 /**
463 * @hide
464 */
465 public static final String PRIVATE_DNS_SPECIFIER_CIRA = "protected.canadianshield.cira.ca";
466
467 /**
468 * @hide
469 */
470 public static final String PRIVATE_DNS_SPECIFIER_CZNIC = "odvr.nic.cz";
471
472 /**
473 * @hide
474 */
475 public static final String PRIVATE_DNS_SPECIFIER_CLEANBROWSING = "security-filter-dns.cleanbrowsing.org";
476
477 /**
478 * @hide
479 */
480 public static final String PRIVATE_DNS_SPECIFIER_CLOUDFLARE = "security.cloudflare-dns.com";
481
482 /**
483 * @hide
484 */
485 public static final String PRIVATE_DNS_SPECIFIER_GOOGLE = "dns.google";
486
487 /**
488 * @hide
489 */
490 public static final String PRIVATE_DNS_SPECIFIER_MULLVAD = "adblock.doh.mullvad.net";
491
492 /**
493 * @hide
494 */
495 public static final String PRIVATE_DNS_SPECIFIER_QUADNINE = "dns.quad9.net";
496
497 /**
498 * @hide
499 */
500 public static final String PRIVATE_DNS_SPECIFIER_RESTENA = "kaitain.restena.lu";
501
502 /**
503 * @hide
504 */
505 public static final String PRIVATE_DNS_SPECIFIER_SWITCH = "dns.switch.ch";
506
507 /**
508 * @hide
509 */
510 public static final String PRIVATE_DNS_SPECIFIER_TWNIC = "101.101.101.101";
511
512 /**
513 * @hide
514 */
515 public static final String PRIVATE_DNS_SPECIFIER_UNCENSOREDDNS = "unicast.censurfridns.dk";
516
517
lucaslin57f9ba82021-04-23 21:03:39 +0800518 /** @hide */
519 @Retention(RetentionPolicy.SOURCE)
520 @IntDef(value = {
521 PRIVATE_DNS_MODE_OFF,
Tad09fdd2b2021-12-21 05:13:40 +0530522 PRIVATE_DNS_MODE_ADGUARD,
523 PRIVATE_DNS_MODE_APPLIEDPRIVACY,
524 PRIVATE_DNS_MODE_CLEANBROWSING,
525 PRIVATE_DNS_MODE_CIRA,
526 PRIVATE_DNS_MODE_CZNIC,
527 PRIVATE_DNS_MODE_CLOUDFLARE,
528 PRIVATE_DNS_MODE_GOOGLE,
529 PRIVATE_DNS_MODE_MULLVAD,
530 PRIVATE_DNS_MODE_QUADNINE,
531 PRIVATE_DNS_MODE_RESTENA,
532 PRIVATE_DNS_MODE_SWITCH,
533 PRIVATE_DNS_MODE_TWNIC,
534 PRIVATE_DNS_MODE_UNCENSOREDDNS,
lucaslin57f9ba82021-04-23 21:03:39 +0800535 PRIVATE_DNS_MODE_OPPORTUNISTIC,
536 PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
537 })
538 public @interface PrivateDnsMode {}
539
lucaslin57f9ba82021-04-23 21:03:39 +0800540 /**
paulhu91e78062021-05-26 16:16:57 +0800541 * A list of uids that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +0800542 *
543 * @hide
544 */
paulhu91e78062021-05-26 16:16:57 +0800545 public static final String UIDS_ALLOWED_ON_RESTRICTED_NETWORKS =
546 "uids_allowed_on_restricted_networks";
paulhu69afcd52021-04-27 00:14:47 +0800547
548 /**
Patrick Rohra2084362022-01-03 15:55:52 +0100549 * A global rate limit that applies to all networks with NET_CAPABILITY_INTERNET when enabled.
550 *
551 * @hide
552 */
553 public static final String INGRESS_RATE_LIMIT_BYTES_PER_SECOND =
554 "ingress_rate_limit_bytes_per_second";
555
556 /**
paulhu94430952021-03-23 00:24:50 +0800557 * Get mobile data activity timeout from {@link Settings}.
558 *
559 * @param context The {@link Context} to query the setting.
560 * @param def The default timeout if no setting value.
561 * @return The {@link Duration} of timeout to track mobile data activity.
562 */
563 @NonNull
564 public static Duration getMobileDataActivityTimeout(@NonNull Context context,
565 @NonNull Duration def) {
566 final int timeout = Settings.Global.getInt(
567 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
568 return Duration.ofSeconds(timeout);
569 }
570
571 /**
572 * Set mobile data activity timeout to {@link Settings}.
573 * Tracking is disabled if set to zero or negative value.
574 *
575 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
576 * ignored.
577 *
578 * @param context The {@link Context} to set the setting.
579 * @param timeout The mobile data activity timeout.
580 */
581 public static void setMobileDataActivityTimeout(@NonNull Context context,
582 @NonNull Duration timeout) {
583 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
584 (int) timeout.getSeconds());
585 }
586
587 /**
588 * Get wifi data activity timeout from {@link Settings}.
589 *
590 * @param context The {@link Context} to query the setting.
591 * @param def The default timeout if no setting value.
592 * @return The {@link Duration} of timeout to track wifi data activity.
593 */
594 @NonNull
595 public static Duration getWifiDataActivityTimeout(@NonNull Context context,
596 @NonNull Duration def) {
597 final int timeout = Settings.Global.getInt(
598 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
599 return Duration.ofSeconds(timeout);
600 }
601
602 /**
603 * Set wifi data activity timeout to {@link Settings}.
604 * Tracking is disabled if set to zero or negative value.
605 *
606 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
607 * ignored.
608 *
609 * @param context The {@link Context} to set the setting.
610 * @param timeout The wifi data activity timeout.
611 */
612 public static void setWifiDataActivityTimeout(@NonNull Context context,
613 @NonNull Duration timeout) {
614 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
615 (int) timeout.getSeconds());
616 }
617
618 /**
619 * Get dns resolver sample validity duration from {@link Settings}.
620 *
621 * @param context The {@link Context} to query the setting.
622 * @param def The default duration if no setting value.
623 * @return The {@link Duration} of sample validity duration to configure for the system DNS
624 * resolver.
625 */
626 @NonNull
627 public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
628 @NonNull Duration def) {
629 final int duration = Settings.Global.getInt(context.getContentResolver(),
630 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
631 return Duration.ofSeconds(duration);
632 }
633
634 /**
635 * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
636 * positive number of seconds.
637 *
638 * @param context The {@link Context} to set the setting.
639 * @param duration The sample validity duration.
640 */
641 public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
642 @NonNull Duration duration) {
643 final int time = (int) duration.getSeconds();
644 if (time <= 0) {
645 throw new IllegalArgumentException("Invalid duration");
646 }
647 Settings.Global.putInt(
648 context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
649 }
650
651 /**
652 * Get dns resolver success threshold percent from {@link Settings}.
653 *
654 * @param context The {@link Context} to query the setting.
655 * @param def The default value if no setting value.
656 * @return The success threshold in percent for use with the system DNS resolver.
657 */
658 public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
659 return Settings.Global.getInt(
660 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
661 }
662
663 /**
664 * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
665 * be 0~100.
666 *
667 * @param context The {@link Context} to set the setting.
668 * @param percent The success threshold percent.
669 */
670 public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
671 @IntRange(from = 0, to = 100) int percent) {
672 if (percent < 0 || percent > 100) {
673 throw new IllegalArgumentException("Percent must be 0~100");
674 }
675 Settings.Global.putInt(
676 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
677 }
678
679 /**
680 * Get dns resolver samples range from {@link Settings}.
681 *
682 * @param context The {@link Context} to query the setting.
683 * @return The {@link Range<Integer>} of samples needed for statistics to be considered
684 * meaningful in the system DNS resolver.
685 */
686 @NonNull
687 public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
688 final int minSamples = Settings.Global.getInt(context.getContentResolver(),
689 DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
690 final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
691 DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
692 return new Range<>(minSamples, maxSamples);
693 }
694
695 /**
696 * Set dns resolver samples range to {@link Settings}.
697 *
698 * @param context The {@link Context} to set the setting.
699 * @param range The samples range. The minimum number should be more than 0 and the maximum
700 * number should be less that 64.
701 */
702 public static void setDnsResolverSampleRanges(@NonNull Context context,
703 @NonNull Range<Integer> range) {
704 if (range.getLower() < 0 || range.getUpper() > 64) {
705 throw new IllegalArgumentException("Argument must be 0~64");
706 }
707 Settings.Global.putInt(
708 context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
709 Settings.Global.putInt(
710 context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
711 }
712
713 /**
714 * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
715 * hours.
716 *
717 * @param context The {@link Context} to query the setting.
718 * @param def The default value if no setting value.
719 * @return The maximum count of notifications shown in 24 hours when switching networks.
720 */
721 public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
722 int def) {
723 return Settings.Global.getInt(
724 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
725 }
726
727 /**
728 * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
729 * The count must be at least 0.
730 *
731 * @param context The {@link Context} to set the setting.
732 * @param count The maximum count of switching network notifications shown in 24 hours.
733 */
734 public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
735 @IntRange(from = 0) int count) {
736 if (count < 0) {
paulhu236a9922021-03-29 10:50:36 +0800737 throw new IllegalArgumentException("Count must be more than 0.");
paulhu94430952021-03-23 00:24:50 +0800738 }
739 Settings.Global.putInt(
740 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
741 }
742
743 /**
744 * Get minimum duration (from {@link Settings}) between each switching network notifications.
745 *
746 * @param context The {@link Context} to query the setting.
747 * @param def The default time if no setting value.
748 * @return The minimum duration between notifications when switching networks.
749 */
750 @NonNull
751 public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
752 @NonNull Duration def) {
753 final int duration = Settings.Global.getInt(context.getContentResolver(),
754 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
755 return Duration.ofMillis(duration);
756 }
757
758 /**
759 * Set minimum duration (to {@link Settings}) between each switching network notifications.
paulhu236a9922021-03-29 10:50:36 +0800760 * The duration will be rounded down to the next millisecond, and must be positive.
paulhu94430952021-03-23 00:24:50 +0800761 *
762 * @param context The {@link Context} to set the setting.
763 * @param duration The minimum duration between notifications when switching networks.
764 */
765 public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
766 @NonNull Duration duration) {
767 final int time = (int) duration.toMillis();
768 if (time < 0) {
769 throw new IllegalArgumentException("Invalid duration.");
770 }
771 Settings.Global.putInt(context.getContentResolver(),
772 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
773 }
774
775 /**
776 * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
777 *
778 * @param context The {@link Context} to query the setting.
779 * @return The URL used for HTTP captive portal detection upon a new connection.
780 */
781 @Nullable
782 public static String getCaptivePortalHttpUrl(@NonNull Context context) {
783 return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
784 }
785
786 /**
787 * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
paulhu236a9922021-03-29 10:50:36 +0800788 * The URL is accessed to check for connectivity and presence of a captive portal on a network.
789 * The URL should respond with HTTP status 204 to a GET request, and the stack will use
790 * redirection status as a signal for captive portal detection.
791 * If the URL is set to null or is otherwise incorrect or inaccessible, the stack will fail to
792 * detect connectivity and portals. This will often result in loss of connectivity.
paulhu94430952021-03-23 00:24:50 +0800793 *
794 * @param context The {@link Context} to set the setting.
795 * @param url The URL used for HTTP captive portal detection upon a new connection.
796 */
797 public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
798 Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
799 }
800
801 /**
802 * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
803 *
804 * @param context The {@link Context} to query the setting.
805 * @param def The default mode if no setting value.
806 * @return The mode when connecting a network that presents a captive portal.
807 */
808 @CaptivePortalMode
809 public static int getCaptivePortalMode(@NonNull Context context,
810 @CaptivePortalMode int def) {
811 return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
812 }
813
814 /**
815 * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
816 *
817 * @param context The {@link Context} to set the setting.
818 * @param mode The mode when connecting a network that presents a captive portal.
819 */
820 public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
821 if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
822 || mode == CAPTIVE_PORTAL_MODE_PROMPT
823 || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
824 throw new IllegalArgumentException("Invalid captive portal mode");
825 }
826 Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
827 }
828
829 /**
830 * Get the global HTTP proxy applied to the device, or null if none.
831 *
832 * @param context The {@link Context} to query the setting.
833 * @return The {@link ProxyInfo} which build from global http proxy settings.
834 */
835 @Nullable
836 public static ProxyInfo getGlobalProxy(@NonNull Context context) {
837 final String host = Settings.Global.getString(
838 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
839 final int port = Settings.Global.getInt(
840 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
841 final String exclusionList = Settings.Global.getString(
842 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
843 final String pacFileUrl = Settings.Global.getString(
844 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
845
846 if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
847 return null; // No global proxy.
848 }
849
850 if (TextUtils.isEmpty(pacFileUrl)) {
851 return ProxyInfo.buildDirectProxy(
852 host, port, ProxyUtils.exclusionStringAsList(exclusionList));
853 } else {
854 return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
855 }
856 }
857
858 /**
859 * Set global http proxy settings from given {@link ProxyInfo}.
860 *
Chalard Jeanc8ef2192023-04-14 13:18:37 +0900861 * <p class="note">
862 * While a {@link ProxyInfo} for a PAC proxy can be specified, not all devices support
863 * PAC proxies. In particular, smaller devices like watches often do not have the capabilities
864 * necessary to interpret the PAC file. In such cases, calling this API with a PAC proxy
865 * results in undefined behavior, including possibly breaking networking for applications.
866 * You can test for this by checking for the presence of {@link PackageManager.FEATURE_WEBVIEW}.
867 * </p>
868 *
paulhu94430952021-03-23 00:24:50 +0800869 * @param context The {@link Context} to set the setting.
870 * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
871 * {@link ProxyInfo#buildPacProxy(Uri)} or
872 * {@link ProxyInfo#buildDirectProxy(String, int, List)}
Chalard Jeanc8ef2192023-04-14 13:18:37 +0900873 * @throws UnsupportedOperationException if |proxyInfo| codes for a PAC proxy but the system
874 * does not support PAC proxies.
paulhu94430952021-03-23 00:24:50 +0800875 */
876 public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
877 final String host = proxyInfo.getHost();
878 final int port = proxyInfo.getPort();
879 final String exclusionList = proxyInfo.getExclusionListAsString();
880 final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
881
Chalard Jeanc8ef2192023-04-14 13:18:37 +0900882
883 if (!TextUtils.isEmpty(pacFileUrl)) {
884 final PackageManager pm = context.getPackageManager();
885 if (null != pm && !pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
886 Log.wtf(TAG, "PAC proxy can't be installed on a device without FEATURE_WEBVIEW");
887 }
888 }
889
paulhu94430952021-03-23 00:24:50 +0800890 if (TextUtils.isEmpty(pacFileUrl)) {
891 Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
892 Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
893 Settings.Global.putString(
894 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
895 Settings.Global.putString(
896 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
897 } else {
898 Settings.Global.putString(
899 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
900 Settings.Global.putString(
901 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
902 Settings.Global.putInt(
903 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
904 Settings.Global.putString(
905 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
906 }
907 }
908
909 /**
910 * Clear all global http proxy settings.
911 *
912 * @param context The {@link Context} to set the setting.
913 */
914 public static void clearGlobalProxy(@NonNull Context context) {
915 Settings.Global.putString(
916 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
917 Settings.Global.putInt(
918 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
919 Settings.Global.putString(
920 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
921 Settings.Global.putString(
922 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
923 }
924
lucaslin57f9ba82021-04-23 21:03:39 +0800925 /**
926 * Get private DNS mode from settings.
927 *
928 * @param context The Context to query the private DNS mode from settings.
929 * @return A string of private DNS mode.
930 */
931 @PrivateDnsMode
932 public static int getPrivateDnsMode(@NonNull Context context) {
lucaslin89621282021-06-21 16:39:08 +0800933 return ConnectivitySettingsUtils.getPrivateDnsMode(context);
lucaslin57f9ba82021-04-23 21:03:39 +0800934 }
935
936 /**
937 * Set private DNS mode to settings.
938 *
939 * @param context The {@link Context} to set the private DNS mode.
940 * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
941 */
942 public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) {
lucaslin89621282021-06-21 16:39:08 +0800943 ConnectivitySettingsUtils.setPrivateDnsMode(context, mode);
lucaslin57f9ba82021-04-23 21:03:39 +0800944 }
945
paulhu94430952021-03-23 00:24:50 +0800946 /**
947 * Get specific private dns provider name from {@link Settings}.
948 *
949 * @param context The {@link Context} to query the setting.
950 * @return The specific private dns provider name, or null if no setting value.
951 */
952 @Nullable
953 public static String getPrivateDnsHostname(@NonNull Context context) {
lucaslin89621282021-06-21 16:39:08 +0800954 return ConnectivitySettingsUtils.getPrivateDnsHostname(context);
paulhu94430952021-03-23 00:24:50 +0800955 }
956
957 /**
958 * Set specific private dns provider name to {@link Settings}.
959 *
960 * @param context The {@link Context} to set the setting.
961 * @param specifier The specific private dns provider name.
962 */
lucaslin89621282021-06-21 16:39:08 +0800963 public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) {
964 ConnectivitySettingsUtils.setPrivateDnsHostname(context, specifier);
paulhu94430952021-03-23 00:24:50 +0800965 }
966
967 /**
968 * Get default private dns mode from {@link Settings}.
969 *
970 * @param context The {@link Context} to query the setting.
971 * @return The default private dns mode.
972 */
973 @PrivateDnsMode
974 @NonNull
975 public static String getPrivateDnsDefaultMode(@NonNull Context context) {
976 return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
977 }
978
979 /**
980 * Set default private dns mode to {@link Settings}.
981 *
982 * @param context The {@link Context} to set the setting.
983 * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
984 * constants.
985 */
986 public static void setPrivateDnsDefaultMode(@NonNull Context context,
lucaslin57f9ba82021-04-23 21:03:39 +0800987 @NonNull @PrivateDnsMode int mode) {
paulhu94430952021-03-23 00:24:50 +0800988 if (!(mode == PRIVATE_DNS_MODE_OFF
Tad09fdd2b2021-12-21 05:13:40 +0530989 || mode == PRIVATE_DNS_MODE_ADGUARD
990 || mode == PRIVATE_DNS_MODE_APPLIEDPRIVACY
991 || mode == PRIVATE_DNS_MODE_CLEANBROWSING
992 || mode == PRIVATE_DNS_MODE_CIRA
993 || mode == PRIVATE_DNS_MODE_CZNIC
994 || mode == PRIVATE_DNS_MODE_CLOUDFLARE
995 || mode == PRIVATE_DNS_MODE_GOOGLE
996 || mode == PRIVATE_DNS_MODE_MULLVAD
997 || mode == PRIVATE_DNS_MODE_QUADNINE
998 || mode == PRIVATE_DNS_MODE_RESTENA
999 || mode == PRIVATE_DNS_MODE_SWITCH
1000 || mode == PRIVATE_DNS_MODE_TWNIC
1001 || mode == PRIVATE_DNS_MODE_UNCENSOREDDNS
paulhu94430952021-03-23 00:24:50 +08001002 || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
1003 || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
1004 throw new IllegalArgumentException("Invalid private dns mode");
1005 }
lucaslin57f9ba82021-04-23 21:03:39 +08001006 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE,
1007 getPrivateDnsModeAsString(mode));
paulhu94430952021-03-23 00:24:50 +08001008 }
1009
1010 /**
1011 * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
1012 *
1013 * @param context The {@link Context} to query the setting.
1014 * @param def The default duration if no setting value.
1015 * @return The duration to keep a PendingIntent-based request.
1016 */
1017 @NonNull
1018 public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
1019 @NonNull Duration def) {
1020 final int duration = Settings.Secure.getInt(context.getContentResolver(),
1021 CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
1022 return Duration.ofMillis(duration);
1023 }
1024
1025 /**
1026 * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
paulhu236a9922021-03-29 10:50:36 +08001027 * The duration will be rounded down to the next millisecond, and must be positive.
paulhu94430952021-03-23 00:24:50 +08001028 *
1029 * @param context The {@link Context} to set the setting.
1030 * @param duration The duration to keep a PendingIntent-based request.
1031 */
1032 public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
1033 @NonNull Duration duration) {
1034 final int time = (int) duration.toMillis();
1035 if (time < 0) {
1036 throw new IllegalArgumentException("Invalid duration.");
1037 }
1038 Settings.Secure.putInt(
1039 context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
1040 }
1041
1042 /**
1043 * Read from {@link Settings} whether the mobile data connection should remain active
1044 * even when higher priority networks are active.
1045 *
1046 * @param context The {@link Context} to query the setting.
1047 * @param def The default value if no setting value.
1048 * @return Whether the mobile data connection should remain active even when higher
1049 * priority networks are active.
1050 */
1051 public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
1052 final int enable = Settings.Global.getInt(
1053 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
1054 return (enable != 0) ? true : false;
1055 }
1056
1057 /**
1058 * Write into {@link Settings} whether the mobile data connection should remain active
1059 * even when higher priority networks are active.
1060 *
1061 * @param context The {@link Context} to set the setting.
1062 * @param enable Whether the mobile data connection should remain active even when higher
1063 * priority networks are active.
1064 */
1065 public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
1066 Settings.Global.putInt(
1067 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
1068 }
1069
1070 /**
1071 * Read from {@link Settings} whether the wifi data connection should remain active
1072 * even when higher priority networks are active.
1073 *
1074 * @param context The {@link Context} to query the setting.
1075 * @param def The default value if no setting value.
1076 * @return Whether the wifi data connection should remain active even when higher
1077 * priority networks are active.
1078 */
1079 public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
1080 final int enable = Settings.Global.getInt(
1081 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
1082 return (enable != 0) ? true : false;
1083 }
1084
1085 /**
1086 * Write into {@link Settings} whether the wifi data connection should remain active
1087 * even when higher priority networks are active.
1088 *
1089 * @param context The {@link Context} to set the setting.
1090 * @param enable Whether the wifi data connection should remain active even when higher
1091 * priority networks are active
1092 */
1093 public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
1094 Settings.Global.putInt(
1095 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
1096 }
1097
1098 /**
1099 * Get avoid bad wifi setting from {@link Settings}.
1100 *
1101 * @param context The {@link Context} to query the setting.
1102 * @return The setting whether to automatically switch away from wifi networks that lose
1103 * internet access.
1104 */
1105 @NetworkAvoidBadWifi
1106 public static int getNetworkAvoidBadWifi(@NonNull Context context) {
1107 final String setting =
1108 Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
1109 if ("0".equals(setting)) {
1110 return NETWORK_AVOID_BAD_WIFI_IGNORE;
1111 } else if ("1".equals(setting)) {
1112 return NETWORK_AVOID_BAD_WIFI_AVOID;
1113 } else {
1114 return NETWORK_AVOID_BAD_WIFI_PROMPT;
1115 }
1116 }
1117
1118 /**
1119 * Set avoid bad wifi setting to {@link Settings}.
1120 *
1121 * @param context The {@link Context} to set the setting.
1122 * @param value Whether to automatically switch away from wifi networks that lose internet
1123 * access.
1124 */
1125 public static void setNetworkAvoidBadWifi(@NonNull Context context,
1126 @NetworkAvoidBadWifi int value) {
1127 final String setting;
1128 if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
1129 setting = "0";
1130 } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
1131 setting = "1";
1132 } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
1133 setting = null;
1134 } else {
1135 throw new IllegalArgumentException("Invalid avoid bad wifi setting");
1136 }
1137 Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
1138 }
1139
1140 /**
1141 * Get network metered multipath preference from {@link Settings}.
1142 *
1143 * @param context The {@link Context} to query the setting.
1144 * @return The network metered multipath preference which should be one of
1145 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
1146 * by config_networkMeteredMultipathPreference is used.
1147 */
1148 @Nullable
1149 public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
1150 return Settings.Global.getString(
1151 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
1152 }
1153
1154 /**
1155 * Set network metered multipath preference to {@link Settings}.
1156 *
1157 * @param context The {@link Context} to set the setting.
1158 * @param preference The network metered multipath preference which should be one of
1159 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
1160 * specified by config_networkMeteredMultipathPreference is used.
1161 */
1162 public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
1163 @NonNull @MultipathPreference String preference) {
1164 if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
1165 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
1166 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
1167 throw new IllegalArgumentException("Invalid private dns mode");
1168 }
1169 Settings.Global.putString(
1170 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
1171 }
paulhu7a4eeed2021-03-25 13:17:58 +08001172
paulhu91e78062021-05-26 16:16:57 +08001173 private static Set<Integer> getUidSetFromString(@Nullable String uidList) {
1174 final Set<Integer> uids = new ArraySet<>();
1175 if (TextUtils.isEmpty(uidList)) {
1176 return uids;
1177 }
1178 for (String uid : uidList.split(";")) {
1179 uids.add(Integer.valueOf(uid));
1180 }
1181 return uids;
1182 }
1183
1184 private static String getUidStringFromSet(@NonNull Set<Integer> uidList) {
1185 final StringJoiner joiner = new StringJoiner(";");
1186 for (Integer uid : uidList) {
1187 if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) {
1188 throw new IllegalArgumentException("Invalid uid");
1189 }
1190 joiner.add(uid.toString());
1191 }
1192 return joiner.toString();
1193 }
1194
paulhu7a4eeed2021-03-25 13:17:58 +08001195 /**
paulhu344c1162021-05-11 09:42:50 +08001196 * Get the list of uids(from {@link Settings}) that should go on cellular networks in preference
paulhu7a4eeed2021-03-25 13:17:58 +08001197 * even when higher-priority networks are connected.
1198 *
1199 * @param context The {@link Context} to query the setting.
paulhu344c1162021-05-11 09:42:50 +08001200 * @return A list of uids that should go on cellular networks in preference even when
paulhu7a4eeed2021-03-25 13:17:58 +08001201 * higher-priority networks are connected or null if no setting value.
1202 */
paulhu344c1162021-05-11 09:42:50 +08001203 @NonNull
1204 public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) {
1205 final String uidList = Settings.Secure.getString(
1206 context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS);
paulhu91e78062021-05-26 16:16:57 +08001207 return getUidSetFromString(uidList);
paulhu7a4eeed2021-03-25 13:17:58 +08001208 }
1209
1210 /**
paulhu344c1162021-05-11 09:42:50 +08001211 * Set the list of uids(to {@link Settings}) that should go on cellular networks in preference
paulhu7a4eeed2021-03-25 13:17:58 +08001212 * even when higher-priority networks are connected.
1213 *
1214 * @param context The {@link Context} to set the setting.
paulhu344c1162021-05-11 09:42:50 +08001215 * @param uidList A list of uids that should go on cellular networks in preference even when
paulhu7a4eeed2021-03-25 13:17:58 +08001216 * higher-priority networks are connected.
1217 */
paulhu344c1162021-05-11 09:42:50 +08001218 public static void setMobileDataPreferredUids(@NonNull Context context,
1219 @NonNull Set<Integer> uidList) {
paulhu91e78062021-05-26 16:16:57 +08001220 final String uids = getUidStringFromSet(uidList);
1221 Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, uids);
paulhu7a4eeed2021-03-25 13:17:58 +08001222 }
paulhu69afcd52021-04-27 00:14:47 +08001223
1224 /**
paulhu91e78062021-05-26 16:16:57 +08001225 * Get the list of uids (from {@link Settings}) allowed to use restricted networks.
1226 *
1227 * Access to restricted networks is controlled by the (preinstalled-only)
1228 * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission, but highly privileged
1229 * callers can also set a list of uids that can access restricted networks.
1230 *
1231 * This is useful for example in some jurisdictions where government apps,
1232 * that can't be preinstalled, must still have access to emergency services.
paulhu69afcd52021-04-27 00:14:47 +08001233 *
1234 * @param context The {@link Context} to query the setting.
paulhu91e78062021-05-26 16:16:57 +08001235 * @return A list of uids that is allowed to use restricted networks or null if no setting
paulhu257a5cf2021-05-14 15:27:36 +08001236 * value.
paulhu69afcd52021-04-27 00:14:47 +08001237 */
1238 @NonNull
paulhu91e78062021-05-26 16:16:57 +08001239 public static Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) {
paulhu44280442021-05-31 10:42:13 +08001240 final String uidList = Settings.Global.getString(
paulhu91e78062021-05-26 16:16:57 +08001241 context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS);
1242 return getUidSetFromString(uidList);
paulhu69afcd52021-04-27 00:14:47 +08001243 }
1244
paulhu92f128c2021-07-01 18:04:45 +08001245 private static boolean isCallingFromSystem() {
1246 final int uid = Binder.getCallingUid();
1247 final int pid = Binder.getCallingPid();
1248 if (uid == Process.SYSTEM_UID && pid == Process.myPid()) {
1249 return true;
1250 }
1251 return false;
1252 }
1253
paulhu69afcd52021-04-27 00:14:47 +08001254 /**
paulhu91e78062021-05-26 16:16:57 +08001255 * Set the list of uids(from {@link Settings}) that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +08001256 *
1257 * @param context The {@link Context} to set the setting.
paulhu91e78062021-05-26 16:16:57 +08001258 * @param uidList A list of uids that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +08001259 */
paulhu91e78062021-05-26 16:16:57 +08001260 public static void setUidsAllowedOnRestrictedNetworks(@NonNull Context context,
1261 @NonNull Set<Integer> uidList) {
paulhu92f128c2021-07-01 18:04:45 +08001262 final boolean calledFromSystem = isCallingFromSystem();
1263 if (!calledFromSystem) {
1264 // Enforce NETWORK_SETTINGS check if it's debug build. This is for MTS test only.
1265 if (!Build.isDebuggable()) {
1266 throw new SecurityException("Only system can set this setting.");
1267 }
1268 context.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
1269 "Requires NETWORK_SETTINGS permission");
1270 }
paulhu91e78062021-05-26 16:16:57 +08001271 final String uids = getUidStringFromSet(uidList);
paulhu44280442021-05-31 10:42:13 +08001272 Settings.Global.putString(context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS,
paulhu91e78062021-05-26 16:16:57 +08001273 uids);
paulhu69afcd52021-04-27 00:14:47 +08001274 }
Patrick Rohra2084362022-01-03 15:55:52 +01001275
1276 /**
Patrick Rohrca7e5782022-02-18 10:34:20 +01001277 * Get the network bandwidth ingress rate limit.
Patrick Rohra2084362022-01-03 15:55:52 +01001278 *
Patrick Rohrca7e5782022-02-18 10:34:20 +01001279 * The limit is only applicable to networks that provide internet connectivity. -1 codes for no
1280 * bandwidth limitation.
Patrick Rohra2084362022-01-03 15:55:52 +01001281 *
1282 * @param context The {@link Context} to query the setting.
1283 * @return The rate limit in number of bytes per second or -1 if disabled.
1284 */
1285 public static long getIngressRateLimitInBytesPerSecond(@NonNull Context context) {
1286 return Settings.Global.getLong(context.getContentResolver(),
1287 INGRESS_RATE_LIMIT_BYTES_PER_SECOND, -1);
1288 }
1289
1290 /**
Patrick Rohrca7e5782022-02-18 10:34:20 +01001291 * Set the network bandwidth ingress rate limit.
Patrick Rohra2084362022-01-03 15:55:52 +01001292 *
Patrick Rohrca7e5782022-02-18 10:34:20 +01001293 * The limit is applied to all networks that provide internet connectivity. It is applied on a
1294 * per-network basis, meaning that global ingress rate could exceed the limit when communicating
1295 * on multiple networks simultaneously.
Patrick Rohra2084362022-01-03 15:55:52 +01001296 *
1297 * @param context The {@link Context} to set the setting.
1298 * @param rateLimitInBytesPerSec The rate limit in number of bytes per second or -1 to disable.
1299 */
1300 public static void setIngressRateLimitInBytesPerSecond(@NonNull Context context,
Patrick Rohrca7e5782022-02-18 10:34:20 +01001301 @IntRange(from = -1L, to = 0xFFFFFFFFL) long rateLimitInBytesPerSec) {
Patrick Rohra2084362022-01-03 15:55:52 +01001302 if (rateLimitInBytesPerSec < -1) {
1303 throw new IllegalArgumentException(
1304 "Rate limit must be within the range [-1, Integer.MAX_VALUE]");
1305 }
1306 Settings.Global.putLong(context.getContentResolver(),
1307 INGRESS_RATE_LIMIT_BYTES_PER_SECOND,
1308 rateLimitInBytesPerSec);
1309 }
paulhu845456e2021-03-17 17:19:09 +08001310}