blob: 085de6b685742f5710b2dcf758b8477ba5fb1697 [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;
31import android.net.ConnectivityManager.MultipathPreference;
paulhu344c1162021-05-11 09:42:50 +080032import android.os.Process;
33import android.os.UserHandle;
paulhu94430952021-03-23 00:24:50 +080034import android.provider.Settings;
35import android.text.TextUtils;
paulhu69afcd52021-04-27 00:14:47 +080036import android.util.ArraySet;
paulhu94430952021-03-23 00:24:50 +080037import android.util.Range;
38
lucaslin89621282021-06-21 16:39:08 +080039import com.android.net.module.util.ConnectivitySettingsUtils;
paulhu94430952021-03-23 00:24:50 +080040import com.android.net.module.util.ProxyUtils;
paulhuc9925e02021-03-17 20:30:33 +080041
42import java.lang.annotation.Retention;
43import java.lang.annotation.RetentionPolicy;
paulhu94430952021-03-23 00:24:50 +080044import java.time.Duration;
45import java.util.List;
paulhu69afcd52021-04-27 00:14:47 +080046import java.util.Set;
47import java.util.StringJoiner;
paulhuc9925e02021-03-17 20:30:33 +080048
paulhu845456e2021-03-17 17:19:09 +080049/**
50 * A manager class for connectivity module settings.
51 *
52 * @hide
53 */
paulhu94430952021-03-23 00:24:50 +080054@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
paulhu845456e2021-03-17 17:19:09 +080055public class ConnectivitySettingsManager {
56
57 private ConnectivitySettingsManager() {}
58
paulhuc9925e02021-03-17 20:30:33 +080059 /** Data activity timeout settings */
60
61 /**
62 * Inactivity timeout to track mobile data activity.
63 *
64 * If set to a positive integer, it indicates the inactivity timeout value in seconds to
65 * infer the data activity of mobile network. After a period of no activity on mobile
66 * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
67 * intent is fired to indicate a transition of network status from "active" to "idle". Any
68 * subsequent activity on mobile networks triggers the firing of {@code
69 * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
70 *
71 * Network activity refers to transmitting or receiving data on the network interfaces.
72 *
73 * Tracking is disabled if set to zero or negative value.
paulhu94430952021-03-23 00:24:50 +080074 *
75 * @hide
paulhuc9925e02021-03-17 20:30:33 +080076 */
77 public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
78
79 /**
80 * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
81 * but for Wifi network.
paulhu94430952021-03-23 00:24:50 +080082 *
83 * @hide
paulhuc9925e02021-03-17 20:30:33 +080084 */
85 public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
86
87 /** Dns resolver settings */
88
89 /**
90 * Sample validity in seconds to configure for the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +080091 *
92 * @hide
paulhuc9925e02021-03-17 20:30:33 +080093 */
94 public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
95 "dns_resolver_sample_validity_seconds";
96
97 /**
98 * Success threshold in percent for use with the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +080099 *
100 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800101 */
102 public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
103 "dns_resolver_success_threshold_percent";
104
105 /**
106 * Minimum number of samples needed for statistics to be considered meaningful in the
107 * system DNS resolver.
paulhu94430952021-03-23 00:24:50 +0800108 *
109 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800110 */
111 public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
112
113 /**
114 * Maximum number taken into account for statistics purposes in the system DNS resolver.
paulhu94430952021-03-23 00:24:50 +0800115 *
116 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800117 */
118 public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
119
paulhu94430952021-03-23 00:24:50 +0800120 private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
121 private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
122
paulhuc9925e02021-03-17 20:30:33 +0800123 /** Network switch notification settings */
124
125 /**
126 * The maximum number of notifications shown in 24 hours when switching networks.
paulhu94430952021-03-23 00:24:50 +0800127 *
128 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800129 */
130 public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
131 "network_switch_notification_daily_limit";
132
133 /**
134 * The minimum time in milliseconds between notifications when switching networks.
paulhu94430952021-03-23 00:24:50 +0800135 *
136 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800137 */
138 public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
139 "network_switch_notification_rate_limit_millis";
140
141 /** Captive portal settings */
142
143 /**
144 * The URL used for HTTP captive portal detection upon a new connection.
145 * A 204 response code from the server is used for validation.
paulhu94430952021-03-23 00:24:50 +0800146 *
147 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800148 */
149 public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
150
151 /**
152 * What to do when connecting a network that presents a captive portal.
paulhu94430952021-03-23 00:24:50 +0800153 * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
paulhuc9925e02021-03-17 20:30:33 +0800154 *
155 * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
paulhu94430952021-03-23 00:24:50 +0800156 *
157 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800158 */
159 public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
160
161 /**
162 * Don't attempt to detect captive portals.
163 */
164 public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
165
166 /**
167 * When detecting a captive portal, display a notification that
168 * prompts the user to sign in.
169 */
170 public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
171
172 /**
173 * When detecting a captive portal, immediately disconnect from the
174 * network and do not reconnect to that network in the future.
175 */
176 public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
177
178 /** @hide */
179 @Retention(RetentionPolicy.SOURCE)
180 @IntDef(value = {
181 CAPTIVE_PORTAL_MODE_IGNORE,
182 CAPTIVE_PORTAL_MODE_PROMPT,
183 CAPTIVE_PORTAL_MODE_AVOID,
184 })
185 public @interface CaptivePortalMode {}
186
187 /** Global http proxy settings */
188
189 /**
190 * Host name for global http proxy. Set via ConnectivityManager.
paulhu94430952021-03-23 00:24:50 +0800191 *
192 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800193 */
194 public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
195
196 /**
197 * Integer host port 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_PORT = "global_http_proxy_port";
202
203 /**
204 * Exclusion list for global proxy. This string contains a list of
205 * comma-separated domains where the global proxy does not apply.
206 * Domains should be listed in a comma- separated list. Example of
207 * acceptable formats: ".domain1.com,my.domain2.com" Use
208 * ConnectivityManager to set/get.
paulhu94430952021-03-23 00:24:50 +0800209 *
210 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800211 */
212 public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
213 "global_http_proxy_exclusion_list";
214
215 /**
216 * The location PAC File for the proxy.
paulhu94430952021-03-23 00:24:50 +0800217 *
218 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800219 */
220 public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
221
222 /** Private dns settings */
223
224 /**
225 * The requested Private DNS mode (string), and an accompanying specifier (string).
226 *
227 * Currently, the specifier holds the chosen provider name when the mode requests
228 * a specific provider. It may be used to store the provider name even when the
229 * mode changes so that temporarily disabling and re-enabling the specific
230 * provider mode does not necessitate retyping the provider hostname.
paulhu94430952021-03-23 00:24:50 +0800231 *
232 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800233 */
234 public static final String PRIVATE_DNS_MODE = "private_dns_mode";
235
236 /**
237 * The specific Private DNS provider name.
paulhu94430952021-03-23 00:24:50 +0800238 *
239 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800240 */
241 public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
242
243 /**
244 * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
245 * This allows changing the default mode without effectively disabling other modes,
246 * all of which require explicit user action to enable/configure. See also b/79719289.
247 *
248 * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
paulhu94430952021-03-23 00:24:50 +0800249 *
250 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800251 */
252 public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
253
254 /** Other settings */
255
256 /**
257 * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
258 * the receivers of the PendingIntent an opportunity to make a new network request before
259 * the Network satisfying the request is potentially removed.
paulhu94430952021-03-23 00:24:50 +0800260 *
261 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800262 */
263 public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
264 "connectivity_release_pending_intent_delay_ms";
265
266 /**
267 * Whether the mobile data connection should remain active even when higher
268 * priority networks like WiFi are active, to help make network switching faster.
269 *
270 * See ConnectivityService for more info.
271 *
272 * (0 = disabled, 1 = enabled)
paulhu94430952021-03-23 00:24:50 +0800273 *
274 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800275 */
276 public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
277
278 /**
279 * Whether the wifi data connection should remain active even when higher
280 * priority networks like Ethernet are active, to keep both networks.
281 * In the case where higher priority networks are connected, wifi will be
282 * unused unless an application explicitly requests to use it.
283 *
284 * See ConnectivityService for more info.
285 *
286 * (0 = disabled, 1 = enabled)
paulhu94430952021-03-23 00:24:50 +0800287 *
288 * @hide
paulhuc9925e02021-03-17 20:30:33 +0800289 */
290 public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
291
paulhu845456e2021-03-17 17:19:09 +0800292 /**
293 * Whether to automatically switch away from wifi networks that lose Internet access.
294 * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
295 * avoids such networks. Valid values are:
296 *
297 * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
298 * null: Ask the user whether to switch away from bad wifi.
299 * 1: Avoid bad wifi.
paulhu94430952021-03-23 00:24:50 +0800300 *
301 * @hide
paulhu845456e2021-03-17 17:19:09 +0800302 */
303 public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
304
305 /**
paulhu94430952021-03-23 00:24:50 +0800306 * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
307 */
308 public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
309
310 /**
311 * Ask the user whether to switch away from bad wifi.
312 */
313 public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
314
315 /**
316 * Avoid bad wifi.
317 */
318 public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
319
320 /** @hide */
321 @Retention(RetentionPolicy.SOURCE)
322 @IntDef(value = {
323 NETWORK_AVOID_BAD_WIFI_IGNORE,
324 NETWORK_AVOID_BAD_WIFI_PROMPT,
325 NETWORK_AVOID_BAD_WIFI_AVOID,
326 })
327 public @interface NetworkAvoidBadWifi {}
328
329 /**
paulhu845456e2021-03-17 17:19:09 +0800330 * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
331 * overridden by the system based on device or application state. If null, the value
332 * specified by config_networkMeteredMultipathPreference is used.
paulhu94430952021-03-23 00:24:50 +0800333 *
334 * @hide
paulhu845456e2021-03-17 17:19:09 +0800335 */
336 public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
337 "network_metered_multipath_preference";
paulhu94430952021-03-23 00:24:50 +0800338
339 /**
paulhu344c1162021-05-11 09:42:50 +0800340 * A list of uids that should go on cellular networks in preference even when higher-priority
paulhu7a4eeed2021-03-25 13:17:58 +0800341 * networks are connected.
342 *
343 * @hide
344 */
paulhu344c1162021-05-11 09:42:50 +0800345 public static final String MOBILE_DATA_PREFERRED_UIDS = "mobile_data_preferred_uids";
paulhu7a4eeed2021-03-25 13:17:58 +0800346
347 /**
lucaslin57f9ba82021-04-23 21:03:39 +0800348 * One of the private DNS modes that indicates the private DNS mode is off.
349 */
lucaslin89621282021-06-21 16:39:08 +0800350 public static final int PRIVATE_DNS_MODE_OFF = ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OFF;
lucaslin57f9ba82021-04-23 21:03:39 +0800351
352 /**
353 * One of the private DNS modes that indicates the private DNS mode is automatic, which
354 * will try to use the current DNS as private DNS.
355 */
lucaslin89621282021-06-21 16:39:08 +0800356 public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC =
357 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OPPORTUNISTIC;
lucaslin57f9ba82021-04-23 21:03:39 +0800358
359 /**
360 * One of the private DNS modes that indicates the private DNS mode is strict and the
361 * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of
362 * {@link #PRIVATE_DNS_SPECIFIER} as private DNS.
363 */
lucaslin89621282021-06-21 16:39:08 +0800364 public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME =
365 ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
lucaslin57f9ba82021-04-23 21:03:39 +0800366
367 /** @hide */
368 @Retention(RetentionPolicy.SOURCE)
369 @IntDef(value = {
370 PRIVATE_DNS_MODE_OFF,
371 PRIVATE_DNS_MODE_OPPORTUNISTIC,
372 PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
373 })
374 public @interface PrivateDnsMode {}
375
lucaslin57f9ba82021-04-23 21:03:39 +0800376 /**
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) {
paulhu236a9922021-03-29 10:50:36 +0800565 throw new IllegalArgumentException("Count must be more than 0.");
paulhu94430952021-03-23 00:24:50 +0800566 }
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.
paulhu236a9922021-03-29 10:50:36 +0800588 * The duration will be rounded down to the next millisecond, and must be positive.
paulhu94430952021-03-23 00:24:50 +0800589 *
590 * @param context The {@link Context} to set the setting.
591 * @param duration The minimum duration between notifications when switching networks.
592 */
593 public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
594 @NonNull Duration duration) {
595 final int time = (int) duration.toMillis();
596 if (time < 0) {
597 throw new IllegalArgumentException("Invalid duration.");
598 }
599 Settings.Global.putInt(context.getContentResolver(),
600 NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
601 }
602
603 /**
604 * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
605 *
606 * @param context The {@link Context} to query the setting.
607 * @return The URL used for HTTP captive portal detection upon a new connection.
608 */
609 @Nullable
610 public static String getCaptivePortalHttpUrl(@NonNull Context context) {
611 return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
612 }
613
614 /**
615 * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
paulhu236a9922021-03-29 10:50:36 +0800616 * The URL is accessed to check for connectivity and presence of a captive portal on a network.
617 * The URL should respond with HTTP status 204 to a GET request, and the stack will use
618 * redirection status as a signal for captive portal detection.
619 * If the URL is set to null or is otherwise incorrect or inaccessible, the stack will fail to
620 * detect connectivity and portals. This will often result in loss of connectivity.
paulhu94430952021-03-23 00:24:50 +0800621 *
622 * @param context The {@link Context} to set the setting.
623 * @param url The URL used for HTTP captive portal detection upon a new connection.
624 */
625 public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
626 Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
627 }
628
629 /**
630 * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
631 *
632 * @param context The {@link Context} to query the setting.
633 * @param def The default mode if no setting value.
634 * @return The mode when connecting a network that presents a captive portal.
635 */
636 @CaptivePortalMode
637 public static int getCaptivePortalMode(@NonNull Context context,
638 @CaptivePortalMode int def) {
639 return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
640 }
641
642 /**
643 * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
644 *
645 * @param context The {@link Context} to set the setting.
646 * @param mode The mode when connecting a network that presents a captive portal.
647 */
648 public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
649 if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
650 || mode == CAPTIVE_PORTAL_MODE_PROMPT
651 || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
652 throw new IllegalArgumentException("Invalid captive portal mode");
653 }
654 Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
655 }
656
657 /**
658 * Get the global HTTP proxy applied to the device, or null if none.
659 *
660 * @param context The {@link Context} to query the setting.
661 * @return The {@link ProxyInfo} which build from global http proxy settings.
662 */
663 @Nullable
664 public static ProxyInfo getGlobalProxy(@NonNull Context context) {
665 final String host = Settings.Global.getString(
666 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
667 final int port = Settings.Global.getInt(
668 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
669 final String exclusionList = Settings.Global.getString(
670 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
671 final String pacFileUrl = Settings.Global.getString(
672 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
673
674 if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
675 return null; // No global proxy.
676 }
677
678 if (TextUtils.isEmpty(pacFileUrl)) {
679 return ProxyInfo.buildDirectProxy(
680 host, port, ProxyUtils.exclusionStringAsList(exclusionList));
681 } else {
682 return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
683 }
684 }
685
686 /**
687 * Set global http proxy settings from given {@link ProxyInfo}.
688 *
689 * @param context The {@link Context} to set the setting.
690 * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
691 * {@link ProxyInfo#buildPacProxy(Uri)} or
692 * {@link ProxyInfo#buildDirectProxy(String, int, List)}
693 */
694 public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
695 final String host = proxyInfo.getHost();
696 final int port = proxyInfo.getPort();
697 final String exclusionList = proxyInfo.getExclusionListAsString();
698 final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
699
700 if (TextUtils.isEmpty(pacFileUrl)) {
701 Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
702 Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
703 Settings.Global.putString(
704 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
705 Settings.Global.putString(
706 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
707 } else {
708 Settings.Global.putString(
709 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
710 Settings.Global.putString(
711 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
712 Settings.Global.putInt(
713 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
714 Settings.Global.putString(
715 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
716 }
717 }
718
719 /**
720 * Clear all global http proxy settings.
721 *
722 * @param context The {@link Context} to set the setting.
723 */
724 public static void clearGlobalProxy(@NonNull Context context) {
725 Settings.Global.putString(
726 context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
727 Settings.Global.putInt(
728 context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
729 Settings.Global.putString(
730 context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
731 Settings.Global.putString(
732 context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
733 }
734
lucaslin57f9ba82021-04-23 21:03:39 +0800735 /**
736 * Get private DNS mode from settings.
737 *
738 * @param context The Context to query the private DNS mode from settings.
739 * @return A string of private DNS mode.
740 */
741 @PrivateDnsMode
742 public static int getPrivateDnsMode(@NonNull Context context) {
lucaslin89621282021-06-21 16:39:08 +0800743 return ConnectivitySettingsUtils.getPrivateDnsMode(context);
lucaslin57f9ba82021-04-23 21:03:39 +0800744 }
745
746 /**
747 * Set private DNS mode to settings.
748 *
749 * @param context The {@link Context} to set the private DNS mode.
750 * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
751 */
752 public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) {
lucaslin89621282021-06-21 16:39:08 +0800753 ConnectivitySettingsUtils.setPrivateDnsMode(context, mode);
lucaslin57f9ba82021-04-23 21:03:39 +0800754 }
755
paulhu94430952021-03-23 00:24:50 +0800756 /**
757 * Get specific private dns provider name from {@link Settings}.
758 *
759 * @param context The {@link Context} to query the setting.
760 * @return The specific private dns provider name, or null if no setting value.
761 */
762 @Nullable
763 public static String getPrivateDnsHostname(@NonNull Context context) {
lucaslin89621282021-06-21 16:39:08 +0800764 return ConnectivitySettingsUtils.getPrivateDnsHostname(context);
paulhu94430952021-03-23 00:24:50 +0800765 }
766
767 /**
768 * Set specific private dns provider name to {@link Settings}.
769 *
770 * @param context The {@link Context} to set the setting.
771 * @param specifier The specific private dns provider name.
772 */
lucaslin89621282021-06-21 16:39:08 +0800773 public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) {
774 ConnectivitySettingsUtils.setPrivateDnsHostname(context, specifier);
paulhu94430952021-03-23 00:24:50 +0800775 }
776
777 /**
778 * Get default private dns mode from {@link Settings}.
779 *
780 * @param context The {@link Context} to query the setting.
781 * @return The default private dns mode.
782 */
783 @PrivateDnsMode
784 @NonNull
785 public static String getPrivateDnsDefaultMode(@NonNull Context context) {
786 return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
787 }
788
789 /**
790 * Set default private dns mode to {@link Settings}.
791 *
792 * @param context The {@link Context} to set the setting.
793 * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
794 * constants.
795 */
796 public static void setPrivateDnsDefaultMode(@NonNull Context context,
lucaslin57f9ba82021-04-23 21:03:39 +0800797 @NonNull @PrivateDnsMode int mode) {
paulhu94430952021-03-23 00:24:50 +0800798 if (!(mode == PRIVATE_DNS_MODE_OFF
799 || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
800 || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
801 throw new IllegalArgumentException("Invalid private dns mode");
802 }
lucaslin57f9ba82021-04-23 21:03:39 +0800803 Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE,
804 getPrivateDnsModeAsString(mode));
paulhu94430952021-03-23 00:24:50 +0800805 }
806
807 /**
808 * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
809 *
810 * @param context The {@link Context} to query the setting.
811 * @param def The default duration if no setting value.
812 * @return The duration to keep a PendingIntent-based request.
813 */
814 @NonNull
815 public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
816 @NonNull Duration def) {
817 final int duration = Settings.Secure.getInt(context.getContentResolver(),
818 CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
819 return Duration.ofMillis(duration);
820 }
821
822 /**
823 * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
paulhu236a9922021-03-29 10:50:36 +0800824 * The duration will be rounded down to the next millisecond, and must be positive.
paulhu94430952021-03-23 00:24:50 +0800825 *
826 * @param context The {@link Context} to set the setting.
827 * @param duration The duration to keep a PendingIntent-based request.
828 */
829 public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
830 @NonNull Duration duration) {
831 final int time = (int) duration.toMillis();
832 if (time < 0) {
833 throw new IllegalArgumentException("Invalid duration.");
834 }
835 Settings.Secure.putInt(
836 context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
837 }
838
839 /**
840 * Read from {@link Settings} whether the mobile data connection should remain active
841 * even when higher priority networks are active.
842 *
843 * @param context The {@link Context} to query the setting.
844 * @param def The default value if no setting value.
845 * @return Whether the mobile data connection should remain active even when higher
846 * priority networks are active.
847 */
848 public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
849 final int enable = Settings.Global.getInt(
850 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
851 return (enable != 0) ? true : false;
852 }
853
854 /**
855 * Write into {@link Settings} whether the mobile data connection should remain active
856 * even when higher priority networks are active.
857 *
858 * @param context The {@link Context} to set the setting.
859 * @param enable Whether the mobile data connection should remain active even when higher
860 * priority networks are active.
861 */
862 public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
863 Settings.Global.putInt(
864 context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
865 }
866
867 /**
868 * Read from {@link Settings} whether the wifi data connection should remain active
869 * even when higher priority networks are active.
870 *
871 * @param context The {@link Context} to query the setting.
872 * @param def The default value if no setting value.
873 * @return Whether the wifi data connection should remain active even when higher
874 * priority networks are active.
875 */
876 public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
877 final int enable = Settings.Global.getInt(
878 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
879 return (enable != 0) ? true : false;
880 }
881
882 /**
883 * Write into {@link Settings} whether the wifi data connection should remain active
884 * even when higher priority networks are active.
885 *
886 * @param context The {@link Context} to set the setting.
887 * @param enable Whether the wifi data connection should remain active even when higher
888 * priority networks are active
889 */
890 public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
891 Settings.Global.putInt(
892 context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
893 }
894
895 /**
896 * Get avoid bad wifi setting from {@link Settings}.
897 *
898 * @param context The {@link Context} to query the setting.
899 * @return The setting whether to automatically switch away from wifi networks that lose
900 * internet access.
901 */
902 @NetworkAvoidBadWifi
903 public static int getNetworkAvoidBadWifi(@NonNull Context context) {
904 final String setting =
905 Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
906 if ("0".equals(setting)) {
907 return NETWORK_AVOID_BAD_WIFI_IGNORE;
908 } else if ("1".equals(setting)) {
909 return NETWORK_AVOID_BAD_WIFI_AVOID;
910 } else {
911 return NETWORK_AVOID_BAD_WIFI_PROMPT;
912 }
913 }
914
915 /**
916 * Set avoid bad wifi setting to {@link Settings}.
917 *
918 * @param context The {@link Context} to set the setting.
919 * @param value Whether to automatically switch away from wifi networks that lose internet
920 * access.
921 */
922 public static void setNetworkAvoidBadWifi(@NonNull Context context,
923 @NetworkAvoidBadWifi int value) {
924 final String setting;
925 if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
926 setting = "0";
927 } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
928 setting = "1";
929 } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
930 setting = null;
931 } else {
932 throw new IllegalArgumentException("Invalid avoid bad wifi setting");
933 }
934 Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
935 }
936
937 /**
938 * Get network metered multipath preference from {@link Settings}.
939 *
940 * @param context The {@link Context} to query the setting.
941 * @return The network metered multipath preference which should be one of
942 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
943 * by config_networkMeteredMultipathPreference is used.
944 */
945 @Nullable
946 public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
947 return Settings.Global.getString(
948 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
949 }
950
951 /**
952 * Set network metered multipath preference to {@link Settings}.
953 *
954 * @param context The {@link Context} to set the setting.
955 * @param preference The network metered multipath preference which should be one of
956 * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
957 * specified by config_networkMeteredMultipathPreference is used.
958 */
959 public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
960 @NonNull @MultipathPreference String preference) {
961 if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
962 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
963 || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
964 throw new IllegalArgumentException("Invalid private dns mode");
965 }
966 Settings.Global.putString(
967 context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
968 }
paulhu7a4eeed2021-03-25 13:17:58 +0800969
paulhu91e78062021-05-26 16:16:57 +0800970 private static Set<Integer> getUidSetFromString(@Nullable String uidList) {
971 final Set<Integer> uids = new ArraySet<>();
972 if (TextUtils.isEmpty(uidList)) {
973 return uids;
974 }
975 for (String uid : uidList.split(";")) {
976 uids.add(Integer.valueOf(uid));
977 }
978 return uids;
979 }
980
981 private static String getUidStringFromSet(@NonNull Set<Integer> uidList) {
982 final StringJoiner joiner = new StringJoiner(";");
983 for (Integer uid : uidList) {
984 if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) {
985 throw new IllegalArgumentException("Invalid uid");
986 }
987 joiner.add(uid.toString());
988 }
989 return joiner.toString();
990 }
991
paulhu7a4eeed2021-03-25 13:17:58 +0800992 /**
paulhu344c1162021-05-11 09:42:50 +0800993 * Get the list of uids(from {@link Settings}) that should go on cellular networks in preference
paulhu7a4eeed2021-03-25 13:17:58 +0800994 * even when higher-priority networks are connected.
995 *
996 * @param context The {@link Context} to query the setting.
paulhu344c1162021-05-11 09:42:50 +0800997 * @return A list of uids that should go on cellular networks in preference even when
paulhu7a4eeed2021-03-25 13:17:58 +0800998 * higher-priority networks are connected or null if no setting value.
999 */
paulhu344c1162021-05-11 09:42:50 +08001000 @NonNull
1001 public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) {
1002 final String uidList = Settings.Secure.getString(
1003 context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS);
paulhu91e78062021-05-26 16:16:57 +08001004 return getUidSetFromString(uidList);
paulhu7a4eeed2021-03-25 13:17:58 +08001005 }
1006
1007 /**
paulhu344c1162021-05-11 09:42:50 +08001008 * Set the list of uids(to {@link Settings}) that should go on cellular networks in preference
paulhu7a4eeed2021-03-25 13:17:58 +08001009 * even when higher-priority networks are connected.
1010 *
1011 * @param context The {@link Context} to set the setting.
paulhu344c1162021-05-11 09:42:50 +08001012 * @param uidList A list of uids that should go on cellular networks in preference even when
paulhu7a4eeed2021-03-25 13:17:58 +08001013 * higher-priority networks are connected.
1014 */
paulhu344c1162021-05-11 09:42:50 +08001015 public static void setMobileDataPreferredUids(@NonNull Context context,
1016 @NonNull Set<Integer> uidList) {
paulhu91e78062021-05-26 16:16:57 +08001017 final String uids = getUidStringFromSet(uidList);
1018 Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, uids);
paulhu7a4eeed2021-03-25 13:17:58 +08001019 }
paulhu69afcd52021-04-27 00:14:47 +08001020
1021 /**
paulhu91e78062021-05-26 16:16:57 +08001022 * Get the list of uids (from {@link Settings}) allowed to use restricted networks.
1023 *
1024 * Access to restricted networks is controlled by the (preinstalled-only)
1025 * CONNECTIVITY_USE_RESTRICTED_NETWORKS permission, but highly privileged
1026 * callers can also set a list of uids that can access restricted networks.
1027 *
1028 * This is useful for example in some jurisdictions where government apps,
1029 * that can't be preinstalled, must still have access to emergency services.
paulhu69afcd52021-04-27 00:14:47 +08001030 *
1031 * @param context The {@link Context} to query the setting.
paulhu91e78062021-05-26 16:16:57 +08001032 * @return A list of uids that is allowed to use restricted networks or null if no setting
paulhu257a5cf2021-05-14 15:27:36 +08001033 * value.
paulhu69afcd52021-04-27 00:14:47 +08001034 */
1035 @NonNull
paulhu91e78062021-05-26 16:16:57 +08001036 public static Set<Integer> getUidsAllowedOnRestrictedNetworks(@NonNull Context context) {
paulhu44280442021-05-31 10:42:13 +08001037 final String uidList = Settings.Global.getString(
paulhu91e78062021-05-26 16:16:57 +08001038 context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS);
1039 return getUidSetFromString(uidList);
paulhu69afcd52021-04-27 00:14:47 +08001040 }
1041
1042 /**
paulhu91e78062021-05-26 16:16:57 +08001043 * Set the list of uids(from {@link Settings}) that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +08001044 *
1045 * @param context The {@link Context} to set the setting.
paulhu91e78062021-05-26 16:16:57 +08001046 * @param uidList A list of uids that is allowed to use restricted networks.
paulhu69afcd52021-04-27 00:14:47 +08001047 */
paulhu91e78062021-05-26 16:16:57 +08001048 public static void setUidsAllowedOnRestrictedNetworks(@NonNull Context context,
1049 @NonNull Set<Integer> uidList) {
1050 final String uids = getUidStringFromSet(uidList);
paulhu44280442021-05-31 10:42:13 +08001051 Settings.Global.putString(context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS,
paulhu91e78062021-05-26 16:16:57 +08001052 uids);
paulhu69afcd52021-04-27 00:14:47 +08001053 }
paulhu845456e2021-03-17 17:19:09 +08001054}