blob: 03c3600414c2720c295fa1bd15eade3ab51caf23 [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
paulhuc9925e02021-03-17 20:30:33 +080023import android.annotation.IntDef;
paulhu94430952021-03-23 00:24:50 +080024import android.annotation.IntRange;
25import android.annotation.NonNull;
26import android.annotation.Nullable;
27import android.annotation.SystemApi;
lucaslin57f9ba82021-04-23 21:03:39 +080028import android.content.ContentResolver;
paulhu94430952021-03-23 00:24:50 +080029import android.content.Context;
30import android.net.ConnectivityManager.MultipathPreference;
paulhu344c1162021-05-11 09:42:50 +080031import android.os.Process;
32import android.os.UserHandle;
paulhu94430952021-03-23 00:24:50 +080033import android.provider.Settings;
34import android.text.TextUtils;
paulhu69afcd52021-04-27 00:14:47 +080035import android.util.ArraySet;
paulhu94430952021-03-23 00:24:50 +080036import 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;
paulhu69afcd52021-04-27 00:14:47 +080044import java.util.Set;
45import java.util.StringJoiner;
paulhuc9925e02021-03-17 20:30:33 +080046
paulhu845456e2021-03-17 17:19:09 +080047/**
48 * A manager class for connectivity module settings.
49 *
50 * @hide
51 */
paulhu94430952021-03-23 00:24:50 +080052@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
paulhu845456e2021-03-17 17:19:09 +080053public class ConnectivitySettingsManager {
54
55 private ConnectivitySettingsManager() {}
56
paulhuc9925e02021-03-17 20:30:33 +080057 /** Data activity timeout settings */
58
59 /**
60 * Inactivity timeout to track mobile data activity.
61 *
62 * If set to a positive integer, it indicates the inactivity timeout value in seconds to
63 * infer the data activity of mobile network. After a period of no activity on mobile
64 * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
65 * intent is fired to indicate a transition of network status from "active" to "idle". Any
66 * subsequent activity on mobile networks triggers the firing of {@code
67 * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
68 *
69 * Network activity refers to transmitting or receiving data on the network interfaces.
70 *
71 * Tracking is disabled if set to zero or negative value.
paulhu94430952021-03-23 00:24:50 +080072 *
73 * @hide
paulhuc9925e02021-03-17 20:30:33 +080074 */
75 public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
76
77 /**
78 * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
79 * but for Wifi network.
paulhu94430952021-03-23 00:24:50 +080080 *
81 * @hide
paulhuc9925e02021-03-17 20:30:33 +080082 */
83 public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
84
85 /** Dns resolver settings */
86
87 /**
88 * Sample validity in seconds to configure for the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +080089 *
90 * @hide
paulhuc9925e02021-03-17 20:30:33 +080091 */
92 public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
93 "dns_resolver_sample_validity_seconds";
94
95 /**
96 * Success threshold in percent for use with the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +080097 *
98 * @hide
paulhuc9925e02021-03-17 20:30:33 +080099 */
100 public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
101 "dns_resolver_success_threshold_percent";
102
103 /**
104 * Minimum number of samples needed for statistics to be considered meaningful in the
105 * system DNS resolver.
paulhu94430952021-03-23 00:24:50 +0800106 *
107 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800108 */
109 public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
110
111 /**
112 * Maximum number taken into account for statistics purposes in the 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_MAX_SAMPLES = "dns_resolver_max_samples";
117
paulhu94430952021-03-23 00:24:50 +0800118 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
119 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
120
paulhuc9925e02021-03-17 20:30:33 +0800121 /** Network switch notification settings */
122
123 /**
124 * The maximum number of notifications shown in 24 hours when switching networks.
paulhu94430952021-03-23 00:24:50 +0800125 *
126 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800127 */
128 public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
129 "network_switch_notification_daily_limit";
130
131 /**
132 * The minimum time in milliseconds between notifications when switching networks.
paulhu94430952021-03-23 00:24:50 +0800133 *
134 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800135 */
136 public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
137 "network_switch_notification_rate_limit_millis";
138
139 /** Captive portal settings */
140
141 /**
142 * The URL used for HTTP captive portal detection upon a new connection.
143 * A 204 response code from the server is used for validation.
paulhu94430952021-03-23 00:24:50 +0800144 *
145 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800146 */
147 public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
148
149 /**
150 * What to do when connecting a network that presents a captive portal.
paulhu94430952021-03-23 00:24:50 +0800151 * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
paulhuc9925e02021-03-17 20:30:33 +0800152 *
153 * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
paulhu94430952021-03-23 00:24:50 +0800154 *
155 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800156 */
157 public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
158
159 /**
160 * Don't attempt to detect captive portals.
161 */
162 public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
163
164 /**
165 * When detecting a captive portal, display a notification that
166 * prompts the user to sign in.
167 */
168 public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
169
170 /**
171 * When detecting a captive portal, immediately disconnect from the
172 * network and do not reconnect to that network in the future.
173 */
174 public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
175
176 /** @hide */
177 @Retention(RetentionPolicy.SOURCE)
178 @IntDef(value = {
179 CAPTIVE_PORTAL_MODE_IGNORE,
180 CAPTIVE_PORTAL_MODE_PROMPT,
181 CAPTIVE_PORTAL_MODE_AVOID,
182 })
183 public @interface CaptivePortalMode {}
184
185 /** Global http proxy settings */
186
187 /**
188 * Host name for global http proxy. Set via ConnectivityManager.
paulhu94430952021-03-23 00:24:50 +0800189 *
190 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800191 */
192 public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
193
194 /**
195 * Integer host port for global http proxy. Set via ConnectivityManager.
paulhu94430952021-03-23 00:24:50 +0800196 *
197 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800198 */
199 public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
200
201 /**
202 * Exclusion list for global proxy. This string contains a list of
203 * comma-separated domains where the global proxy does not apply.
204 * Domains should be listed in a comma- separated list. Example of
205 * acceptable formats: ".domain1.com,my.domain2.com" Use
206 * ConnectivityManager to set/get.
paulhu94430952021-03-23 00:24:50 +0800207 *
208 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800209 */
210 public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
211 "global_http_proxy_exclusion_list";
212
213 /**
214 * The location PAC File for the proxy.
paulhu94430952021-03-23 00:24:50 +0800215 *
216 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800217 */
218 public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
219
220 /** Private dns settings */
221
222 /**
223 * The requested Private DNS mode (string), and an accompanying specifier (string).
224 *
225 * Currently, the specifier holds the chosen provider name when the mode requests
226 * a specific provider. It may be used to store the provider name even when the
227 * mode changes so that temporarily disabling and re-enabling the specific
228 * provider mode does not necessitate retyping the provider hostname.
paulhu94430952021-03-23 00:24:50 +0800229 *
230 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800231 */
232 public static final String PRIVATE_DNS_MODE = "private_dns_mode";
233
234 /**
235 * The specific Private DNS provider name.
paulhu94430952021-03-23 00:24:50 +0800236 *
237 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800238 */
239 public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
240
241 /**
242 * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
243 * This allows changing the default mode without effectively disabling other modes,
244 * all of which require explicit user action to enable/configure. See also b/79719289.
245 *
246 * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
paulhu94430952021-03-23 00:24:50 +0800247 *
248 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800249 */
250 public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
251
252 /** Other settings */
253
254 /**
255 * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
256 * the receivers of the PendingIntent an opportunity to make a new network request before
257 * the Network satisfying the request is potentially removed.
paulhu94430952021-03-23 00:24:50 +0800258 *
259 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800260 */
261 public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
262 "connectivity_release_pending_intent_delay_ms";
263
264 /**
265 * Whether the mobile data connection should remain active even when higher
266 * priority networks like WiFi are active, to help make network switching faster.
267 *
268 * See ConnectivityService for more info.
269 *
270 * (0 = disabled, 1 = enabled)
paulhu94430952021-03-23 00:24:50 +0800271 *
272 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800273 */
274 public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
275
276 /**
277 * Whether the wifi data connection should remain active even when higher
278 * priority networks like Ethernet are active, to keep both networks.
279 * In the case where higher priority networks are connected, wifi will be
280 * unused unless an application explicitly requests to use it.
281 *
282 * See ConnectivityService for more info.
283 *
284 * (0 = disabled, 1 = enabled)
paulhu94430952021-03-23 00:24:50 +0800285 *
286 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800287 */
288 public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
289
paulhu845456e2021-03-17 17:19:09 +0800290 /**
291 * Whether to automatically switch away from wifi networks that lose Internet access.
292 * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
293 * avoids such networks. Valid values are:
294 *
295 * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
296 * null: Ask the user whether to switch away from bad wifi.
297 * 1: Avoid bad wifi.
paulhu94430952021-03-23 00:24:50 +0800298 *
299 * @hide
paulhu845456e2021-03-17 17:19:09 +0800300 */
301 public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
302
303 /**
paulhu94430952021-03-23 00:24:50 +0800304 * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
305 */
306 public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
307
308 /**
309 * Ask the user whether to switch away from bad wifi.
310 */
311 public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
312
313 /**
314 * Avoid bad wifi.
315 */
316 public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
317
318 /** @hide */
319 @Retention(RetentionPolicy.SOURCE)
320 @IntDef(value = {
321 NETWORK_AVOID_BAD_WIFI_IGNORE,
322 NETWORK_AVOID_BAD_WIFI_PROMPT,
323 NETWORK_AVOID_BAD_WIFI_AVOID,
324 })
325 public @interface NetworkAvoidBadWifi {}
326
327 /**
paulhu845456e2021-03-17 17:19:09 +0800328 * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
329 * overridden by the system based on device or application state. If null, the value
330 * specified by config_networkMeteredMultipathPreference is used.
paulhu94430952021-03-23 00:24:50 +0800331 *
332 * @hide
paulhu845456e2021-03-17 17:19:09 +0800333 */
334 public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
335 "network_metered_multipath_preference";
paulhu94430952021-03-23 00:24:50 +0800336
337 /**
paulhu344c1162021-05-11 09:42:50 +0800338 * A list of uids that should go on cellular networks in preference even when higher-priority
paulhu7a4eeed2021-03-25 13:17:58 +0800339 * networks are connected.
340 *
341 * @hide
342 */
paulhu344c1162021-05-11 09:42:50 +0800343 public static final String MOBILE_DATA_PREFERRED_UIDS = "mobile_data_preferred_uids";
paulhu7a4eeed2021-03-25 13:17:58 +0800344
345 /**
lucaslin57f9ba82021-04-23 21:03:39 +0800346 * One of the private DNS modes that indicates the private DNS mode is off.
347 */
348 public static final int PRIVATE_DNS_MODE_OFF = 1;
349
350 /**
351 * One of the private DNS modes that indicates the private DNS mode is automatic, which
352 * will try to use the current DNS as private DNS.
353 */
354 public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2;
355
356 /**
357 * One of the private DNS modes that indicates the private DNS mode is strict and the
358 * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of
359 * {@link #PRIVATE_DNS_SPECIFIER} as private DNS.
360 */
361 public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3;
362
363 /** @hide */
364 @Retention(RetentionPolicy.SOURCE)
365 @IntDef(value = {
366 PRIVATE_DNS_MODE_OFF,
367 PRIVATE_DNS_MODE_OPPORTUNISTIC,
368 PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
369 })
370 public @interface PrivateDnsMode {}
371
372 private static final String PRIVATE_DNS_MODE_OFF_STRING = "off";
373 private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic";
374 private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname";
375
376 /**
paulhu91e78062021-05-26 16:16:57 +0800377 * A list of uids that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +0800378 *
379 * @hide
380 */
paulhu91e78062021-05-26 16:16:57 +0800381 public static final String UIDS_ALLOWED_ON_RESTRICTED_NETWORKS =
382 "uids_allowed_on_restricted_networks";
paulhu69afcd52021-04-27 00:14:47 +0800383
384 /**
paulhu94430952021-03-23 00:24:50 +0800385 * Get mobile data activity timeout from {@link Settings}.
386 *
387 * @param context The {@link Context} to query the setting.
388 * @param def The default timeout if no setting value.
389 * @return The {@link Duration} of timeout to track mobile data activity.
390 */
391 @NonNull
392 public static Duration getMobileDataActivityTimeout(@NonNull Context context,
393 @NonNull Duration def) {
394 final int timeout = Settings.Global.getInt(
395 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
396 return Duration.ofSeconds(timeout);
397 }
398
399 /**
400 * Set mobile data activity timeout to {@link Settings}.
401 * Tracking is disabled if set to zero or negative value.
402 *
403 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
404 * ignored.
405 *
406 * @param context The {@link Context} to set the setting.
407 * @param timeout The mobile data activity timeout.
408 */
409 public static void setMobileDataActivityTimeout(@NonNull Context context,
410 @NonNull Duration timeout) {
411 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
412 (int) timeout.getSeconds());
413 }
414
415 /**
416 * Get wifi data activity timeout from {@link Settings}.
417 *
418 * @param context The {@link Context} to query the setting.
419 * @param def The default timeout if no setting value.
420 * @return The {@link Duration} of timeout to track wifi data activity.
421 */
422 @NonNull
423 public static Duration getWifiDataActivityTimeout(@NonNull Context context,
424 @NonNull Duration def) {
425 final int timeout = Settings.Global.getInt(
426 context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
427 return Duration.ofSeconds(timeout);
428 }
429
430 /**
431 * Set wifi data activity timeout to {@link Settings}.
432 * Tracking is disabled if set to zero or negative value.
433 *
434 * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
435 * ignored.
436 *
437 * @param context The {@link Context} to set the setting.
438 * @param timeout The wifi data activity timeout.
439 */
440 public static void setWifiDataActivityTimeout(@NonNull Context context,
441 @NonNull Duration timeout) {
442 Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
443 (int) timeout.getSeconds());
444 }
445
446 /**
447 * Get dns resolver sample validity duration from {@link Settings}.
448 *
449 * @param context The {@link Context} to query the setting.
450 * @param def The default duration if no setting value.
451 * @return The {@link Duration} of sample validity duration to configure for the system DNS
452 * resolver.
453 */
454 @NonNull
455 public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
456 @NonNull Duration def) {
457 final int duration = Settings.Global.getInt(context.getContentResolver(),
458 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
459 return Duration.ofSeconds(duration);
460 }
461
462 /**
463 * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
464 * positive number of seconds.
465 *
466 * @param context The {@link Context} to set the setting.
467 * @param duration The sample validity duration.
468 */
469 public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
470 @NonNull Duration duration) {
471 final int time = (int) duration.getSeconds();
472 if (time <= 0) {
473 throw new IllegalArgumentException("Invalid duration");
474 }
475 Settings.Global.putInt(
476 context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
477 }
478
479 /**
480 * Get dns resolver success threshold percent from {@link Settings}.
481 *
482 * @param context The {@link Context} to query the setting.
483 * @param def The default value if no setting value.
484 * @return The success threshold in percent for use with the system DNS resolver.
485 */
486 public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
487 return Settings.Global.getInt(
488 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
489 }
490
491 /**
492 * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
493 * be 0~100.
494 *
495 * @param context The {@link Context} to set the setting.
496 * @param percent The success threshold percent.
497 */
498 public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
499 @IntRange(from = 0, to = 100) int percent) {
500 if (percent < 0 || percent > 100) {
501 throw new IllegalArgumentException("Percent must be 0~100");
502 }
503 Settings.Global.putInt(
504 context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
505 }
506
507 /**
508 * Get dns resolver samples range from {@link Settings}.
509 *
510 * @param context The {@link Context} to query the setting.
511 * @return The {@link Range<Integer>} of samples needed for statistics to be considered
512 * meaningful in the system DNS resolver.
513 */
514 @NonNull
515 public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
516 final int minSamples = Settings.Global.getInt(context.getContentResolver(),
517 DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
518 final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
519 DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
520 return new Range<>(minSamples, maxSamples);
521 }
522
523 /**
524 * Set dns resolver samples range to {@link Settings}.
525 *
526 * @param context The {@link Context} to set the setting.
527 * @param range The samples range. The minimum number should be more than 0 and the maximum
528 * number should be less that 64.
529 */
530 public static void setDnsResolverSampleRanges(@NonNull Context context,
531 @NonNull Range<Integer> range) {
532 if (range.getLower() < 0 || range.getUpper() > 64) {
533 throw new IllegalArgumentException("Argument must be 0~64");
534 }
535 Settings.Global.putInt(
536 context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
537 Settings.Global.putInt(
538 context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
539 }
540
541 /**
542 * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
543 * hours.
544 *
545 * @param context The {@link Context} to query the setting.
546 * @param def The default value if no setting value.
547 * @return The maximum count of notifications shown in 24 hours when switching networks.
548 */
549 public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
550 int def) {
551 return Settings.Global.getInt(
552 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
553 }
554
555 /**
556 * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
557 * The count must be at least 0.
558 *
559 * @param context The {@link Context} to set the setting.
560 * @param count The maximum count of switching network notifications shown in 24 hours.
561 */
562 public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
563 @IntRange(from = 0) int count) {
564 if (count < 0) {
565 throw new IllegalArgumentException("Count must be 0~10.");
566 }
567 Settings.Global.putInt(
568 context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
569 }
570
571 /**
572 * Get minimum duration (from {@link Settings}) between each switching network notifications.
573 *
574 * @param context The {@link Context} to query the setting.
575 * @param def The default time if no setting value.
576 * @return The minimum duration between notifications when switching networks.
577 */
578 @NonNull
579 public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
580 @NonNull Duration def) {
581 final int duration = Settings.Global.getInt(context.getContentResolver(),
582 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
583 return Duration.ofMillis(duration);
584 }
585
586 /**
587 * Set minimum duration (to {@link Settings}) between each switching network notifications.
588 *
589 * @param context The {@link Context} to set the setting.
590 * @param duration The minimum duration between notifications when switching networks.
591 */
592 public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
593 @NonNull Duration duration) {
594 final int time = (int) duration.toMillis();
595 if (time < 0) {
596 throw new IllegalArgumentException("Invalid duration.");
597 }
598 Settings.Global.putInt(context.getContentResolver(),
599 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
600 }
601
602 /**
603 * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
604 *
605 * @param context The {@link Context} to query the setting.
606 * @return The URL used for HTTP captive portal detection upon a new connection.
607 */
608 @Nullable
609 public static String getCaptivePortalHttpUrl(@NonNull Context context) {
610 return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
611 }
612
613 /**
614 * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
615 * This URL should respond with a 204 response to a GET request to indicate no captive portal is
616 * present. And this URL must be HTTP as redirect responses are used to find captive portal
617 * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal
618 * detection failed and lost the connection.
619 *
620 * @param context The {@link Context} to set the setting.
621 * @param url The URL used for HTTP captive portal detection upon a new connection.
622 */
623 public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
624 Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
625 }
626
627 /**
628 * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
629 *
630 * @param context The {@link Context} to query the setting.
631 * @param def The default mode if no setting value.
632 * @return The mode when connecting a network that presents a captive portal.
633 */
634 @CaptivePortalMode
635 public static int getCaptivePortalMode(@NonNull Context context,
636 @CaptivePortalMode int def) {
637 return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
638 }
639
640 /**
641 * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
642 *
643 * @param context The {@link Context} to set the setting.
644 * @param mode The mode when connecting a network that presents a captive portal.
645 */
646 public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
647 if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
648 || mode == CAPTIVE_PORTAL_MODE_PROMPT
649 || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
650 throw new IllegalArgumentException("Invalid captive portal mode");
651 }
652 Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
653 }
654
655 /**
656 * Get the global HTTP proxy applied to the device, or null if none.
657 *
658 * @param context The {@link Context} to query the setting.
659 * @return The {@link ProxyInfo} which build from global http proxy settings.
660 */
661 @Nullable
662 public static ProxyInfo getGlobalProxy(@NonNull Context context) {
663 final String host = Settings.Global.getString(
664 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
665 final int port = Settings.Global.getInt(
666 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
667 final String exclusionList = Settings.Global.getString(
668 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
669 final String pacFileUrl = Settings.Global.getString(
670 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
671
672 if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
673 return null; // No global proxy.
674 }
675
676 if (TextUtils.isEmpty(pacFileUrl)) {
677 return ProxyInfo.buildDirectProxy(
678 host, port, ProxyUtils.exclusionStringAsList(exclusionList));
679 } else {
680 return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
681 }
682 }
683
684 /**
685 * Set global http proxy settings from given {@link ProxyInfo}.
686 *
687 * @param context The {@link Context} to set the setting.
688 * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
689 * {@link ProxyInfo#buildPacProxy(Uri)} or
690 * {@link ProxyInfo#buildDirectProxy(String, int, List)}
691 */
692 public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
693 final String host = proxyInfo.getHost();
694 final int port = proxyInfo.getPort();
695 final String exclusionList = proxyInfo.getExclusionListAsString();
696 final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
697
698 if (TextUtils.isEmpty(pacFileUrl)) {
699 Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
700 Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
701 Settings.Global.putString(
702 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
703 Settings.Global.putString(
704 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
705 } else {
706 Settings.Global.putString(
707 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
708 Settings.Global.putString(
709 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
710 Settings.Global.putInt(
711 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
712 Settings.Global.putString(
713 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
714 }
715 }
716
717 /**
718 * Clear all global http proxy settings.
719 *
720 * @param context The {@link Context} to set the setting.
721 */
722 public static void clearGlobalProxy(@NonNull Context context) {
723 Settings.Global.putString(
724 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
725 Settings.Global.putInt(
726 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
727 Settings.Global.putString(
728 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
729 Settings.Global.putString(
730 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
731 }
732
lucaslin57f9ba82021-04-23 21:03:39 +0800733 private static String getPrivateDnsModeAsString(@PrivateDnsMode int mode) {
734 switch (mode) {
735 case PRIVATE_DNS_MODE_OFF:
736 return PRIVATE_DNS_MODE_OFF_STRING;
737 case PRIVATE_DNS_MODE_OPPORTUNISTIC:
738 return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING;
739 case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
740 return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING;
741 default:
742 throw new IllegalArgumentException("Invalid private dns mode: " + mode);
743 }
744 }
745
746 private static int getPrivateDnsModeAsInt(String mode) {
747 switch (mode) {
748 case "off":
749 return PRIVATE_DNS_MODE_OFF;
750 case "hostname":
751 return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
752 case "opportunistic":
753 return PRIVATE_DNS_MODE_OPPORTUNISTIC;
754 default:
755 throw new IllegalArgumentException("Invalid private dns mode: " + mode);
756 }
757 }
758
759 /**
760 * Get private DNS mode from settings.
761 *
762 * @param context The Context to query the private DNS mode from settings.
763 * @return A string of private DNS mode.
764 */
765 @PrivateDnsMode
766 public static int getPrivateDnsMode(@NonNull Context context) {
767 final ContentResolver cr = context.getContentResolver();
768 String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE);
769 if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE);
770 // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose
771 // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode.
772 if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC;
773 return getPrivateDnsModeAsInt(mode);
774 }
775
776 /**
777 * Set private DNS mode to settings.
778 *
779 * @param context The {@link Context} to set the private DNS mode.
780 * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
781 */
782 public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) {
783 if (!(mode == PRIVATE_DNS_MODE_OFF
784 || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
785 || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
786 throw new IllegalArgumentException("Invalid private dns mode: " + mode);
787 }
788 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE,
789 getPrivateDnsModeAsString(mode));
790 }
791
paulhu94430952021-03-23 00:24:50 +0800792 /**
793 * Get specific private dns provider name from {@link Settings}.
794 *
795 * @param context The {@link Context} to query the setting.
796 * @return The specific private dns provider name, or null if no setting value.
797 */
798 @Nullable
799 public static String getPrivateDnsHostname(@NonNull Context context) {
800 return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER);
801 }
802
803 /**
804 * Set specific private dns provider name to {@link Settings}.
805 *
806 * @param context The {@link Context} to set the setting.
807 * @param specifier The specific private dns provider name.
808 */
809 public static void setPrivateDnsHostname(@NonNull Context context,
810 @Nullable String specifier) {
811 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier);
812 }
813
814 /**
815 * Get default private dns mode from {@link Settings}.
816 *
817 * @param context The {@link Context} to query the setting.
818 * @return The default private dns mode.
819 */
820 @PrivateDnsMode
821 @NonNull
822 public static String getPrivateDnsDefaultMode(@NonNull Context context) {
823 return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
824 }
825
826 /**
827 * Set default private dns mode to {@link Settings}.
828 *
829 * @param context The {@link Context} to set the setting.
830 * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
831 * constants.
832 */
833 public static void setPrivateDnsDefaultMode(@NonNull Context context,
lucaslin57f9ba82021-04-23 21:03:39 +0800834 @NonNull @PrivateDnsMode int mode) {
paulhu94430952021-03-23 00:24:50 +0800835 if (!(mode == PRIVATE_DNS_MODE_OFF
836 || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
837 || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
838 throw new IllegalArgumentException("Invalid private dns mode");
839 }
lucaslin57f9ba82021-04-23 21:03:39 +0800840 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE,
841 getPrivateDnsModeAsString(mode));
paulhu94430952021-03-23 00:24:50 +0800842 }
843
844 /**
845 * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
846 *
847 * @param context The {@link Context} to query the setting.
848 * @param def The default duration if no setting value.
849 * @return The duration to keep a PendingIntent-based request.
850 */
851 @NonNull
852 public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
853 @NonNull Duration def) {
854 final int duration = Settings.Secure.getInt(context.getContentResolver(),
855 CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
856 return Duration.ofMillis(duration);
857 }
858
859 /**
860 * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
861 *
862 * @param context The {@link Context} to set the setting.
863 * @param duration The duration to keep a PendingIntent-based request.
864 */
865 public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
866 @NonNull Duration duration) {
867 final int time = (int) duration.toMillis();
868 if (time < 0) {
869 throw new IllegalArgumentException("Invalid duration.");
870 }
871 Settings.Secure.putInt(
872 context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
873 }
874
875 /**
876 * Read from {@link Settings} whether the mobile data connection should remain active
877 * even when higher priority networks are active.
878 *
879 * @param context The {@link Context} to query the setting.
880 * @param def The default value if no setting value.
881 * @return Whether the mobile data connection should remain active even when higher
882 * priority networks are active.
883 */
884 public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
885 final int enable = Settings.Global.getInt(
886 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
887 return (enable != 0) ? true : false;
888 }
889
890 /**
891 * Write into {@link Settings} whether the mobile data connection should remain active
892 * even when higher priority networks are active.
893 *
894 * @param context The {@link Context} to set the setting.
895 * @param enable Whether the mobile data connection should remain active even when higher
896 * priority networks are active.
897 */
898 public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
899 Settings.Global.putInt(
900 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
901 }
902
903 /**
904 * Read from {@link Settings} whether the wifi data connection should remain active
905 * even when higher priority networks are active.
906 *
907 * @param context The {@link Context} to query the setting.
908 * @param def The default value if no setting value.
909 * @return Whether the wifi data connection should remain active even when higher
910 * priority networks are active.
911 */
912 public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
913 final int enable = Settings.Global.getInt(
914 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
915 return (enable != 0) ? true : false;
916 }
917
918 /**
919 * Write into {@link Settings} whether the wifi data connection should remain active
920 * even when higher priority networks are active.
921 *
922 * @param context The {@link Context} to set the setting.
923 * @param enable Whether the wifi data connection should remain active even when higher
924 * priority networks are active
925 */
926 public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
927 Settings.Global.putInt(
928 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
929 }
930
931 /**
932 * Get avoid bad wifi setting from {@link Settings}.
933 *
934 * @param context The {@link Context} to query the setting.
935 * @return The setting whether to automatically switch away from wifi networks that lose
936 * internet access.
937 */
938 @NetworkAvoidBadWifi
939 public static int getNetworkAvoidBadWifi(@NonNull Context context) {
940 final String setting =
941 Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
942 if ("0".equals(setting)) {
943 return NETWORK_AVOID_BAD_WIFI_IGNORE;
944 } else if ("1".equals(setting)) {
945 return NETWORK_AVOID_BAD_WIFI_AVOID;
946 } else {
947 return NETWORK_AVOID_BAD_WIFI_PROMPT;
948 }
949 }
950
951 /**
952 * Set avoid bad wifi setting to {@link Settings}.
953 *
954 * @param context The {@link Context} to set the setting.
955 * @param value Whether to automatically switch away from wifi networks that lose internet
956 * access.
957 */
958 public static void setNetworkAvoidBadWifi(@NonNull Context context,
959 @NetworkAvoidBadWifi int value) {
960 final String setting;
961 if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
962 setting = "0";
963 } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
964 setting = "1";
965 } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
966 setting = null;
967 } else {
968 throw new IllegalArgumentException("Invalid avoid bad wifi setting");
969 }
970 Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
971 }
972
973 /**
974 * Get network metered multipath preference from {@link Settings}.
975 *
976 * @param context The {@link Context} to query the setting.
977 * @return The network metered multipath preference which should be one of
978 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
979 * by config_networkMeteredMultipathPreference is used.
980 */
981 @Nullable
982 public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
983 return Settings.Global.getString(
984 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
985 }
986
987 /**
988 * Set network metered multipath preference to {@link Settings}.
989 *
990 * @param context The {@link Context} to set the setting.
991 * @param preference The network metered multipath preference which should be one of
992 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
993 * specified by config_networkMeteredMultipathPreference is used.
994 */
995 public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
996 @NonNull @MultipathPreference String preference) {
997 if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
998 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
999 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
1000 throw new IllegalArgumentException("Invalid private dns mode");
1001 }
1002 Settings.Global.putString(
1003 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
1004 }
paulhu7a4eeed2021-03-25 13:17:58 +08001005
paulhu91e78062021-05-26 16:16:57 +08001006 private static Set<Integer> getUidSetFromString(@Nullable String uidList) {
1007 final Set<Integer> uids = new ArraySet<>();
1008 if (TextUtils.isEmpty(uidList)) {
1009 return uids;
1010 }
1011 for (String uid : uidList.split(";")) {
1012 uids.add(Integer.valueOf(uid));
1013 }
1014 return uids;
1015 }
1016
1017 private static String getUidStringFromSet(@NonNull Set<Integer> uidList) {
1018 final StringJoiner joiner = new StringJoiner(";");
1019 for (Integer uid : uidList) {
1020 if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) {
1021 throw new IllegalArgumentException("Invalid uid");
1022 }
1023 joiner.add(uid.toString());
1024 }
1025 return joiner.toString();
1026 }
1027
paulhu7a4eeed2021-03-25 13:17:58 +08001028 /**
paulhu344c1162021-05-11 09:42:50 +08001029 * Get the list of uids(from {@link Settings}) that should go on cellular networks in preference
paulhu7a4eeed2021-03-25 13:17:58 +08001030 * even when higher-priority networks are connected.
1031 *
1032 * @param context The {@link Context} to query the setting.
paulhu344c1162021-05-11 09:42:50 +08001033 * @return A list of uids that should go on cellular networks in preference even when
paulhu7a4eeed2021-03-25 13:17:58 +08001034 * higher-priority networks are connected or null if no setting value.
1035 */
paulhu344c1162021-05-11 09:42:50 +08001036 @NonNull
1037 public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) {
1038 final String uidList = Settings.Secure.getString(
1039 context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS);
paulhu91e78062021-05-26 16:16:57 +08001040 return getUidSetFromString(uidList);
paulhu7a4eeed2021-03-25 13:17:58 +08001041 }
1042
1043 /**
paulhu344c1162021-05-11 09:42:50 +08001044 * Set the list of uids(to {@link Settings}) that should go on cellular networks in preference
paulhu7a4eeed2021-03-25 13:17:58 +08001045 * even when higher-priority networks are connected.
1046 *
1047 * @param context The {@link Context} to set the setting.
paulhu344c1162021-05-11 09:42:50 +08001048 * @param uidList A list of uids that should go on cellular networks in preference even when
paulhu7a4eeed2021-03-25 13:17:58 +08001049 * higher-priority networks are connected.
1050 */
paulhu344c1162021-05-11 09:42:50 +08001051 public static void setMobileDataPreferredUids(@NonNull Context context,
1052 @NonNull Set<Integer> uidList) {
paulhu91e78062021-05-26 16:16:57 +08001053 final String uids = getUidStringFromSet(uidList);
1054 Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, uids);
paulhu7a4eeed2021-03-25 13:17:58 +08001055 }
paulhu69afcd52021-04-27 00:14:47 +08001056
1057 /**
paulhu91e78062021-05-26 16:16:57 +08001058 * Get the list of uids (from {@link Settings}) allowed to use restricted networks.
1059 *
1060 * Access to restricted networks is controlled by the (preinstalled-only)
1061 * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission, but highly privileged
1062 * callers can also set a list of uids that can access restricted networks.
1063 *
1064 * This is useful for example in some jurisdictions where government apps,
1065 * that can't be preinstalled, must still have access to emergency services.
paulhu69afcd52021-04-27 00:14:47 +08001066 *
1067 * @param context The {@link Context} to query the setting.
paulhu91e78062021-05-26 16:16:57 +08001068 * @return A list of uids that is allowed to use restricted networks or null if no setting
paulhu257a5cf2021-05-14 15:27:36 +08001069 * value.
paulhu69afcd52021-04-27 00:14:47 +08001070 */
1071 @NonNull
paulhu91e78062021-05-26 16:16:57 +08001072 public static Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) {
paulhu44280442021-05-31 10:42:13 +08001073 final String uidList = Settings.Global.getString(
paulhu91e78062021-05-26 16:16:57 +08001074 context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS);
1075 return getUidSetFromString(uidList);
paulhu69afcd52021-04-27 00:14:47 +08001076 }
1077
1078 /**
paulhu91e78062021-05-26 16:16:57 +08001079 * Set the list of uids(from {@link Settings}) that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +08001080 *
1081 * @param context The {@link Context} to set the setting.
paulhu91e78062021-05-26 16:16:57 +08001082 * @param uidList A list of uids that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +08001083 */
paulhu91e78062021-05-26 16:16:57 +08001084 public static void setUidsAllowedOnRestrictedNetworks(@NonNull Context context,
1085 @NonNull Set<Integer> uidList) {
1086 final String uids = getUidStringFromSet(uidList);
paulhu44280442021-05-31 10:42:13 +08001087 Settings.Global.putString(context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS,
paulhu91e78062021-05-26 16:16:57 +08001088 uids);
paulhu69afcd52021-04-27 00:14:47 +08001089 }
paulhu845456e2021-03-17 17:19:09 +08001090}