Merge "Support Dual ViLTE stats"
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..94f9232
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,19 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/net"
+ },
+ {
+ "path": "packages/modules/NetworkStack"
+ },
+ {
+ "path": "packages/modules/CaptivePortalLogin"
+ },
+ {
+ "path": "packages/modules/Connectivity"
+ },
+ {
+ "path": "packages/modules/Connectivity/Tethering"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/jni/android_net_NetworkUtils.cpp b/core/jni/android_net_NetworkUtils.cpp
index 7508108..1cee895 100644
--- a/core/jni/android_net_NetworkUtils.cpp
+++ b/core/jni/android_net_NetworkUtils.cpp
@@ -52,27 +52,6 @@
// FrameworkListener limits the size of commands to 4096 bytes.
constexpr int MAXCMDSIZE = 4096;
-static void throwErrnoException(JNIEnv* env, const char* functionName, int error) {
- ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
- if (detailMessage.get() == NULL) {
- // Not really much we can do here. We're probably dead in the water,
- // but let's try to stumble on...
- env->ExceptionClear();
- }
- static jclass errnoExceptionClass =
- MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException"));
-
- static jmethodID errnoExceptionCtor =
- GetMethodIDOrDie(env, errnoExceptionClass,
- "<init>", "(Ljava/lang/String;I)V");
-
- jobject exception = env->NewObject(errnoExceptionClass,
- errnoExceptionCtor,
- detailMessage.get(),
- error);
- env->Throw(reinterpret_cast<jthrowable>(exception));
-}
-
static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
{
struct sock_filter filter_code[] = {
@@ -123,11 +102,6 @@
return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
}
-static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
-{
- return (jboolean) !queryUserAccess(uid, netId);
-}
-
static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
{
if (env->GetArrayLength(addr) != len) {
@@ -150,7 +124,7 @@
int fd = resNetworkQuery(netId, queryname.data(), ns_class, ns_type, flags);
if (fd < 0) {
- throwErrnoException(env, "resNetworkQuery", -fd);
+ jniThrowErrnoException(env, "resNetworkQuery", -fd);
return nullptr;
}
@@ -165,7 +139,7 @@
int fd = resNetworkSend(netId, data, msgLen, flags);
if (fd < 0) {
- throwErrnoException(env, "resNetworkSend", -fd);
+ jniThrowErrnoException(env, "resNetworkSend", -fd);
return nullptr;
}
@@ -180,13 +154,13 @@
int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
jniSetFileDescriptorOfFD(env, javaFd, -1);
if (res < 0) {
- throwErrnoException(env, "resNetworkResult", -res);
+ jniThrowErrnoException(env, "resNetworkResult", -res);
return nullptr;
}
jbyteArray answer = env->NewByteArray(res);
if (answer == nullptr) {
- throwErrnoException(env, "resNetworkResult", ENOMEM);
+ jniThrowErrnoException(env, "resNetworkResult", ENOMEM);
return nullptr;
} else {
env->SetByteArrayRegion(answer, 0, res,
@@ -208,7 +182,7 @@
static jobject android_net_utils_getDnsNetwork(JNIEnv *env, jobject thiz) {
unsigned dnsNetId = 0;
if (int res = getNetworkForDns(&dnsNetId) < 0) {
- throwErrnoException(env, "getDnsNetId", -res);
+ jniThrowErrnoException(env, "getDnsNetId", -res);
return nullptr;
}
bool privateDnsBypass = dnsNetId & NETID_USE_LOCAL_NAMESERVERS;
@@ -233,8 +207,8 @@
// Obtain the parameters of the TCP repair window.
int rc = getsockopt(fd, IPPROTO_TCP, TCP_REPAIR_WINDOW, &trw, &size);
if (rc == -1) {
- throwErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
- return NULL;
+ jniThrowErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
+ return NULL;
}
struct tcp_info tcpinfo = {};
@@ -244,8 +218,8 @@
// should be applied to the window size.
rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpinfo, &tcpinfo_size);
if (rc == -1) {
- throwErrnoException(env, "getsockopt : TCP_INFO", errno);
- return NULL;
+ jniThrowErrnoException(env, "getsockopt : TCP_INFO", errno);
+ return NULL;
}
jclass class_TcpRepairWindow = env->FindClass("android/net/TcpRepairWindow");
@@ -267,7 +241,6 @@
{ "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
{ "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
- { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
{ "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
{ "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
{ "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
diff --git a/framework/Android.bp b/framework/Android.bp
index 9da27d2..017ff51 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -23,7 +23,25 @@
default_applicable_licenses: ["frameworks_base_license"],
}
-// TODO: use a java_library in the bootclasspath instead
+java_library {
+ name: "framework-connectivity-protos",
+ proto: {
+ type: "nano",
+ },
+ srcs: [
+ // TODO: consider moving relevant .proto files directly to the module directory
+ ":framework-javastream-protos",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.tethering",
+ ],
+ jarjar_rules: "jarjar-rules-proto.txt",
+ visibility: [
+ "//visibility:private",
+ ],
+}
+
filegroup {
name: "framework-connectivity-internal-sources",
srcs: [
@@ -84,3 +102,39 @@
],
permitted_packages: ["android.net", "com.android.connectivity.aidl"],
}
+
+java_library {
+ name: "framework-connectivity.impl",
+ // Instead of building against private API (framework.jar),
+ // build against core_platform + framework-minus-apex + module
+ // stub libs. This allows framework.jar to depend on this library,
+ // so it can be part of the private API until all clients have been migrated.
+ // TODO: just build against module_api, and remove this jar from
+ // the private API.
+ sdk_version: "core_platform",
+ srcs: [
+ ":framework-connectivity-sources",
+ ],
+ aidl: {
+ include_dirs: [
+ "frameworks/base/core/java", // For framework parcelables
+ "frameworks/native/aidl/binder", // For PersistableBundle.aidl
+ ],
+ },
+ libs: [
+ "framework-minus-apex",
+ // TODO: just framework-tethering, framework-wifi when building against module_api
+ "framework-tethering.stubs.module_lib",
+ "framework-wifi.stubs.module_lib",
+ "unsupportedappusage",
+ "ServiceConnectivityResources",
+ ],
+ static_libs: [
+ "framework-connectivity-protos",
+ "net-utils-device-common",
+ ],
+ jarjar_rules: "jarjar-rules.txt",
+ apex_available: ["com.android.tethering"],
+ installable: true,
+ permitted_packages: ["android.net", "com.android.connectivity.aidl"],
+}
diff --git a/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/framework/aidl-export/android/net/NetworkScore.aidl
similarity index 79%
copy from framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to framework/aidl-export/android/net/NetworkScore.aidl
index 7979afc..af12dcf 100644
--- a/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/framework/aidl-export/android/net/NetworkScore.aidl
@@ -1,6 +1,5 @@
/**
- *
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (c) 2021, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +16,5 @@
package android.net;
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
-}
+parcelable NetworkScore;
+
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 243e4ca..ad44b27 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -87,6 +87,7 @@
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
method public boolean isDefaultNetworkActive();
method @Deprecated public static boolean isNetworkTypeValid(int);
+ method public void registerBestMatchingNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
@@ -290,6 +291,7 @@
ctor public NetworkCapabilities();
ctor public NetworkCapabilities(android.net.NetworkCapabilities);
method public int describeContents();
+ method @NonNull public int[] getCapabilities();
method public int getLinkDownstreamBandwidthKbps();
method public int getLinkUpstreamBandwidthKbps();
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
@@ -394,6 +396,7 @@
public static class NetworkRequest.Builder {
ctor public NetworkRequest.Builder();
+ ctor public NetworkRequest.Builder(@NonNull android.net.NetworkRequest);
method public android.net.NetworkRequest.Builder addCapability(int);
method public android.net.NetworkRequest.Builder addTransportType(int);
method public android.net.NetworkRequest build();
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 4b33366..35e45ec 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -6,25 +6,134 @@
}
public class ConnectivityManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void factoryReset();
method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot();
+ method @Nullable public android.net.ProxyInfo getGlobalProxy();
method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
+ method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackAsUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
+ method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
+ method public void systemReady();
+ field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
+ field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
+ field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000
+ field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
+ field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
+ field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
+ field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
+ field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
+ field public static final int BLOCKED_REASON_NONE = 0; // 0x0
+ field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
+ field public static final String PRIVATE_DNS_MODE_OFF = "off";
+ field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
+ field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+ field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
+ field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
+ }
+
+ public static class ConnectivityManager.NetworkCallback {
+ method public void onBlockedStatusChanged(@NonNull android.net.Network, int);
+ }
+
+ public class ConnectivitySettingsManager {
+ method public static void clearGlobalProxy(@NonNull android.content.Context);
+ method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
+ method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
+ method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context);
+ method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
+ method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
+ method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+ method @Nullable public static String getMobileDataPreferredApps(@NonNull android.content.Context);
+ method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
+ method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
+ method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
+ method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
+ method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
+ method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+ method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
+ method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
+ method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>);
+ method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
+ method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
+ method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+ method public static void setMobileDataPreferredApps(@NonNull android.content.Context, @Nullable String);
+ method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
+ method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
+ method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
+ method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String);
+ method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
+ method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+ method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
+ field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
+ field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
+ field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
+ field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
+ field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
}
public final class NetworkAgentConfig implements android.os.Parcelable {
method @Nullable public String getSubscriberId();
+ method public boolean isBypassableVpn();
}
public static final class NetworkAgentConfig.Builder {
+ method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
}
public final class NetworkCapabilities implements android.os.Parcelable {
+ ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, long);
+ method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
+ method public boolean hasUnwantedCapability(int);
+ field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
+ field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
+ field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
+ field public static final long REDACT_FOR_NETWORK_SETTINGS = 4L; // 0x4L
+ field public static final long REDACT_NONE = 0L; // 0x0L
field public static final int TRANSPORT_TEST = 7; // 0x7
}
+ public static final class NetworkCapabilities.Builder {
+ method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
+ }
+
+ public class NetworkRequest implements android.os.Parcelable {
+ method public boolean hasUnwantedCapability(int);
+ }
+
+ public static class NetworkRequest.Builder {
+ method @NonNull public android.net.NetworkRequest.Builder addUnwantedCapability(int);
+ method @NonNull public android.net.NetworkRequest.Builder removeUnwantedCapability(int);
+ method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ ctor public ParseException(@NonNull String);
+ ctor public ParseException(@NonNull String, @NonNull Throwable);
+ }
+
public final class TcpRepairWindow {
ctor public TcpRepairWindow(int, int, int, int, int, int);
field public final int maxWindow;
@@ -60,6 +169,11 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkSpecifier> CREATOR;
}
+ public interface TransportInfo {
+ method public default long getApplicableRedactions();
+ method @NonNull public default android.net.TransportInfo makeCopy(long);
+ }
+
public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
ctor public VpnTransportInfo(int);
method public int describeContents();
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index a98f14e..6f832c6 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -18,7 +18,7 @@
method public long getRefreshTimeMillis();
method @Nullable public android.net.Uri getUserPortalUrl();
method public int getUserPortalUrlSource();
- method @Nullable public String getVenueFriendlyName();
+ method @Nullable public CharSequence getVenueFriendlyName();
method @Nullable public android.net.Uri getVenueInfoUrl();
method public int getVenueInfoUrlSource();
method public boolean isCaptive();
@@ -40,7 +40,7 @@
method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable CharSequence);
method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
}
@@ -52,11 +52,11 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
- method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
+ method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.QosCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
- method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable android.net.ConnectivityManager.OnSetOemNetworkPreferenceListener);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
@@ -78,10 +78,6 @@
field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
}
- public static interface ConnectivityManager.OnSetOemNetworkPreferenceListener {
- method public void onComplete();
- }
-
@Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
method @Deprecated public void onTetheringFailed();
@@ -216,10 +212,13 @@
public abstract class NetworkAgent {
ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
method @Nullable public android.net.Network getNetwork();
method public void markConnected();
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
method public void onAutomaticReconnectDisabled();
+ method public void onNetworkCreated();
+ method public void onNetworkDisconnected();
method public void onNetworkUnwanted();
method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
method public void onQosCallbackUnregistered(int);
@@ -234,8 +233,8 @@
method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
method public final void sendQosCallbackError(int, int);
- method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
- method public final void sendQosSessionLost(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
+ method public final void sendQosSessionLost(int, int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
@@ -265,7 +264,6 @@
}
public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
method @NonNull public int[] getAdministratorUids();
method @Nullable public String getSsid();
method @NonNull public int[] getTransportTypes();
@@ -321,6 +319,19 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
}
+ public final class NetworkScore implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getLegacyInt();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+ }
+
+ public static final class NetworkScore.Builder {
+ ctor public NetworkScore.Builder();
+ method @NonNull public android.net.NetworkScore build();
+ method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int);
+ }
+
public final class OemNetworkPreferences implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences();
@@ -368,6 +379,7 @@
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
field public static final int TYPE_EPS_BEARER = 1; // 0x1
+ field public static final int TYPE_NR_BEARER = 2; // 0x2
}
public interface QosSessionAttributes {
@@ -439,11 +451,6 @@
field public final int tcpWindowScale;
}
- public interface TransportInfo {
- method public default boolean hasLocationSensitiveFields();
- method @NonNull public default android.net.TransportInfo makeCopy(boolean);
- }
-
}
package android.net.apf {
diff --git a/framework/jarjar-rules-proto.txt b/framework/jarjar-rules-proto.txt
new file mode 100644
index 0000000..37b4dec
--- /dev/null
+++ b/framework/jarjar-rules-proto.txt
@@ -0,0 +1,3 @@
+keep android.net.NetworkCapabilitiesProto
+keep android.net.NetworkProto
+keep android.net.NetworkRequestProto
diff --git a/framework/jarjar-rules.txt b/framework/jarjar-rules.txt
new file mode 100644
index 0000000..0959840
--- /dev/null
+++ b/framework/jarjar-rules.txt
@@ -0,0 +1,10 @@
+rule com.android.net.module.util.** android.net.connectivity.framework.util.@1
+
+# TODO (b/149403767): remove the annotations from net-utils-device-common instead of here
+zap android.annotation.**
+zap com.android.net.module.annotation.**
+zap com.android.internal.annotations.**
+
+rule android.net.NetworkCapabilitiesProto* android.net.connectivity.proto.NetworkCapabilitiesProto@1
+rule android.net.NetworkProto* android.net.connectivity.proto.NetworkProto@1
+rule android.net.NetworkRequestProto* android.net.connectivity.proto.NetworkRequestProto@1
diff --git a/framework/src/android/net/CaptivePortalData.java b/framework/src/android/net/CaptivePortalData.java
index eafda4d..82dbd0f 100644
--- a/framework/src/android/net/CaptivePortalData.java
+++ b/framework/src/android/net/CaptivePortalData.java
@@ -42,7 +42,7 @@
private final long mByteLimit;
private final long mExpiryTimeMillis;
private final boolean mCaptive;
- private final String mVenueFriendlyName;
+ private final CharSequence mVenueFriendlyName;
private final int mVenueInfoUrlSource;
private final int mUserPortalUrlSource;
@@ -65,7 +65,7 @@
private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
- String venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
+ CharSequence venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
mRefreshTimeMillis = refreshTimeMillis;
mUserPortalUrl = userPortalUrl;
mVenueInfoUrl = venueInfoUrl;
@@ -80,7 +80,7 @@
private CaptivePortalData(Parcel p) {
this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
- p.readLong(), p.readLong(), p.readBoolean(), p.readString(), p.readInt(),
+ p.readLong(), p.readLong(), p.readBoolean(), p.readCharSequence(), p.readInt(),
p.readInt());
}
@@ -98,7 +98,7 @@
dest.writeLong(mByteLimit);
dest.writeLong(mExpiryTimeMillis);
dest.writeBoolean(mCaptive);
- dest.writeString(mVenueFriendlyName);
+ dest.writeCharSequence(mVenueFriendlyName);
dest.writeInt(mVenueInfoUrlSource);
dest.writeInt(mUserPortalUrlSource);
}
@@ -114,7 +114,7 @@
private long mBytesRemaining = -1;
private long mExpiryTime = -1;
private boolean mCaptive;
- private String mVenueFriendlyName;
+ private CharSequence mVenueFriendlyName;
private @CaptivePortalDataSource int mVenueInfoUrlSource = CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
private @CaptivePortalDataSource int mUserPortalUrlSource =
CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
@@ -228,7 +228,7 @@
* Set the venue friendly name.
*/
@NonNull
- public Builder setVenueFriendlyName(@Nullable String venueFriendlyName) {
+ public Builder setVenueFriendlyName(@Nullable CharSequence venueFriendlyName) {
mVenueFriendlyName = venueFriendlyName;
return this;
}
@@ -321,7 +321,7 @@
* Get the venue friendly name
*/
@Nullable
- public String getVenueFriendlyName() {
+ public CharSequence getVenueFriendlyName() {
return mVenueFriendlyName;
}
diff --git a/framework/src/android/net/ConnectivityDiagnosticsManager.java b/framework/src/android/net/ConnectivityDiagnosticsManager.java
index 5234494..3598ebc 100644
--- a/framework/src/android/net/ConnectivityDiagnosticsManager.java
+++ b/framework/src/android/net/ConnectivityDiagnosticsManager.java
@@ -28,7 +28,6 @@
import android.os.RemoteException;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -70,8 +69,8 @@
/** @hide */
public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
- mContext = Preconditions.checkNotNull(context, "missing context");
- mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+ mContext = Objects.requireNonNull(context, "missing context");
+ mService = Objects.requireNonNull(service, "missing IConnectivityManager");
}
/** @hide */
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 8c66db9..d196c1a 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -16,10 +16,12 @@
package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.LISTEN;
+import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
import static android.net.NetworkRequest.Type.REQUEST;
-import static android.net.NetworkRequest.Type.TRACK_BEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
import static android.net.QosCallback.QosCallbackRegistrationException;
@@ -31,11 +33,15 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.IpSecManager.UdpEncapsulationSocket;
@@ -58,20 +64,18 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Range;
import android.util.SparseIntArray;
-import com.android.connectivity.aidl.INetworkAgent;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.Protocol;
import libcore.net.event.NetworkEventDispatcher;
@@ -802,24 +806,134 @@
/**
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final String PRIVATE_DNS_MODE_OFF = "off";
/**
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
/**
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(value = {
+ PRIVATE_DNS_MODE_OFF,
+ PRIVATE_DNS_MODE_OPPORTUNISTIC,
+ PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+ })
+ public @interface PrivateDnsMode {}
+
/**
- * The default Private DNS mode.
- *
- * This may change from release to release or may become dependent upon
- * the capabilities of the underlying platform.
+ * Flag to indicate that an app is not subject to any restrictions that could result in its
+ * network access blocked.
*
* @hide
*/
- public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_NONE = 0;
+
+ /**
+ * Flag to indicate that an app is subject to Battery saver restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_BATTERY_SAVER = 1 << 0;
+
+ /**
+ * Flag to indicate that an app is subject to Doze restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_DOZE = 1 << 1;
+
+ /**
+ * Flag to indicate that an app is subject to App Standby restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_APP_STANDBY = 1 << 2;
+
+ /**
+ * Flag to indicate that an app is subject to Restricted mode restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3;
+
+ /**
+ * Flag to indicate that an app is blocked because it is subject to an always-on VPN but the VPN
+ * is not currently connected.
+ *
+ * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean)
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_LOCKDOWN_VPN = 1 << 4;
+
+ /**
+ * Flag to indicate that an app is subject to Data saver restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_DATA_SAVER = 1 << 16;
+
+ /**
+ * Flag to indicate that an app is subject to user restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 1 << 17;
+
+ /**
+ * Flag to indicate that an app is subject to Device admin restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 1 << 18;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"BLOCKED_"}, value = {
+ BLOCKED_REASON_NONE,
+ BLOCKED_REASON_BATTERY_SAVER,
+ BLOCKED_REASON_DOZE,
+ BLOCKED_REASON_APP_STANDBY,
+ BLOCKED_REASON_RESTRICTED_MODE,
+ BLOCKED_METERED_REASON_DATA_SAVER,
+ BLOCKED_METERED_REASON_USER_RESTRICTED,
+ BLOCKED_METERED_REASON_ADMIN_DISABLED,
+ })
+ public @interface BlockedReason {}
+
+ /**
+ * Set of blocked reasons that are only applicable on metered networks.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private final IConnectivityManager mService;
@@ -834,7 +948,6 @@
private final Context mContext;
- private INetworkPolicyManager mNPManager;
private final TetheringManager mTetheringManager;
/**
@@ -907,8 +1020,8 @@
/**
* @hide
- * TODO: Expose for SystemServer when becomes a module.
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public void systemReady() {
try {
mService.systemReady();
@@ -963,6 +1076,33 @@
}
/**
+ * Preference for {@link #setNetworkPreferenceForUser(UserHandle, int, Executor, Runnable)}.
+ * Specify that the traffic for this user should by follow the default rules.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0;
+
+ /**
+ * Preference for {@link #setNetworkPreferenceForUser(UserHandle, int, Executor, Runnable)}.
+ * Specify that the traffic for this user should by default go on a network with
+ * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE}, and on the system default network
+ * if no such network is available.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ PROFILE_NETWORK_PREFERENCE_DEFAULT,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE
+ })
+ public @interface ProfileNetworkPreference {
+ }
+
+ /**
* Specifies the preferred network type. When the device has more
* than one type available the preferred network type will be used.
*
@@ -1091,12 +1231,13 @@
* @param ranges the UID ranges to restrict
* @param requireVpn whether the specified UID ranges must use a VPN
*
- * TODO: expose as @SystemApi.
* @hide
*/
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_STACK})
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
public void setRequireVpnForUids(boolean requireVpn,
@NonNull Collection<Range<Integer>> ranges) {
Objects.requireNonNull(ranges);
@@ -1140,13 +1281,13 @@
*
* @param enabled whether legacy lockdown VPN is enabled or disabled
*
- * TODO: @SystemApi(client = MODULE_LIBRARIES)
- *
* @hide
*/
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
public void setLegacyLockdownVpnEnabled(boolean enabled) {
try {
mService.setLegacyLockdownVpnEnabled(enabled);
@@ -1742,7 +1883,9 @@
// Map from type to transports.
final int NOT_FOUND = -1;
final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND);
- Preconditions.checkArgument(transport != NOT_FOUND, "unknown legacy type: " + type);
+ if (transport == NOT_FOUND) {
+ throw new IllegalArgumentException("unknown legacy type: " + type);
+ }
nc.addTransportType(transport);
// Map from type to capabilities.
@@ -1847,8 +1990,8 @@
}
private PacketKeepalive(Network network, PacketKeepaliveCallback callback) {
- Preconditions.checkNotNull(network, "network cannot be null");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ Objects.requireNonNull(network, "network cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
mNetwork = network;
mExecutor = Executors.newSingleThreadExecutor();
mCallback = new ISocketKeepaliveCallback.Stub() {
@@ -2091,6 +2234,7 @@
*/
@Deprecated
@UnsupportedAppUsage
+ @SystemApi(client = MODULE_LIBRARIES)
public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
checkLegacyRoutingApiAccess();
try {
@@ -2223,7 +2367,9 @@
*/
public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) {
INetworkActivityListener rl = mNetworkActivityListeners.get(l);
- Preconditions.checkArgument(rl != null, "Listener was not registered.");
+ if (rl == null) {
+ throw new IllegalArgumentException("Listener was not registered.");
+ }
try {
mService.registerNetworkActivityListener(rl);
} catch (RemoteException e) {
@@ -2251,8 +2397,8 @@
* {@hide}
*/
public ConnectivityManager(Context context, IConnectivityManager service) {
- mContext = Preconditions.checkNotNull(context, "missing context");
- mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+ mContext = Objects.requireNonNull(context, "missing context");
+ mService = Objects.requireNonNull(service, "missing IConnectivityManager");
mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
sInstance = this;
}
@@ -2519,7 +2665,7 @@
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
- Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
+ Objects.requireNonNull(callback, "OnStartTetheringCallback cannot be null.");
final Executor executor = new Executor() {
@Override
@@ -2612,7 +2758,7 @@
public void registerTetheringEventCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull final OnTetheringEventCallback callback) {
- Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null.");
+ Objects.requireNonNull(callback, "OnTetheringEventCallback cannot be null.");
final TetheringEventCallback tetherCallback =
new TetheringEventCallback() {
@@ -2910,7 +3056,7 @@
public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
@NonNull @CallbackExecutor Executor executor,
@NonNull final OnTetheringEntitlementResultListener listener) {
- Preconditions.checkNotNull(listener, "TetheringEntitlementResultListener cannot be null.");
+ Objects.requireNonNull(listener, "TetheringEntitlementResultListener cannot be null.");
ResultReceiver wrappedListener = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -3003,8 +3149,9 @@
* HTTP proxy. A {@code null} value will clear the global HTTP proxy.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setGlobalProxy(ProxyInfo p) {
+ public void setGlobalProxy(@Nullable ProxyInfo p) {
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
@@ -3019,6 +3166,8 @@
* if no global HTTP proxy is set.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
+ @Nullable
public ProxyInfo getGlobalProxy() {
try {
return mService.getGlobalProxy();
@@ -3205,10 +3354,6 @@
}
}
- // TODO : remove this method. It is a stopgap measure to help sheperding a number
- // of dependent changes that would conflict throughout the automerger graph. Having this
- // temporarily helps with the process of going through with all these dependent changes across
- // the entire tree.
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
@@ -3218,20 +3363,8 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_FACTORY})
public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, int score, NetworkAgentConfig config) {
- return registerNetworkAgent(na, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
- }
-
- /**
- * @hide
- * Register a NetworkAgent with ConnectivityService.
- * @return Network corresponding to NetworkAgent.
- */
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_FACTORY})
- public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
+ NetworkCapabilities nc, @NonNull NetworkScore score, NetworkAgentConfig config,
+ int providerId) {
try {
return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId);
} catch (RemoteException e) {
@@ -3296,7 +3429,9 @@
}
public NetworkCallback(@Flag int flags) {
- Preconditions.checkArgument((flags & VALID_FLAGS) == flags);
+ if ((flags & VALID_FLAGS) != flags) {
+ throw new IllegalArgumentException("Invalid flags");
+ }
mFlags = flags;
}
@@ -3328,12 +3463,30 @@
* @param blocked Whether access to the {@link Network} is blocked due to system policy.
* @hide
*/
- public void onAvailable(@NonNull Network network,
+ public final void onAvailable(@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
- @NonNull LinkProperties linkProperties, boolean blocked) {
+ @NonNull LinkProperties linkProperties, @BlockedReason int blocked) {
// Internally only this method is called when a new network is available, and
// it calls the callback in the same way and order that older versions used
// to call so as not to change the behavior.
+ onAvailable(network, networkCapabilities, linkProperties, blocked != 0);
+ onBlockedStatusChanged(network, blocked);
+ }
+
+ /**
+ * Legacy variant of onAvailable that takes a boolean blocked reason.
+ *
+ * This method has never been public API, but it's not final, so there may be apps that
+ * implemented it and rely on it being called. Do our best not to break them.
+ * Note: such apps will also get a second call to onBlockedStatusChanged immediately after
+ * this method is called. There does not seem to be a way to avoid this.
+ * TODO: add a compat check to move apps off this method, and eventually stop calling it.
+ *
+ * @hide
+ */
+ public void onAvailable(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties, boolean blocked) {
onAvailable(network);
if (!networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
@@ -3341,7 +3494,7 @@
}
onCapabilitiesChanged(network, networkCapabilities);
onLinkPropertiesChanged(network, linkProperties);
- onBlockedStatusChanged(network, blocked);
+ // No call to onBlockedStatusChanged here. That is done by the caller.
}
/**
@@ -3505,6 +3658,26 @@
*/
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
+ /**
+ * Called when access to the specified network is blocked or unblocked.
+ *
+ * If a NetworkCallback object implements this method,
+ * {@link #onBlockedStatusChanged(Network, boolean)} will not be called.
+ *
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions : calling these methods while in a
+ * callback may return an outdated or even a null object.
+ *
+ * @param network The {@link Network} whose blocked status has changed.
+ * @param blocked The blocked status of this {@link Network}.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void onBlockedStatusChanged(@NonNull Network network, @BlockedReason int blocked) {
+ onBlockedStatusChanged(network, blocked != 0);
+ }
+
private NetworkRequest networkRequest;
private final int mFlags;
}
@@ -3531,29 +3704,28 @@
}
}
- private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER;
/** @hide */
- public static final int CALLBACK_PRECHECK = BASE + 1;
+ public static final int CALLBACK_PRECHECK = 1;
/** @hide */
- public static final int CALLBACK_AVAILABLE = BASE + 2;
+ public static final int CALLBACK_AVAILABLE = 2;
/** @hide arg1 = TTL */
- public static final int CALLBACK_LOSING = BASE + 3;
+ public static final int CALLBACK_LOSING = 3;
/** @hide */
- public static final int CALLBACK_LOST = BASE + 4;
+ public static final int CALLBACK_LOST = 4;
/** @hide */
- public static final int CALLBACK_UNAVAIL = BASE + 5;
+ public static final int CALLBACK_UNAVAIL = 5;
/** @hide */
- public static final int CALLBACK_CAP_CHANGED = BASE + 6;
+ public static final int CALLBACK_CAP_CHANGED = 6;
/** @hide */
- public static final int CALLBACK_IP_CHANGED = BASE + 7;
+ public static final int CALLBACK_IP_CHANGED = 7;
/** @hide obj = NetworkCapabilities, arg1 = seq number */
- private static final int EXPIRE_LEGACY_REQUEST = BASE + 8;
+ private static final int EXPIRE_LEGACY_REQUEST = 8;
/** @hide */
- public static final int CALLBACK_SUSPENDED = BASE + 9;
+ public static final int CALLBACK_SUSPENDED = 9;
/** @hide */
- public static final int CALLBACK_RESUMED = BASE + 10;
+ public static final int CALLBACK_RESUMED = 10;
/** @hide */
- public static final int CALLBACK_BLK_CHANGED = BASE + 11;
+ public static final int CALLBACK_BLK_CHANGED = 11;
/** @hide */
public static String getCallbackName(int whichCallback) {
@@ -3583,7 +3755,7 @@
}
CallbackHandler(Handler handler) {
- this(Preconditions.checkNotNull(handler, "Handler cannot be null.").getLooper());
+ this(Objects.requireNonNull(handler, "Handler cannot be null.").getLooper());
}
@Override
@@ -3620,7 +3792,7 @@
case CALLBACK_AVAILABLE: {
NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
LinkProperties lp = getObject(message, LinkProperties.class);
- callback.onAvailable(network, cap, lp, message.arg1 != 0);
+ callback.onAvailable(network, cap, lp, message.arg1);
break;
}
case CALLBACK_LOSING: {
@@ -3654,8 +3826,7 @@
break;
}
case CALLBACK_BLK_CHANGED: {
- boolean blocked = message.arg1 != 0;
- callback.onBlockedStatusChanged(network, blocked);
+ callback.onBlockedStatusChanged(network, message.arg1);
}
}
}
@@ -3677,13 +3848,14 @@
private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
private static CallbackHandler sCallbackHandler;
- private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
- int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
+ private NetworkRequest sendRequestForNetwork(int asUid, NetworkCapabilities need,
+ NetworkCallback callback, int timeoutMs, NetworkRequest.Type reqType, int legacyType,
+ CallbackHandler handler) {
printStackTrace();
checkCallbackNotNull(callback);
- Preconditions.checkArgument(
- reqType == TRACK_DEFAULT || reqType == TRACK_SYSTEM_DEFAULT || need != null,
- "null NetworkCapabilities");
+ if (reqType != TRACK_DEFAULT && reqType != TRACK_SYSTEM_DEFAULT && need == null) {
+ throw new IllegalArgumentException("null NetworkCapabilities");
+ }
final NetworkRequest request;
final String callingPackageName = mContext.getOpPackageName();
try {
@@ -3703,8 +3875,8 @@
getAttributionTag());
} else {
request = mService.requestNetwork(
- need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
- callbackFlags, callingPackageName, getAttributionTag());
+ asUid, need, reqType.ordinal(), messenger, timeoutMs, binder,
+ legacyType, callbackFlags, callingPackageName, getAttributionTag());
}
if (request != null) {
sCallbacks.put(request, callback);
@@ -3719,6 +3891,12 @@
return request;
}
+ private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
+ int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
+ return sendRequestForNetwork(Process.INVALID_UID, need, callback, timeoutMs, reqType,
+ legacyType, handler);
+ }
+
/**
* Helper function to request a network with a particular legacy type.
*
@@ -4030,15 +4208,17 @@
}
private static void checkPendingIntentNotNull(PendingIntent intent) {
- Preconditions.checkNotNull(intent, "PendingIntent cannot be null.");
+ Objects.requireNonNull(intent, "PendingIntent cannot be null.");
}
private static void checkCallbackNotNull(NetworkCallback callback) {
- Preconditions.checkNotNull(callback, "null NetworkCallback");
+ Objects.requireNonNull(callback, "null NetworkCallback");
}
private static void checkTimeout(int timeoutMs) {
- Preconditions.checkArgumentPositive(timeoutMs, "timeoutMs must be strictly positive.");
+ if (timeoutMs <= 0) {
+ throw new IllegalArgumentException("timeoutMs must be strictly positive.");
+ }
}
/**
@@ -4202,8 +4382,40 @@
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
@NonNull Handler handler) {
+ registerDefaultNetworkCallbackAsUid(Process.INVALID_UID, networkCallback, handler);
+ }
+
+ /**
+ * Registers to receive notifications about changes in the default network for the specified
+ * UID. This may be a physical network or a virtual network, such as a VPN that applies to the
+ * UID. The callbacks will continue to be called until either the application exits or
+ * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
+ *
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ * @param uid the UID for which to track default network changes.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as the
+ * UID's default network changes.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @SuppressLint({"ExecutorRegistration", "PairedRegistration"})
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ public void registerDefaultNetworkCallbackAsUid(int uid,
+ @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
CallbackHandler cbHandler = new CallbackHandler(handler);
- sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
+ sendRequestForNetwork(uid, null /* need */, networkCallback, 0 /* timeoutMs */,
TRACK_DEFAULT, TYPE_NONE, cbHandler);
}
@@ -4249,15 +4461,33 @@
}
/**
- * @hide
+ * Registers to receive notifications about the best matching network which satisfy the given
+ * {@link NetworkRequest}. The callbacks will continue to be called until
+ * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
+ * called.
+ *
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * {@link #registerNetworkCallback} and its variants and {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
+ * networks change state.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws RuntimeException if the app already has too many callbacks registered.
*/
- // TODO: Make it public api.
@SuppressLint("ExecutorRegistration")
public void registerBestMatchingNetworkCallback(@NonNull NetworkRequest request,
@NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
final NetworkCapabilities nc = request.networkCapabilities;
final CallbackHandler cbHandler = new CallbackHandler(handler);
- sendRequestForNetwork(nc, networkCallback, 0, TRACK_BEST, TYPE_NONE, cbHandler);
+ sendRequestForNetwork(nc, networkCallback, 0, LISTEN_FOR_BEST, TYPE_NONE, cbHandler);
}
/**
@@ -4300,8 +4530,9 @@
// Find all requests associated to this callback and stop callback triggers immediately.
// Callback is reusable immediately. http://b/20701525, http://b/35921499.
synchronized (sCallbacks) {
- Preconditions.checkArgument(networkCallback.networkRequest != null,
- "NetworkCallback was not registered");
+ if (networkCallback.networkRequest == null) {
+ throw new IllegalArgumentException("NetworkCallback was not registered");
+ }
if (networkCallback.networkRequest == ALREADY_UNREGISTERED) {
Log.d(TAG, "NetworkCallback was already unregistered");
return;
@@ -4352,8 +4583,13 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+ public void setAcceptUnvalidated(@NonNull Network network, boolean accept, boolean always) {
try {
mService.setAcceptUnvalidated(network, accept, always);
} catch (RemoteException e) {
@@ -4375,8 +4611,14 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) {
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+ public void setAcceptPartialConnectivity(@NonNull Network network, boolean accept,
+ boolean always) {
try {
mService.setAcceptPartialConnectivity(network, accept, always);
} catch (RemoteException e) {
@@ -4394,8 +4636,13 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void setAvoidUnvalidated(Network network) {
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
+ public void setAvoidUnvalidated(@NonNull Network network) {
try {
mService.setAvoidUnvalidated(network);
} catch (RemoteException e) {
@@ -4406,12 +4653,20 @@
/**
* Requests that the system open the captive portal app on the specified network.
*
+ * <p>This is to be used on networks where a captive portal was detected, as per
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
+ *
* @param network The network to log into.
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void startCaptivePortalApp(Network network) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public void startCaptivePortalApp(@NonNull Network network) {
try {
mService.startCaptivePortalApp(network);
} catch (RemoteException e) {
@@ -4525,7 +4780,10 @@
* Resets all connectivity manager settings back to factory defaults.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
public void factoryReset() {
try {
mService.factoryReset();
@@ -4603,7 +4861,7 @@
Log.e(TAG, "Can't set proxy properties", e);
}
// Must flush DNS cache as new network may have different DNS resolutions.
- InetAddress.clearDnsCache();
+ InetAddressCompat.clearDnsCache();
// Must flush socket pool as idle sockets will be bound to previous network and may
// cause subsequent fetches to be performed on old network.
NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
@@ -4728,17 +4986,6 @@
public @interface RestrictBackgroundStatus {
}
- private INetworkPolicyManager getNetworkPolicyManager() {
- synchronized (this) {
- if (mNPManager != null) {
- return mNPManager;
- }
- mNPManager = INetworkPolicyManager.Stub.asInterface(ServiceManager
- .getService(Context.NETWORK_POLICY_SERVICE));
- return mNPManager;
- }
- }
-
/**
* Determines if the calling application is subject to metered network restrictions while
* running on background.
@@ -4749,7 +4996,7 @@
*/
public @RestrictBackgroundStatus int getRestrictBackgroundStatus() {
try {
- return getNetworkPolicyManager().getRestrictBackgroundByCaller();
+ return mService.getRestrictBackgroundStatusByCaller();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4879,20 +5126,20 @@
* {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}.
*
* @param socketInfo the socket information used to match QoS events
- * @param callback receives qos events that satisfy socketInfo
* @param executor The executor on which the callback will be invoked. The provided
* {@link Executor} must run callback sequentially, otherwise the order of
- * callbacks cannot be guaranteed.
+ * callbacks cannot be guaranteed.onQosCallbackRegistered
+ * @param callback receives qos events that satisfy socketInfo
*
* @hide
*/
@SystemApi
public void registerQosCallback(@NonNull final QosSocketInfo socketInfo,
- @NonNull final QosCallback callback,
- @CallbackExecutor @NonNull final Executor executor) {
+ @CallbackExecutor @NonNull final Executor executor,
+ @NonNull final QosCallback callback) {
Objects.requireNonNull(socketInfo, "socketInfo must be non-null");
- Objects.requireNonNull(callback, "callback must be non-null");
Objects.requireNonNull(executor, "executor must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
try {
synchronized (mQosCallbackConnections) {
@@ -5057,19 +5304,6 @@
}
/**
- * Listener for {@link #setOemNetworkPreference(OemNetworkPreferences, Executor,
- * OnSetOemNetworkPreferenceListener)}.
- * @hide
- */
- @SystemApi
- public interface OnSetOemNetworkPreferenceListener {
- /**
- * Called when setOemNetworkPreference() successfully completes.
- */
- void onComplete();
- }
-
- /**
* Used by automotive devices to set the network preferences used to direct traffic at an
* application level as per the given OemNetworkPreferences. An example use-case would be an
* automotive OEM wanting to provide connectivity for applications critical to the usage of a
@@ -5091,16 +5325,16 @@
@RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE)
public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference,
@Nullable @CallbackExecutor final Executor executor,
- @Nullable final OnSetOemNetworkPreferenceListener listener) {
+ @Nullable final Runnable listener) {
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
if (null != listener) {
Objects.requireNonNull(executor, "Executor must be non-null");
}
- final IOnSetOemNetworkPreferenceListener listenerInternal = listener == null ? null :
- new IOnSetOemNetworkPreferenceListener.Stub() {
+ final IOnCompleteListener listenerInternal = listener == null ? null :
+ new IOnCompleteListener.Stub() {
@Override
public void onComplete() {
- executor.execute(listener::onComplete);
+ executor.execute(listener::run);
}
};
@@ -5112,10 +5346,56 @@
}
}
+ /**
+ * Request that a user profile is put by default on a network matching a given preference.
+ *
+ * See the documentation for the individual preferences for a description of the supported
+ * behaviors.
+ *
+ * @param profile the profile concerned.
+ * @param preference the preference for this profile.
+ * @param executor an executor to execute the listener on. Optional if listener is null.
+ * @param listener an optional listener to listen for completion of the operation.
+ * @throws IllegalArgumentException if {@code profile} is not a valid user profile.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @hide
+ */
+ // This function is for establishing per-profile default networking and can only be called by
+ // the device policy manager, running as the system server. It would make no sense to call it
+ // on a context for a user because it does not establish a setting on behalf of a user, rather
+ // it establishes a setting for a user on behalf of the DPM.
+ @SuppressLint({"UserHandle"})
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+ public void setProfileNetworkPreference(@NonNull final UserHandle profile,
+ @ProfileNetworkPreference final int preference,
+ @Nullable @CallbackExecutor final Executor executor,
+ @Nullable final Runnable listener) {
+ if (null != listener) {
+ Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+ }
+ final IOnCompleteListener proxy;
+ if (null == listener) {
+ proxy = null;
+ } else {
+ proxy = new IOnCompleteListener.Stub() {
+ @Override
+ public void onComplete() {
+ executor.execute(listener::run);
+ }
+ };
+ }
+ try {
+ mService.setProfileNetworkPreference(profile, preference, proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
// The first network ID of IPSec tunnel interface.
- private static final int TUN_INTF_NETID_START = 0xFC00;
+ private static final int TUN_INTF_NETID_START = 0xFC00; // 0xFC00 = 64512
// The network ID range of IPSec tunnel interface.
- private static final int TUN_INTF_NETID_RANGE = 0x0400;
+ private static final int TUN_INTF_NETID_RANGE = 0x0400; // 0x0400 = 1024
/**
* Get the network ID range reserved for IPSec tunnel interfaces.
@@ -5128,4 +5408,44 @@
public static Range<Integer> getIpSecNetIdRange() {
return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1);
}
+
+ /**
+ * Get private DNS mode from settings.
+ *
+ * @param context The Context to query the private DNS mode from settings.
+ * @return A string of private DNS mode as one of the PRIVATE_DNS_MODE_* constants.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @NonNull
+ @PrivateDnsMode
+ public static String getPrivateDnsMode(@NonNull Context context) {
+ final ContentResolver cr = context.getContentResolver();
+ String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE);
+ if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE);
+ // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose
+ // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode.
+ if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ return mode;
+ }
+
+ /**
+ * Set private DNS mode to settings.
+ *
+ * @param context The {@link Context} to set the private DNS mode.
+ * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static void setPrivateDnsMode(@NonNull Context context,
+ @NonNull @PrivateDnsMode String mode) {
+ if (!(mode == PRIVATE_DNS_MODE_OFF
+ || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+ || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode);
+ }
}
diff --git a/framework/src/android/net/ConnectivityResources.java b/framework/src/android/net/ConnectivityResources.java
new file mode 100644
index 0000000..18f0de0
--- /dev/null
+++ b/framework/src/android/net/ConnectivityResources.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+
+/**
+ * Utility to obtain the {@link com.android.server.ConnectivityService} {@link Resources}, in the
+ * ServiceConnectivityResources APK.
+ * @hide
+ */
+public class ConnectivityResources {
+ private static final String RESOURCES_APK_INTENT =
+ "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK";
+ private static final String RES_PKG_DIR = "/apex/com.android.tethering/";
+
+ @NonNull
+ private final Context mContext;
+
+ @Nullable
+ private Context mResourcesContext = null;
+
+ @Nullable
+ private static Context sTestResourcesContext = null;
+
+ public ConnectivityResources(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Convenience method to mock all resources for the duration of a test.
+ *
+ * Call with a null context to reset after the test.
+ */
+ @VisibleForTesting
+ public static void setResourcesContextForTest(@Nullable Context testContext) {
+ sTestResourcesContext = testContext;
+ }
+
+ /**
+ * Get the {@link Context} of the resources package.
+ */
+ public synchronized Context getResourcesContext() {
+ if (sTestResourcesContext != null) {
+ return sTestResourcesContext;
+ }
+
+ if (mResourcesContext != null) {
+ return mResourcesContext;
+ }
+
+ final List<ResolveInfo> pkgs = mContext.getPackageManager()
+ .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY);
+ pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(RES_PKG_DIR));
+ if (pkgs.size() > 1) {
+ Log.wtf(ConnectivityResources.class.getSimpleName(),
+ "More than one package found: " + pkgs);
+ }
+ if (pkgs.isEmpty()) {
+ throw new IllegalStateException("No connectivity resource package found");
+ }
+
+ final Context pkgContext;
+ try {
+ pkgContext = mContext.createPackageContext(
+ pkgs.get(0).activityInfo.applicationInfo.packageName, 0 /* flags */);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException("Resolved package not found", e);
+ }
+
+ mResourcesContext = pkgContext;
+ return pkgContext;
+ }
+
+ /**
+ * Get the {@link Resources} of the ServiceConnectivityResources APK.
+ */
+ public Resources get() {
+ return getResourcesContext().getResources();
+ }
+}
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
new file mode 100644
index 0000000..9a00055
--- /dev/null
+++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -0,0 +1,929 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.net.ConnectivityManager.MultipathPreference;
+import android.net.ConnectivityManager.PrivateDnsMode;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Range;
+
+import com.android.net.module.util.ProxyUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * A manager class for connectivity module settings.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public class ConnectivitySettingsManager {
+
+ private ConnectivitySettingsManager() {}
+
+ /** Data activity timeout settings */
+
+ /**
+ * Inactivity timeout to track mobile data activity.
+ *
+ * If set to a positive integer, it indicates the inactivity timeout value in seconds to
+ * infer the data activity of mobile network. After a period of no activity on mobile
+ * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
+ * intent is fired to indicate a transition of network status from "active" to "idle". Any
+ * subsequent activity on mobile networks triggers the firing of {@code
+ * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
+ *
+ * Network activity refers to transmitting or receiving data on the network interfaces.
+ *
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * @hide
+ */
+ public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
+
+ /**
+ * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
+ * but for Wifi network.
+ *
+ * @hide
+ */
+ public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
+
+ /** Dns resolver settings */
+
+ /**
+ * Sample validity in seconds to configure for the system DNS resolver.
+ *
+ * @hide
+ */
+ public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
+ "dns_resolver_sample_validity_seconds";
+
+ /**
+ * Success threshold in percent for use with the system DNS resolver.
+ *
+ * @hide
+ */
+ public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
+ "dns_resolver_success_threshold_percent";
+
+ /**
+ * Minimum number of samples needed for statistics to be considered meaningful in the
+ * system DNS resolver.
+ *
+ * @hide
+ */
+ public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
+
+ /**
+ * Maximum number taken into account for statistics purposes in the system DNS resolver.
+ *
+ * @hide
+ */
+ public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
+
+ private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
+ private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
+
+ /** Network switch notification settings */
+
+ /**
+ * The maximum number of notifications shown in 24 hours when switching networks.
+ *
+ * @hide
+ */
+ public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
+ "network_switch_notification_daily_limit";
+
+ /**
+ * The minimum time in milliseconds between notifications when switching networks.
+ *
+ * @hide
+ */
+ public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
+ "network_switch_notification_rate_limit_millis";
+
+ /** Captive portal settings */
+
+ /**
+ * The URL used for HTTP captive portal detection upon a new connection.
+ * A 204 response code from the server is used for validation.
+ *
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
+
+ /**
+ * What to do when connecting a network that presents a captive portal.
+ * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
+ *
+ * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
+ *
+ * @hide
+ */
+ public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
+
+ /**
+ * Don't attempt to detect captive portals.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
+
+ /**
+ * When detecting a captive portal, display a notification that
+ * prompts the user to sign in.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
+
+ /**
+ * When detecting a captive portal, immediately disconnect from the
+ * network and do not reconnect to that network in the future.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ CAPTIVE_PORTAL_MODE_IGNORE,
+ CAPTIVE_PORTAL_MODE_PROMPT,
+ CAPTIVE_PORTAL_MODE_AVOID,
+ })
+ public @interface CaptivePortalMode {}
+
+ /** Global http proxy settings */
+
+ /**
+ * Host name for global http proxy. Set via ConnectivityManager.
+ *
+ * @hide
+ */
+ public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
+
+ /**
+ * Integer host port for global http proxy. Set via ConnectivityManager.
+ *
+ * @hide
+ */
+ public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
+
+ /**
+ * Exclusion list for global proxy. This string contains a list of
+ * comma-separated domains where the global proxy does not apply.
+ * Domains should be listed in a comma- separated list. Example of
+ * acceptable formats: ".domain1.com,my.domain2.com" Use
+ * ConnectivityManager to set/get.
+ *
+ * @hide
+ */
+ public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
+ "global_http_proxy_exclusion_list";
+
+ /**
+ * The location PAC File for the proxy.
+ *
+ * @hide
+ */
+ public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
+
+ /** Private dns settings */
+
+ /**
+ * The requested Private DNS mode (string), and an accompanying specifier (string).
+ *
+ * Currently, the specifier holds the chosen provider name when the mode requests
+ * a specific provider. It may be used to store the provider name even when the
+ * mode changes so that temporarily disabling and re-enabling the specific
+ * provider mode does not necessitate retyping the provider hostname.
+ *
+ * @hide
+ */
+ public static final String PRIVATE_DNS_MODE = "private_dns_mode";
+
+ /**
+ * The specific Private DNS provider name.
+ *
+ * @hide
+ */
+ public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
+
+ /**
+ * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
+ * This allows changing the default mode without effectively disabling other modes,
+ * all of which require explicit user action to enable/configure. See also b/79719289.
+ *
+ * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
+ *
+ * @hide
+ */
+ public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
+
+ /** Other settings */
+
+ /**
+ * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
+ * the receivers of the PendingIntent an opportunity to make a new network request before
+ * the Network satisfying the request is potentially removed.
+ *
+ * @hide
+ */
+ public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
+ "connectivity_release_pending_intent_delay_ms";
+
+ /**
+ * Whether the mobile data connection should remain active even when higher
+ * priority networks like WiFi are active, to help make network switching faster.
+ *
+ * See ConnectivityService for more info.
+ *
+ * (0 = disabled, 1 = enabled)
+ *
+ * @hide
+ */
+ public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
+
+ /**
+ * Whether the wifi data connection should remain active even when higher
+ * priority networks like Ethernet are active, to keep both networks.
+ * In the case where higher priority networks are connected, wifi will be
+ * unused unless an application explicitly requests to use it.
+ *
+ * See ConnectivityService for more info.
+ *
+ * (0 = disabled, 1 = enabled)
+ *
+ * @hide
+ */
+ public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
+
+ /**
+ * Whether to automatically switch away from wifi networks that lose Internet access.
+ * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
+ * avoids such networks. Valid values are:
+ *
+ * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+ * null: Ask the user whether to switch away from bad wifi.
+ * 1: Avoid bad wifi.
+ *
+ * @hide
+ */
+ public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
+
+ /**
+ * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
+
+ /**
+ * Ask the user whether to switch away from bad wifi.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
+
+ /**
+ * Avoid bad wifi.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ NETWORK_AVOID_BAD_WIFI_IGNORE,
+ NETWORK_AVOID_BAD_WIFI_PROMPT,
+ NETWORK_AVOID_BAD_WIFI_AVOID,
+ })
+ public @interface NetworkAvoidBadWifi {}
+
+ /**
+ * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
+ * overridden by the system based on device or application state. If null, the value
+ * specified by config_networkMeteredMultipathPreference is used.
+ *
+ * @hide
+ */
+ public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
+ "network_metered_multipath_preference";
+
+ /**
+ * A list of apps that should go on cellular networks in preference even when higher-priority
+ * networks are connected.
+ *
+ * @hide
+ */
+ public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps";
+
+ /**
+ * Get mobile data activity timeout from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default timeout if no setting value.
+ * @return The {@link Duration} of timeout to track mobile data activity.
+ */
+ @NonNull
+ public static Duration getMobileDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration def) {
+ final int timeout = Settings.Global.getInt(
+ context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
+ return Duration.ofSeconds(timeout);
+ }
+
+ /**
+ * Set mobile data activity timeout to {@link Settings}.
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
+ * ignored.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param timeout The mobile data activity timeout.
+ */
+ public static void setMobileDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration timeout) {
+ Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
+ (int) timeout.getSeconds());
+ }
+
+ /**
+ * Get wifi data activity timeout from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default timeout if no setting value.
+ * @return The {@link Duration} of timeout to track wifi data activity.
+ */
+ @NonNull
+ public static Duration getWifiDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration def) {
+ final int timeout = Settings.Global.getInt(
+ context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
+ return Duration.ofSeconds(timeout);
+ }
+
+ /**
+ * Set wifi data activity timeout to {@link Settings}.
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
+ * ignored.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param timeout The wifi data activity timeout.
+ */
+ public static void setWifiDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration timeout) {
+ Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
+ (int) timeout.getSeconds());
+ }
+
+ /**
+ * Get dns resolver sample validity duration from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default duration if no setting value.
+ * @return The {@link Duration} of sample validity duration to configure for the system DNS
+ * resolver.
+ */
+ @NonNull
+ public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
+ return Duration.ofSeconds(duration);
+ }
+
+ /**
+ * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
+ * positive number of seconds.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The sample validity duration.
+ */
+ public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.getSeconds();
+ if (time <= 0) {
+ throw new IllegalArgumentException("Invalid duration");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
+ }
+
+ /**
+ * Get dns resolver success threshold percent from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return The success threshold in percent for use with the system DNS resolver.
+ */
+ public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
+ return Settings.Global.getInt(
+ context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
+ }
+
+ /**
+ * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
+ * be 0~100.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param percent The success threshold percent.
+ */
+ public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
+ @IntRange(from = 0, to = 100) int percent) {
+ if (percent < 0 || percent > 100) {
+ throw new IllegalArgumentException("Percent must be 0~100");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
+ }
+
+ /**
+ * Get dns resolver samples range from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The {@link Range<Integer>} of samples needed for statistics to be considered
+ * meaningful in the system DNS resolver.
+ */
+ @NonNull
+ public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
+ final int minSamples = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
+ final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
+ return new Range<>(minSamples, maxSamples);
+ }
+
+ /**
+ * Set dns resolver samples range to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param range The samples range. The minimum number should be more than 0 and the maximum
+ * number should be less that 64.
+ */
+ public static void setDnsResolverSampleRanges(@NonNull Context context,
+ @NonNull Range<Integer> range) {
+ if (range.getLower() < 0 || range.getUpper() > 64) {
+ throw new IllegalArgumentException("Argument must be 0~64");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
+ }
+
+ /**
+ * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
+ * hours.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return The maximum count of notifications shown in 24 hours when switching networks.
+ */
+ public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
+ int def) {
+ return Settings.Global.getInt(
+ context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
+ }
+
+ /**
+ * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
+ * The count must be at least 0.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param count The maximum count of switching network notifications shown in 24 hours.
+ */
+ public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
+ @IntRange(from = 0) int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException("Count must be 0~10.");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
+ }
+
+ /**
+ * Get minimum duration (from {@link Settings}) between each switching network notifications.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default time if no setting value.
+ * @return The minimum duration between notifications when switching networks.
+ */
+ @NonNull
+ public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Global.getInt(context.getContentResolver(),
+ NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
+ return Duration.ofMillis(duration);
+ }
+
+ /**
+ * Set minimum duration (to {@link Settings}) between each switching network notifications.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The minimum duration between notifications when switching networks.
+ */
+ public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.toMillis();
+ if (time < 0) {
+ throw new IllegalArgumentException("Invalid duration.");
+ }
+ Settings.Global.putInt(context.getContentResolver(),
+ NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
+ }
+
+ /**
+ * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The URL used for HTTP captive portal detection upon a new connection.
+ */
+ @Nullable
+ public static String getCaptivePortalHttpUrl(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
+ }
+
+ /**
+ * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
+ * This URL should respond with a 204 response to a GET request to indicate no captive portal is
+ * present. And this URL must be HTTP as redirect responses are used to find captive portal
+ * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal
+ * detection failed and lost the connection.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param url The URL used for HTTP captive portal detection upon a new connection.
+ */
+ public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
+ Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
+ }
+
+ /**
+ * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default mode if no setting value.
+ * @return The mode when connecting a network that presents a captive portal.
+ */
+ @CaptivePortalMode
+ public static int getCaptivePortalMode(@NonNull Context context,
+ @CaptivePortalMode int def) {
+ return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
+ }
+
+ /**
+ * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param mode The mode when connecting a network that presents a captive portal.
+ */
+ public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
+ if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
+ || mode == CAPTIVE_PORTAL_MODE_PROMPT
+ || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
+ throw new IllegalArgumentException("Invalid captive portal mode");
+ }
+ Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
+ }
+
+ /**
+ * Get the global HTTP proxy applied to the device, or null if none.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The {@link ProxyInfo} which build from global http proxy settings.
+ */
+ @Nullable
+ public static ProxyInfo getGlobalProxy(@NonNull Context context) {
+ final String host = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
+ final int port = Settings.Global.getInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
+ final String exclusionList = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ final String pacFileUrl = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
+
+ if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
+ return null; // No global proxy.
+ }
+
+ if (TextUtils.isEmpty(pacFileUrl)) {
+ return ProxyInfo.buildDirectProxy(
+ host, port, ProxyUtils.exclusionStringAsList(exclusionList));
+ } else {
+ return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
+ }
+ }
+
+ /**
+ * Set global http proxy settings from given {@link ProxyInfo}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
+ * {@link ProxyInfo#buildPacProxy(Uri)} or
+ * {@link ProxyInfo#buildDirectProxy(String, int, List)}
+ */
+ public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
+ final String host = proxyInfo.getHost();
+ final int port = proxyInfo.getPort();
+ final String exclusionList = proxyInfo.getExclusionListAsString();
+ final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
+
+ if (TextUtils.isEmpty(pacFileUrl)) {
+ Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
+ } else {
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
+ Settings.Global.putInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
+ }
+ }
+
+ /**
+ * Clear all global http proxy settings.
+ *
+ * @param context The {@link Context} to set the setting.
+ */
+ public static void clearGlobalProxy(@NonNull Context context) {
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
+ Settings.Global.putInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
+ }
+
+ /**
+ * Get specific private dns provider name from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The specific private dns provider name, or null if no setting value.
+ */
+ @Nullable
+ public static String getPrivateDnsHostname(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER);
+ }
+
+ /**
+ * Set specific private dns provider name to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param specifier The specific private dns provider name.
+ */
+ public static void setPrivateDnsHostname(@NonNull Context context,
+ @Nullable String specifier) {
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier);
+ }
+
+ /**
+ * Get default private dns mode from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The default private dns mode.
+ */
+ @PrivateDnsMode
+ @NonNull
+ public static String getPrivateDnsDefaultMode(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
+ }
+
+ /**
+ * Set default private dns mode to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
+ * constants.
+ */
+ public static void setPrivateDnsDefaultMode(@NonNull Context context,
+ @NonNull @PrivateDnsMode String mode) {
+ if (!(mode == PRIVATE_DNS_MODE_OFF
+ || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+ || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode);
+ }
+
+ /**
+ * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default duration if no setting value.
+ * @return The duration to keep a PendingIntent-based request.
+ */
+ @NonNull
+ public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Secure.getInt(context.getContentResolver(),
+ CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
+ return Duration.ofMillis(duration);
+ }
+
+ /**
+ * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The duration to keep a PendingIntent-based request.
+ */
+ public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.toMillis();
+ if (time < 0) {
+ throw new IllegalArgumentException("Invalid duration.");
+ }
+ Settings.Secure.putInt(
+ context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
+ }
+
+ /**
+ * Read from {@link Settings} whether the mobile data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return Whether the mobile data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
+ final int enable = Settings.Global.getInt(
+ context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
+ return (enable != 0) ? true : false;
+ }
+
+ /**
+ * Write into {@link Settings} whether the mobile data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param enable Whether the mobile data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
+ Settings.Global.putInt(
+ context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
+ }
+
+ /**
+ * Read from {@link Settings} whether the wifi data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return Whether the wifi data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
+ final int enable = Settings.Global.getInt(
+ context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
+ return (enable != 0) ? true : false;
+ }
+
+ /**
+ * Write into {@link Settings} whether the wifi data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param enable Whether the wifi data connection should remain active even when higher
+ * priority networks are active
+ */
+ public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
+ Settings.Global.putInt(
+ context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
+ }
+
+ /**
+ * Get avoid bad wifi setting from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The setting whether to automatically switch away from wifi networks that lose
+ * internet access.
+ */
+ @NetworkAvoidBadWifi
+ public static int getNetworkAvoidBadWifi(@NonNull Context context) {
+ final String setting =
+ Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
+ if ("0".equals(setting)) {
+ return NETWORK_AVOID_BAD_WIFI_IGNORE;
+ } else if ("1".equals(setting)) {
+ return NETWORK_AVOID_BAD_WIFI_AVOID;
+ } else {
+ return NETWORK_AVOID_BAD_WIFI_PROMPT;
+ }
+ }
+
+ /**
+ * Set avoid bad wifi setting to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param value Whether to automatically switch away from wifi networks that lose internet
+ * access.
+ */
+ public static void setNetworkAvoidBadWifi(@NonNull Context context,
+ @NetworkAvoidBadWifi int value) {
+ final String setting;
+ if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
+ setting = "0";
+ } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
+ setting = "1";
+ } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
+ setting = null;
+ } else {
+ throw new IllegalArgumentException("Invalid avoid bad wifi setting");
+ }
+ Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
+ }
+
+ /**
+ * Get network metered multipath preference from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The network metered multipath preference which should be one of
+ * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
+ * by config_networkMeteredMultipathPreference is used.
+ */
+ @Nullable
+ public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
+ return Settings.Global.getString(
+ context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
+ }
+
+ /**
+ * Set network metered multipath preference to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param preference The network metered multipath preference which should be one of
+ * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
+ * specified by config_networkMeteredMultipathPreference is used.
+ */
+ public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
+ @NonNull @MultipathPreference String preference) {
+ if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
+ || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
+ || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(
+ context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
+ }
+
+ /**
+ * Get the list of apps(from {@link Settings}) that should go on cellular networks in preference
+ * even when higher-priority networks are connected.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return A list of apps that should go on cellular networks in preference even when
+ * higher-priority networks are connected or null if no setting value.
+ */
+ @Nullable
+ public static String getMobileDataPreferredApps(@NonNull Context context) {
+ return Settings.Secure.getString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS);
+ }
+
+ /**
+ * Set the list of apps(to {@link Settings}) that should go on cellular networks in preference
+ * even when higher-priority networks are connected.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param list A list of apps that should go on cellular networks in preference even when
+ * higher-priority networks are connected.
+ */
+ public static void setMobileDataPreferredApps(@NonNull Context context, @Nullable String list) {
+ Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS, list);
+ }
+}
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index f9393e3..0826922 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -20,7 +20,8 @@
import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
-import android.net.IOnSetOemNetworkPreferenceListener;
+import android.net.INetworkAgent;
+import android.net.IOnCompleteListener;
import android.net.INetworkActivityListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
@@ -30,6 +31,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkState;
import android.net.NetworkStateSnapshot;
import android.net.OemNetworkPreferences;
@@ -42,8 +44,7 @@
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.ResultReceiver;
-
-import com.android.connectivity.aidl.INetworkAgent;
+import android.os.UserHandle;
/**
* Interface that answers queries about, and allows changing, the
@@ -138,10 +139,10 @@
void declareNetworkRequestUnfulfillable(in NetworkRequest request);
Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
+ in NetworkCapabilities nc, in NetworkScore score, in NetworkAgentConfig config,
in int factorySerialNumber);
- NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
+ NetworkRequest requestNetwork(int uid, in NetworkCapabilities networkCapabilities, int reqType,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
int callbackFlags, String callingPackageName, String callingAttributionTag);
@@ -214,5 +215,10 @@
void unregisterQosCallback(in IQosCallback callback);
void setOemNetworkPreference(in OemNetworkPreferences preference,
- in IOnSetOemNetworkPreferenceListener listener);
+ in IOnCompleteListener listener);
+
+ void setProfileNetworkPreference(in UserHandle profile, int preference,
+ in IOnCompleteListener listener);
+
+ int getRestrictBackgroundStatusByCaller();
}
diff --git a/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/framework/src/android/net/INetworkAgent.aidl
similarity index 93%
rename from framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
rename to framework/src/android/net/INetworkAgent.aidl
index 64b5567..f9d3994 100644
--- a/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl
+++ b/framework/src/android/net/INetworkAgent.aidl
@@ -13,13 +13,13 @@
* See the License for the specific language governing perNmissions and
* limitations under the License.
*/
-package com.android.connectivity.aidl;
+package android.net;
import android.net.NattKeepalivePacketData;
import android.net.QosFilterParcelable;
import android.net.TcpKeepalivePacketData;
-import com.android.connectivity.aidl.INetworkAgentRegistry;
+import android.net.INetworkAgentRegistry;
/**
* Interface to notify NetworkAgent of connectivity events.
@@ -46,4 +46,6 @@
void onRemoveKeepalivePacketFilter(int slot);
void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel);
void onQosCallbackUnregistered(int qosCallbackId);
+ void onNetworkCreated();
+ void onNetworkDisconnected();
}
diff --git a/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/framework/src/android/net/INetworkAgentRegistry.aidl
similarity index 83%
rename from framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
rename to framework/src/android/net/INetworkAgentRegistry.aidl
index f0193db..cbd6193 100644
--- a/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl
+++ b/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -13,17 +13,19 @@
* See the License for the specific language governing perNmissions and
* limitations under the License.
*/
-package com.android.connectivity.aidl;
+package android.net;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
+import android.net.NetworkScore;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
/**
- * Interface for NetworkAgents to send network network properties.
+ * Interface for NetworkAgents to send network properties.
* @hide
*/
oneway interface INetworkAgentRegistry {
@@ -31,11 +33,12 @@
void sendLinkProperties(in LinkProperties lp);
// TODO: consider replacing this by "markConnected()" and removing
void sendNetworkInfo(in NetworkInfo info);
- void sendScore(int score);
+ void sendScore(in NetworkScore score);
void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial);
void sendSocketKeepaliveEvent(int slot, int reason);
void sendUnderlyingNetworks(in @nullable List<Network> networks);
void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes);
+ void sendNrQosSessionAvailable(int callbackId, in QosSession session, in NrQosSessionAttributes attributes);
void sendQosSessionLost(int qosCallbackId, in QosSession session);
void sendQosCallbackError(int qosCallbackId, int exceptionType);
}
diff --git a/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/framework/src/android/net/IOnCompleteListener.aidl
similarity index 92%
rename from framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
rename to framework/src/android/net/IOnCompleteListener.aidl
index 7979afc..4bb89f6 100644
--- a/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/framework/src/android/net/IOnCompleteListener.aidl
@@ -18,6 +18,6 @@
package android.net;
/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
+oneway interface IOnCompleteListener {
void onComplete();
}
diff --git a/framework/src/android/net/IQosCallback.aidl b/framework/src/android/net/IQosCallback.aidl
index 91c7575..c973541 100644
--- a/framework/src/android/net/IQosCallback.aidl
+++ b/framework/src/android/net/IQosCallback.aidl
@@ -19,6 +19,7 @@
import android.os.Bundle;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
/**
* AIDL interface for QosCallback
@@ -29,6 +30,8 @@
{
void onQosEpsBearerSessionAvailable(in QosSession session,
in EpsBearerQosSessionAttributes attributes);
+ void onNrQosSessionAvailable(in QosSession session,
+ in NrQosSessionAttributes attributes);
void onQosSessionLost(in QosSession session);
void onError(in int type);
}
diff --git a/framework/src/android/net/InetAddressCompat.java b/framework/src/android/net/InetAddressCompat.java
new file mode 100644
index 0000000..6b7e75c
--- /dev/null
+++ b/framework/src/android/net/InetAddressCompat.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Compatibility utility for InetAddress core platform APIs.
+ *
+ * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
+ * (only core_current). Most stable core platform APIs are included manually in the connectivity
+ * build rules, but because InetAddress is also part of the base java SDK that is earlier on the
+ * classpath, the extra core platform APIs are not seen.
+ *
+ * TODO (b/183097033): remove this utility as soon as core_current is part of module_current
+ * @hide
+ */
+public class InetAddressCompat {
+
+ /**
+ * @see InetAddress#clearDnsCache()
+ */
+ public static void clearDnsCache() {
+ try {
+ InetAddress.class.getMethod("clearDnsCache").invoke(null);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+ throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
+ } catch (IllegalAccessException | NoSuchMethodException e) {
+ Log.wtf(InetAddressCompat.class.getSimpleName(), "Error clearing DNS cache", e);
+ }
+ }
+
+ /**
+ * @see InetAddress#getAllByNameOnNet(String, int)
+ */
+ public static InetAddress[] getAllByNameOnNet(String host, int netId) throws
+ UnknownHostException {
+ return (InetAddress[]) callGetByNameMethod("getAllByNameOnNet", host, netId);
+ }
+
+ /**
+ * @see InetAddress#getByNameOnNet(String, int)
+ */
+ public static InetAddress getByNameOnNet(String host, int netId) throws
+ UnknownHostException {
+ return (InetAddress) callGetByNameMethod("getByNameOnNet", host, netId);
+ }
+
+ private static Object callGetByNameMethod(String method, String host, int netId)
+ throws UnknownHostException {
+ try {
+ return InetAddress.class.getMethod(method, String.class, int.class)
+ .invoke(null, host, netId);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof UnknownHostException) {
+ throw (UnknownHostException) e.getCause();
+ }
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+ throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
+ } catch (IllegalAccessException | NoSuchMethodException e) {
+ Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling " + method, e);
+ throw new IllegalStateException("Error querying via " + method, e);
+ }
+ }
+}
diff --git a/framework/src/android/net/IpPrefix.java b/framework/src/android/net/IpPrefix.java
index d2ee7d1..bf4481a 100644
--- a/framework/src/android/net/IpPrefix.java
+++ b/framework/src/android/net/IpPrefix.java
@@ -113,7 +113,7 @@
// first statement in constructor". We could factor out setting the member variables to an
// init() method, but if we did, then we'd have to make the members non-final, or "error:
// cannot assign a value to final variable address". So we just duplicate the code here.
- Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(prefix);
+ Pair<InetAddress, Integer> ipAndMask = NetworkUtils.legacyParseIpAndMask(prefix);
this.address = ipAndMask.first.getAddress();
this.prefixLength = ipAndMask.second;
checkAndMaskAddressAndPrefixLength();
diff --git a/framework/src/android/net/LinkAddress.java b/framework/src/android/net/LinkAddress.java
index d1bdaa0..d48b8c7 100644
--- a/framework/src/android/net/LinkAddress.java
+++ b/framework/src/android/net/LinkAddress.java
@@ -325,7 +325,7 @@
public LinkAddress(@NonNull String address, int flags, int scope) {
// This may throw an IllegalArgumentException; catching it is the caller's responsibility.
// TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
- Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
+ Pair<InetAddress, Integer> ipAndMask = NetworkUtils.legacyParseIpAndMask(address);
init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
}
diff --git a/framework/src/android/net/MacAddress.java b/framework/src/android/net/MacAddress.java
index c83c23a..26a504a 100644
--- a/framework/src/android/net/MacAddress.java
+++ b/framework/src/android/net/MacAddress.java
@@ -25,7 +25,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Preconditions;
import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
@@ -34,6 +33,7 @@
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Objects;
/**
* Representation of a MAC address.
@@ -229,7 +229,7 @@
* @hide
*/
public static @NonNull byte[] byteAddrFromStringAddr(String addr) {
- Preconditions.checkNotNull(addr);
+ Objects.requireNonNull(addr);
String[] parts = addr.split(":");
if (parts.length != ETHER_ADDR_LEN) {
throw new IllegalArgumentException(addr + " was not a valid MAC address");
@@ -275,7 +275,7 @@
// Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr))
// that avoids the allocation of an intermediary byte[].
private static long longAddrFromStringAddr(String addr) {
- Preconditions.checkNotNull(addr);
+ Objects.requireNonNull(addr);
String[] parts = addr.split(":");
if (parts.length != ETHER_ADDR_LEN) {
throw new IllegalArgumentException(addr + " was not a valid MAC address");
@@ -364,8 +364,8 @@
*
*/
public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
- Preconditions.checkNotNull(baseAddress);
- Preconditions.checkNotNull(mask);
+ Objects.requireNonNull(baseAddress);
+ Objects.requireNonNull(mask);
return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
}
diff --git a/framework/src/android/net/Network.java b/framework/src/android/net/Network.java
index 46141e0..0741414 100644
--- a/framework/src/android/net/Network.java
+++ b/framework/src/android/net/Network.java
@@ -30,10 +30,10 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
-import com.android.okhttp.internalandroidapi.Dns;
-import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory;
import libcore.io.IoUtils;
+import libcore.net.http.Dns;
+import libcore.net.http.HttpURLConnectionFactory;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -142,7 +142,7 @@
* @throws UnknownHostException if the address lookup fails.
*/
public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
+ return InetAddressCompat.getAllByNameOnNet(host, getNetIdForResolv());
}
/**
@@ -155,7 +155,7 @@
* if the address lookup fails.
*/
public InetAddress getByName(String host) throws UnknownHostException {
- return InetAddress.getByNameOnNet(host, getNetIdForResolv());
+ return InetAddressCompat.getByNameOnNet(host, getNetIdForResolv());
}
/**
@@ -299,7 +299,7 @@
// Set configuration on the HttpURLConnectionFactory that will be good for all
// connections created by this Network. Configuration that might vary is left
// until openConnection() and passed as arguments.
- HttpURLConnectionFactory urlConnectionFactory = new HttpURLConnectionFactory();
+ HttpURLConnectionFactory urlConnectionFactory = HttpURLConnectionFactory.createInstance();
urlConnectionFactory.setDns(dnsLookup); // Let traffic go via dnsLookup
// A private connection pool just for this Network.
urlConnectionFactory.setNewConnectionPool(httpMaxConnections,
diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java
index 27aa15d..01b88aa 100644
--- a/framework/src/android/net/NetworkAgent.java
+++ b/framework/src/android/net/NetworkAgent.java
@@ -32,12 +32,10 @@
import android.os.Message;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
-import com.android.connectivity.aidl.INetworkAgent;
-import com.android.connectivity.aidl.INetworkAgentRegistry;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Protocol;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -125,7 +123,10 @@
*/
public final int providerId;
- private static final int BASE = Protocol.BASE_NETWORK_AGENT;
+ // ConnectivityService parses message constants from itself and NetworkAgent with MessageUtils
+ // for debugging purposes, and crashes if some messages have the same values.
+ // TODO: have ConnectivityService store message names in different maps and remove this base
+ private static final int BASE = 200;
/**
* Sent by ConnectivityService to the NetworkAgent to inform it of
@@ -361,6 +362,22 @@
*/
public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
+ /**
+ * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
+ * network was created and the Network object is now valid.
+ *
+ * @hide
+ */
+ public static final int CMD_NETWORK_CREATED = BASE + 22;
+
+ /**
+ * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
+ * network was destroyed.
+ *
+ * @hide
+ */
+ public static final int CMD_NETWORK_DISCONNECTED = BASE + 23;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
// with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -371,6 +388,14 @@
return ni;
}
+ // Temporary backward compatibility constructor
+ public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
+ @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
+ this(context, looper, logTag, nc, lp,
+ new NetworkScore.Builder().setLegacyInt(score).build(), config, provider);
+ }
+
/**
* Create a new network agent.
* @param context a {@link Context} to get system services from.
@@ -384,8 +409,9 @@
* @param provider the {@link NetworkProvider} managing this agent.
*/
public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
- @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
+ @NonNull NetworkScore score, @NonNull NetworkAgentConfig config,
+ @Nullable NetworkProvider provider) {
this(looper, context, logTag, nc, lp, score, config,
provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(),
getLegacyNetworkInfo(config));
@@ -395,12 +421,12 @@
public final Context context;
public final NetworkCapabilities capabilities;
public final LinkProperties properties;
- public final int score;
+ public final NetworkScore score;
public final NetworkAgentConfig config;
public final NetworkInfo info;
InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities,
- @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config,
- @NonNull NetworkInfo info) {
+ @NonNull LinkProperties properties, @NonNull NetworkScore score,
+ @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info) {
this.context = context;
this.capabilities = capabilities;
this.properties = properties;
@@ -412,8 +438,9 @@
private volatile InitialConfiguration mInitialConfiguration;
private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
- @NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni) {
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
+ @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, int providerId,
+ @NonNull NetworkInfo ni) {
mHandler = new NetworkAgentHandler(looper);
LOG_TAG = logTag;
mNetworkInfo = new NetworkInfo(ni);
@@ -423,7 +450,7 @@
}
mInitialConfiguration = new InitialConfiguration(context,
- new NetworkCapabilities(nc, /* parcelLocationSensitiveFields */ true),
+ new NetworkCapabilities(nc, NetworkCapabilities.REDACT_NONE),
new LinkProperties(lp), score, config, ni);
}
@@ -551,6 +578,14 @@
msg.arg1 /* QoS callback id */);
break;
}
+ case CMD_NETWORK_CREATED: {
+ onNetworkCreated();
+ break;
+ }
+ case CMD_NETWORK_DISCONNECTED: {
+ onNetworkDisconnected();
+ break;
+ }
}
}
}
@@ -691,6 +726,16 @@
mHandler.sendMessage(mHandler.obtainMessage(
CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
}
+
+ @Override
+ public void onNetworkCreated() {
+ mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_CREATED));
+ }
+
+ @Override
+ public void onNetworkDisconnected() {
+ mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DISCONNECTED));
+ }
}
/**
@@ -867,21 +912,29 @@
mBandwidthUpdatePending.set(false);
mLastBwRefreshTime = System.currentTimeMillis();
final NetworkCapabilities nc =
- new NetworkCapabilities(networkCapabilities,
- /* parcelLocationSensitiveFields */ true);
+ new NetworkCapabilities(networkCapabilities, NetworkCapabilities.REDACT_NONE);
queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc));
}
/**
* Must be called by the agent to update the score of this network.
*
+ * @param score the new score.
+ * @hide TODO : unhide when impl is complete
+ */
+ public final void sendNetworkScore(@NonNull NetworkScore score) {
+ Objects.requireNonNull(score);
+ queueOrSendMessage(reg -> reg.sendScore(score));
+ }
+
+ /**
+ * Must be called by the agent to update the score of this network.
+ *
* @param score the new score, between 0 and 99.
+ * deprecated use sendNetworkScore(NetworkScore) TODO : remove in S.
*/
public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) {
- if (score < 0) {
- throw new IllegalArgumentException("Score must be >= 0");
- }
- queueOrSendMessage(reg -> reg.sendScore(score));
+ sendNetworkScore(new NetworkScore.Builder().setLegacyInt(score).build());
}
/**
@@ -991,6 +1044,17 @@
}
/**
+ * Called when ConnectivityService has successfully created this NetworkAgent's native network.
+ */
+ public void onNetworkCreated() {}
+
+
+ /**
+ * Called when ConnectivityService has successfully destroy this NetworkAgent's native network.
+ */
+ public void onNetworkDisconnected() {}
+
+ /**
* Requests that the network hardware send the specified packet at the specified interval.
*
* @param slot the hardware slot on which to start the keepalive.
@@ -1141,29 +1205,37 @@
/**
- * Sends the attributes of Eps Bearer Qos Session back to the Application
+ * Sends the attributes of Qos Session back to the Application
*
* @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Eps Bearer Qos Sessions
- * @param attributes the attributes of the Eps Qos Session
+ * @param sessionId the unique session id across all Qos Sessions
+ * @param attributes the attributes of the Qos Session
*/
public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
- @NonNull final EpsBearerQosSessionAttributes attributes) {
+ @NonNull final QosSessionAttributes attributes) {
Objects.requireNonNull(attributes, "The attributes must be non-null");
- queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
- attributes));
+ if (attributes instanceof EpsBearerQosSessionAttributes) {
+ queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
+ (EpsBearerQosSessionAttributes)attributes));
+ } else if (attributes instanceof NrQosSessionAttributes) {
+ queueOrSendMessage(ra -> ra.sendNrQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_NR_BEARER),
+ (NrQosSessionAttributes)attributes));
+ }
}
/**
- * Sends event that the Eps Qos Session was lost.
+ * Sends event that the Qos Session was lost.
*
* @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ * @param sessionId the unique session id across all Qos Sessions
+ * @param qosSessionType the session type {@code QosSesson#QosSessionType}
*/
- public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
+ public final void sendQosSessionLost(final int qosCallbackId,
+ final int sessionId, final int qosSessionType) {
queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
+ new QosSession(sessionId, qosSessionType)));
}
/**
diff --git a/framework/src/android/net/NetworkAgentConfig.java b/framework/src/android/net/NetworkAgentConfig.java
index 664c265..0bd2371 100644
--- a/framework/src/android/net/NetworkAgentConfig.java
+++ b/framework/src/android/net/NetworkAgentConfig.java
@@ -50,7 +50,8 @@
* ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to
* connect to a particular access point is also explicit, though this may change in the future
* as we want apps to use the multinetwork apis.
- *
+ * TODO : this is a bad name, because it sounds like the user just tapped on the network.
+ * It's not necessarily the case ; auto-reconnection to WiFi has this true for example.
* @hide
*/
public boolean explicitlySelected;
@@ -63,6 +64,16 @@
}
/**
+ * @return whether this VPN connection can be bypassed by the apps.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public boolean isBypassableVpn() {
+ return allowBypass;
+ }
+
+ /**
* Set if the user desires to use this network even if it is unvalidated. This field has meaning
* only if {@link explicitlySelected} is true. If it is, this field must also be set to the
* appropriate value based on previous user choice.
@@ -346,6 +357,19 @@
}
/**
+ * Sets whether the apps can bypass the VPN connection.
+ *
+ * @return this builder, to facilitate chaining.
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = MODULE_LIBRARIES)
+ public Builder setBypassableVpn(boolean allowBypass) {
+ mConfig.allowBypass = allowBypass;
+ return this;
+ }
+
+ /**
* Returns the constructed {@link NetworkAgentConfig} object.
*/
@NonNull
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 058f3c9..881fa8c 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -19,9 +19,11 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import android.annotation.IntDef;
+import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.ConnectivityManager.NetworkCallback;
@@ -32,10 +34,10 @@
import android.os.Process;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Range;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkCapabilitiesUtils;
@@ -63,6 +65,68 @@
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
+ /**
+ * Mechanism to support redaction of fields in NetworkCapabilities that are guarded by specific
+ * app permissions.
+ **/
+ /**
+ * Don't redact any fields since the receiving app holds all the necessary permissions.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_NONE = 0;
+
+ /**
+ * Redact any fields that need {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
+ * permission since the receiving app does not hold this permission or the location toggle
+ * is off.
+ *
+ * @see android.Manifest.permission#ACCESS_FINE_LOCATION
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1 << 0;
+
+ /**
+ * Redact any fields that need {@link android.Manifest.permission#LOCAL_MAC_ADDRESS}
+ * permission since the receiving app does not hold this permission.
+ *
+ * @see android.Manifest.permission#LOCAL_MAC_ADDRESS
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 1 << 1;
+
+ /**
+ *
+ * Redact any fields that need {@link android.Manifest.permission#NETWORK_SETTINGS}
+ * permission since the receiving app does not hold this permission.
+ *
+ * @see android.Manifest.permission#NETWORK_SETTINGS
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_FOR_NETWORK_SETTINGS = 1 << 2;
+
+ /**
+ * Redact all fields in this object that require any relevant permission.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final long REDACT_ALL = -1L;
+
+ /** @hide */
+ @LongDef(flag = true, prefix = { "REDACT_" }, value = {
+ REDACT_NONE,
+ REDACT_FOR_ACCESS_FINE_LOCATION,
+ REDACT_FOR_LOCAL_MAC_ADDRESS,
+ REDACT_FOR_NETWORK_SETTINGS,
+ REDACT_ALL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RedactionType {}
+
// Set to true when private DNS is broken.
private boolean mPrivateDnsBroken;
@@ -77,32 +141,31 @@
private String mRequestorPackageName;
/**
- * Indicates whether parceling should preserve fields that are set based on permissions of
- * the process receiving the {@link NetworkCapabilities}.
+ * Indicates what fields should be redacted from this instance.
*/
- private final boolean mParcelLocationSensitiveFields;
+ private final @RedactionType long mRedactions;
public NetworkCapabilities() {
- mParcelLocationSensitiveFields = false;
+ mRedactions = REDACT_ALL;
clearAll();
mNetworkCapabilities = DEFAULT_CAPABILITIES;
}
public NetworkCapabilities(NetworkCapabilities nc) {
- this(nc, false /* parcelLocationSensitiveFields */);
+ this(nc, REDACT_ALL);
}
/**
* Make a copy of NetworkCapabilities.
*
* @param nc Original NetworkCapabilities
- * @param parcelLocationSensitiveFields Whether to parcel location sensitive data or not.
+ * @param redactions bitmask of redactions that needs to be performed on this new instance of
+ * {@link NetworkCapabilities}.
* @hide
*/
- @SystemApi
- public NetworkCapabilities(
- @Nullable NetworkCapabilities nc, boolean parcelLocationSensitiveFields) {
- mParcelLocationSensitiveFields = parcelLocationSensitiveFields;
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) {
+ mRedactions = redactions;
if (nc != null) {
set(nc);
}
@@ -114,11 +177,13 @@
* @hide
*/
public void clearAll() {
- // Ensures that the internal copies maintained by the connectivity stack does not set
- // this bit.
- if (mParcelLocationSensitiveFields) {
+ // Ensures that the internal copies maintained by the connectivity stack does not set it to
+ // anything other than |REDACT_ALL|.
+ if (mRedactions != REDACT_ALL) {
+ // This is needed because the current redaction mechanism relies on redaction while
+ // parceling.
throw new UnsupportedOperationException(
- "Cannot clear NetworkCapabilities when parcelLocationSensitiveFields is set");
+ "Cannot clear NetworkCapabilities when mRedactions is set");
}
mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
@@ -148,12 +213,12 @@
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
if (nc.getTransportInfo() != null) {
- setTransportInfo(nc.getTransportInfo().makeCopy(mParcelLocationSensitiveFields));
+ setTransportInfo(nc.getTransportInfo().makeCopy(mRedactions));
} else {
setTransportInfo(null);
}
mSignalStrength = nc.mSignalStrength;
- setUids(nc.mUids); // Will make the defensive copy
+ mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids);
setAdministratorUids(nc.getAdministratorUids());
mOwnerUid = nc.mOwnerUid;
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
@@ -574,19 +639,31 @@
}
/**
- * Removes (if found) the given capability from this {@code NetworkCapability} instance.
+ * Removes (if found) the given capability from this {@code NetworkCapability}
+ * instance that were added via addCapability(int) or setCapabilities(int[], int[]).
*
* @param capability the capability to be removed.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
- // Note that this method removes capabilities that were added via addCapability(int),
- // addUnwantedCapability(int) or setCapabilities(int[], int[]).
checkValidCapability(capability);
final long mask = ~(1 << capability);
mNetworkCapabilities &= mask;
- mUnwantedNetworkCapabilities &= mask;
+ return this;
+ }
+
+ /**
+ * Removes (if found) the given unwanted capability from this {@code NetworkCapability}
+ * instance that were added via addUnwantedCapability(int) or setCapabilities(int[], int[]).
+ *
+ * @param capability the capability to be removed.
+ * @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
+ */
+ public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) {
+ checkValidCapability(capability);
+ mUnwantedNetworkCapabilities &= ~(1 << capability);
return this;
}
@@ -609,10 +686,8 @@
* Gets all the capabilities set on this {@code NetworkCapability} instance.
*
* @return an array of capability values for this instance.
- * @hide
*/
- @UnsupportedAppUsage
- public @NetCapability int[] getCapabilities() {
+ public @NonNull @NetCapability int[] getCapabilities() {
return NetworkCapabilitiesUtils.unpackBits(mNetworkCapabilities);
}
@@ -660,6 +735,7 @@
}
/** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return isValidCapability(capability)
&& ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
@@ -673,10 +749,16 @@
return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
}
- /** Note this method may result in having the same capability in wanted and unwanted lists. */
private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
- this.mNetworkCapabilities |= nc.mNetworkCapabilities;
- this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities;
+ final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities;
+ final long unwantedCaps =
+ this.mUnwantedNetworkCapabilities | nc.mUnwantedNetworkCapabilities;
+ if ((wantedCaps & unwantedCaps) != 0) {
+ throw new IllegalArgumentException(
+ "Cannot have the same capability in wanted and unwanted lists.");
+ }
+ this.mNetworkCapabilities = wantedCaps;
+ this.mUnwantedNetworkCapabilities = unwantedCaps;
}
/**
@@ -1458,9 +1540,8 @@
* @hide
*/
public @NonNull NetworkCapabilities setSingleUid(int uid) {
- final ArraySet<UidRange> identity = new ArraySet<>(1);
- identity.add(new UidRange(uid, uid));
- setUids(identity);
+ mUids = new ArraySet<>(1);
+ mUids.add(new UidRange(uid, uid));
return this;
}
@@ -1469,22 +1550,34 @@
* This makes a copy of the set so that callers can't modify it after the call.
* @hide
*/
- public @NonNull NetworkCapabilities setUids(Set<UidRange> uids) {
- if (null == uids) {
- mUids = null;
- } else {
- mUids = new ArraySet<>(uids);
- }
+ public @NonNull NetworkCapabilities setUids(@Nullable Set<Range<Integer>> uids) {
+ mUids = UidRange.fromIntRanges(uids);
return this;
}
/**
* Get the list of UIDs this network applies to.
* This returns a copy of the set so that callers can't modify the original object.
+ *
+ * @return the list of UIDs this network applies to. If {@code null}, then the network applies
+ * to all UIDs.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("NullableCollection")
+ public @Nullable Set<Range<Integer>> getUids() {
+ return UidRange.toIntRanges(mUids);
+ }
+
+ /**
+ * Get the list of UIDs this network applies to.
+ * This returns a copy of the set so that callers can't modify the original object.
* @hide
*/
- public @Nullable Set<UidRange> getUids() {
- return null == mUids ? null : new ArraySet<>(mUids);
+ public @Nullable Set<UidRange> getUidRanges() {
+ if (mUids == null) return null;
+
+ return new ArraySet<>(mUids);
}
/**
@@ -2099,8 +2192,9 @@
}
private static void checkValidTransportType(@Transport int transport) {
- Preconditions.checkArgument(
- isValidTransport(transport), "Invalid TransportType " + transport);
+ if (!isValidTransport(transport)) {
+ throw new IllegalArgumentException("Invalid TransportType " + transport);
+ }
}
private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) {
@@ -2108,8 +2202,9 @@
}
private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) {
- Preconditions.checkArgument(isValidCapability(capability),
- "NetworkCapability " + capability + "out of range");
+ if (!isValidCapability(capability)) {
+ throw new IllegalArgumentException("NetworkCapability " + capability + "out of range");
+ }
}
/**
@@ -2338,6 +2433,23 @@
}
/**
+ * Returns a bitmask of all the applicable redactions (based on the permissions held by the
+ * receiving app) to be performed on this object.
+ *
+ * @return bitmask of redactions applicable on this instance.
+ * @hide
+ */
+ public @RedactionType long getApplicableRedactions() {
+ // Currently, there are no fields redacted in NetworkCapabilities itself, so we just
+ // passthrough the redactions required by the embedded TransportInfo. If this changes
+ // in the future, modify this method.
+ if (mTransportInfo == null) {
+ return NetworkCapabilities.REDACT_NONE;
+ }
+ return mTransportInfo.getApplicableRedactions();
+ }
+
+ /**
* Builder class for NetworkCapabilities.
*
* This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
@@ -2655,6 +2767,21 @@
}
/**
+ * Set the list of UIDs this network applies to.
+ *
+ * @param uids the list of UIDs this network applies to, or {@code null} if this network
+ * applies to all UIDs.
+ * @return this builder
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public Builder setUids(@Nullable Set<Range<Integer>> uids) {
+ mCaps.setUids(uids);
+ return this;
+ }
+
+ /**
* Builds the instance of the capabilities.
*
* @return the built instance of NetworkCapabilities.
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index 3fd95ee..bcbc04f7 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -36,6 +36,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.NetworkCapabilities.NetCapability;
@@ -45,6 +46,7 @@
import android.os.Parcelable;
import android.os.Process;
import android.text.TextUtils;
+import android.util.Range;
import android.util.proto.ProtoOutputStream;
import java.util.Arrays;
@@ -140,7 +142,7 @@
REQUEST,
BACKGROUND_REQUEST,
TRACK_SYSTEM_DEFAULT,
- TRACK_BEST,
+ LISTEN_FOR_BEST,
};
/**
@@ -214,6 +216,14 @@
}
/**
+ * Creates a new Builder of NetworkRequest from an existing instance.
+ */
+ public Builder(@NonNull final NetworkRequest request) {
+ Objects.requireNonNull(request);
+ mNetworkCapabilities = request.networkCapabilities;
+ }
+
+ /**
* Build {@link NetworkRequest} give the current set of capabilities.
*/
public NetworkRequest build() {
@@ -277,11 +287,14 @@
* Set the watched UIDs for this request. This will be reset and wiped out unless
* the calling app holds the CHANGE_NETWORK_STATE permission.
*
- * @param uids The watched UIDs as a set of UidRanges, or null for everything.
+ * @param uids The watched UIDs as a set of {@code Range<Integer>}, or null for everything.
* @return The builder to facilitate chaining.
* @hide
*/
- public Builder setUids(Set<UidRange> uids) {
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setUids(@Nullable Set<Range<Integer>> uids) {
mNetworkCapabilities.setUids(uids);
return this;
}
@@ -300,12 +313,31 @@
*
* @hide
*/
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addUnwantedCapability(capability);
return this;
}
/**
+ * Removes (if found) the given unwanted capability from this builder instance.
+ *
+ * @param capability The unwanted capability to remove.
+ * @return The builder to facilitate chaining.
+ *
+ * @hide
+ */
+ @NonNull
+ @SuppressLint("BuilderSetStyle")
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public Builder removeUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
+ mNetworkCapabilities.removeUnwantedCapability(capability);
+ return this;
+ }
+
+ /**
* Completely clears all the {@code NetworkCapabilities} from this builder instance,
* removing even the capabilities that are set by default when the object is constructed.
*
@@ -514,6 +546,15 @@
}
/**
+ * Returns true iff. this NetworkRequest is of type LISTEN_FOR_BEST.
+ *
+ * @hide
+ */
+ public boolean isListenForBest() {
+ return type == Type.LISTEN_FOR_BEST;
+ }
+
+ /**
* Returns true iff. the contained NetworkRequest is one that:
*
* - should be associated with at most one satisfying network
@@ -553,6 +594,7 @@
*
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return networkCapabilities.hasUnwantedCapability(capability);
}
diff --git a/framework/src/android/net/NetworkScore.java b/framework/src/android/net/NetworkScore.java
new file mode 100644
index 0000000..6584993
--- /dev/null
+++ b/framework/src/android/net/NetworkScore.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Object representing the quality of a network as perceived by the user.
+ *
+ * A NetworkScore object represents the characteristics of a network that affects how good the
+ * network is considered for a particular use.
+ * @hide
+ */
+@SystemApi
+public final class NetworkScore implements Parcelable {
+ // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
+ // a migration.
+ private final int mLegacyInt;
+
+ // Agent-managed policies
+ // TODO : add them here, starting from 1
+ /** @hide */
+ public static final int MIN_AGENT_MANAGED_POLICY = 0;
+ /** @hide */
+ public static final int MAX_AGENT_MANAGED_POLICY = -1;
+
+ // Bitmask of all the policies applied to this score.
+ private final long mPolicies;
+
+ /** @hide */
+ NetworkScore(final int legacyInt, final long policies) {
+ mLegacyInt = legacyInt;
+ mPolicies = policies;
+ }
+
+ private NetworkScore(@NonNull final Parcel in) {
+ mLegacyInt = in.readInt();
+ mPolicies = in.readLong();
+ }
+
+ public int getLegacyInt() {
+ return mLegacyInt;
+ }
+
+ /**
+ * @return whether this score has a particular policy.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean hasPolicy(final int policy) {
+ return 0 != (mPolicies & (1L << policy));
+ }
+
+ @Override
+ public String toString() {
+ return "Score(" + mLegacyInt + ")";
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(mLegacyInt);
+ dest.writeLong(mPolicies);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull public static final Creator<NetworkScore> CREATOR = new Creator<>() {
+ @Override
+ @NonNull
+ public NetworkScore createFromParcel(@NonNull final Parcel in) {
+ return new NetworkScore(in);
+ }
+
+ @Override
+ @NonNull
+ public NetworkScore[] newArray(int size) {
+ return new NetworkScore[size];
+ }
+ };
+
+ /**
+ * A builder for NetworkScore.
+ */
+ public static final class Builder {
+ private static final long POLICY_NONE = 0L;
+ private static final int INVALID_LEGACY_INT = Integer.MIN_VALUE;
+ private int mLegacyInt = INVALID_LEGACY_INT;
+
+ /**
+ * Sets the legacy int for this score.
+ *
+ * Do not rely on this. It will be gone by the time S is released.
+ *
+ * @param score the legacy int
+ * @return this
+ */
+ @NonNull
+ public Builder setLegacyInt(final int score) {
+ mLegacyInt = score;
+ return this;
+ }
+
+ /**
+ * Builds this NetworkScore.
+ * @return The built NetworkScore object.
+ */
+ @NonNull
+ public NetworkScore build() {
+ return new NetworkScore(mLegacyInt, POLICY_NONE);
+ }
+ }
+}
diff --git a/framework/src/android/net/NetworkUtils.java b/framework/src/android/net/NetworkUtils.java
index 9e42bbe..a92fda1 100644
--- a/framework/src/android/net/NetworkUtils.java
+++ b/framework/src/android/net/NetworkUtils.java
@@ -27,8 +27,10 @@
import java.io.FileDescriptor;
import java.math.BigInteger;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.SocketException;
+import java.net.UnknownHostException;
import java.util.Locale;
import java.util.TreeSet;
@@ -90,7 +92,10 @@
* Determine if {@code uid} can access network designated by {@code netId}.
* @return {@code true} if {@code uid} can access network, {@code false} otherwise.
*/
- public native static boolean queryUserAccess(int uid, int netId);
+ public static boolean queryUserAccess(int uid, int netId) {
+ // TODO (b/183485986): remove this method
+ return false;
+ }
/**
* DNS resolver series jni method.
@@ -212,7 +217,7 @@
@Deprecated
public static InetAddress numericToInetAddress(String addrString)
throws IllegalArgumentException {
- return InetAddress.parseNumericAddress(addrString);
+ return InetAddresses.parseNumericAddress(addrString);
}
/**
@@ -234,7 +239,7 @@
try {
String[] pieces = ipAndMaskString.split("/", 2);
prefixLength = Integer.parseInt(pieces[1]);
- address = InetAddress.parseNumericAddress(pieces[0]);
+ address = InetAddresses.parseNumericAddress(pieces[0]);
} catch (NullPointerException e) { // Null string.
} catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
} catch (NumberFormatException e) { // Non-numeric prefix.
@@ -249,6 +254,47 @@
}
/**
+ * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
+ * @hide
+ *
+ * @deprecated This method is used only for IpPrefix and LinkAddress. Since Android S, use
+ * {@link #parseIpAndMask(String)}, if possible.
+ */
+ @Deprecated
+ public static Pair<InetAddress, Integer> legacyParseIpAndMask(String ipAndMaskString) {
+ InetAddress address = null;
+ int prefixLength = -1;
+ try {
+ String[] pieces = ipAndMaskString.split("/", 2);
+ prefixLength = Integer.parseInt(pieces[1]);
+ if (pieces[0] == null || pieces[0].isEmpty()) {
+ final byte[] bytes = new byte[16];
+ bytes[15] = 1;
+ return new Pair<InetAddress, Integer>(Inet6Address.getByAddress(
+ "ip6-localhost"/* host */, bytes, 0 /* scope_id */), prefixLength);
+ }
+
+ if (pieces[0].startsWith("[")
+ && pieces[0].endsWith("]")
+ && pieces[0].indexOf(':') != -1) {
+ pieces[0] = pieces[0].substring(1, pieces[0].length() - 1);
+ }
+ address = InetAddresses.parseNumericAddress(pieces[0]);
+ } catch (NullPointerException e) { // Null string.
+ } catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
+ } catch (NumberFormatException e) { // Non-numeric prefix.
+ } catch (IllegalArgumentException e) { // Invalid IP address.
+ } catch (UnknownHostException e) { // IP address length is illegal
+ }
+
+ if (address == null || prefixLength == -1) {
+ throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
+ }
+
+ return new Pair<InetAddress, Integer>(address, prefixLength);
+ }
+
+ /**
* Convert a 32 char hex string into a Inet6Address.
* throws a runtime exception if the string isn't 32 chars, isn't hex or can't be
* made into an Inet6Address
@@ -280,22 +326,7 @@
*/
@UnsupportedAppUsage
public static String trimV4AddrZeros(String addr) {
- if (addr == null) return null;
- String[] octets = addr.split("\\.");
- if (octets.length != 4) return addr;
- StringBuilder builder = new StringBuilder(16);
- String result = null;
- for (int i = 0; i < 4; i++) {
- try {
- if (octets[i].length() > 3) return addr;
- builder.append(Integer.parseInt(octets[i]));
- } catch (NumberFormatException e) {
- return addr;
- }
- if (i < 3) builder.append('.');
- }
- result = builder.toString();
- return result;
+ return Inet4AddressUtils.trimAddressZeros(addr);
}
/**
diff --git a/framework/src/android/net/OemNetworkPreferences.java b/framework/src/android/net/OemNetworkPreferences.java
index 48bd297..5a76cd6 100644
--- a/framework/src/android/net/OemNetworkPreferences.java
+++ b/framework/src/android/net/OemNetworkPreferences.java
@@ -73,6 +73,14 @@
private final Bundle mNetworkMappings;
/**
+ * Return whether this object is empty.
+ * @hide
+ */
+ public boolean isEmpty() {
+ return mNetworkMappings.keySet().size() == 0;
+ }
+
+ /**
* Return the currently built application package name to {@link OemNetworkPreference} mappings.
* @return the current network preferences map.
*/
diff --git a/framework/src/android/net/ParseException.java b/framework/src/android/net/ParseException.java
index bcfdd7e..ca6d012 100644
--- a/framework/src/android/net/ParseException.java
+++ b/framework/src/android/net/ParseException.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
/**
* Thrown when parsing failed.
@@ -25,12 +26,16 @@
public class ParseException extends RuntimeException {
public String response;
- ParseException(@NonNull String response) {
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public ParseException(@NonNull String response) {
super(response);
this.response = response;
}
- ParseException(@NonNull String response, @NonNull Throwable cause) {
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public ParseException(@NonNull String response, @NonNull Throwable cause) {
super(response, cause);
this.response = response;
}
diff --git a/framework/src/android/net/ProxyInfo.java b/framework/src/android/net/ProxyInfo.java
index 229db0d..745e20f 100644
--- a/framework/src/android/net/ProxyInfo.java
+++ b/framework/src/android/net/ProxyInfo.java
@@ -129,7 +129,7 @@
}
/**
- * Only used in PacProxyInstaller after Local Proxy is bound.
+ * Only used in PacProxyService after Local Proxy is bound.
* @hide
*/
public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) {
diff --git a/framework/src/android/net/QosCallbackConnection.java b/framework/src/android/net/QosCallbackConnection.java
index bdb4ad6..de0fc24 100644
--- a/framework/src/android/net/QosCallbackConnection.java
+++ b/framework/src/android/net/QosCallbackConnection.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import com.android.internal.annotations.VisibleForTesting;
@@ -84,6 +85,25 @@
}
/**
+ * Called when either the {@link NrQosSessionAttributes} has changed or on the first time
+ * the attributes have become available.
+ *
+ * @param session the session that is now available
+ * @param attributes the corresponding attributes of session
+ */
+ @Override
+ public void onNrQosSessionAvailable(@NonNull final QosSession session,
+ @NonNull final NrQosSessionAttributes attributes) {
+
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionAvailable(session, attributes);
+ }
+ });
+ }
+
+ /**
* Called when the session is lost.
*
* @param session the session that was lost
diff --git a/framework/src/android/net/QosSession.java b/framework/src/android/net/QosSession.java
index 4f3bb77..93f2ff2 100644
--- a/framework/src/android/net/QosSession.java
+++ b/framework/src/android/net/QosSession.java
@@ -36,6 +36,11 @@
*/
public static final int TYPE_EPS_BEARER = 1;
+ /**
+ * The {@link QosSession} is a NR Session.
+ */
+ public static final int TYPE_NR_BEARER = 2;
+
private final int mSessionId;
private final int mSessionType;
@@ -100,6 +105,7 @@
*/
@IntDef(value = {
TYPE_EPS_BEARER,
+ TYPE_NR_BEARER,
})
@interface QosSessionType {}
diff --git a/framework/src/android/net/StaticIpConfiguration.java b/framework/src/android/net/StaticIpConfiguration.java
index ce54597..7904f7a 100644
--- a/framework/src/android/net/StaticIpConfiguration.java
+++ b/framework/src/android/net/StaticIpConfiguration.java
@@ -24,7 +24,6 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Preconditions;
import com.android.net.module.util.InetAddressUtils;
import java.net.InetAddress;
@@ -153,7 +152,7 @@
* @return The {@link Builder} for chaining.
*/
public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) {
- Preconditions.checkNotNull(dnsServers);
+ Objects.requireNonNull(dnsServers);
mDnsServers = dnsServers;
return this;
}
diff --git a/framework/src/android/net/TestNetworkManager.java b/framework/src/android/net/TestNetworkManager.java
index a174a7b..a7a6235 100644
--- a/framework/src/android/net/TestNetworkManager.java
+++ b/framework/src/android/net/TestNetworkManager.java
@@ -21,10 +21,9 @@
import android.os.IBinder;
import android.os.RemoteException;
-import com.android.internal.util.Preconditions;
-
import java.util.Arrays;
import java.util.Collection;
+import java.util.Objects;
/**
* Class that allows creation and management of per-app, test-only networks
@@ -50,7 +49,7 @@
/** @hide */
public TestNetworkManager(@NonNull ITestNetworkManager service) {
- mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager");
+ mService = Objects.requireNonNull(service, "missing ITestNetworkManager");
}
/**
@@ -93,7 +92,7 @@
*/
public void setupTestNetwork(
@NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) {
- Preconditions.checkNotNull(lp, "Invalid LinkProperties");
+ Objects.requireNonNull(lp, "Invalid LinkProperties");
setupTestNetwork(lp.getInterfaceName(), lp, isMetered, new int[0], binder);
}
diff --git a/framework/src/android/net/TestNetworkSpecifier.java b/framework/src/android/net/TestNetworkSpecifier.java
index b7470a5..117457d 100644
--- a/framework/src/android/net/TestNetworkSpecifier.java
+++ b/framework/src/android/net/TestNetworkSpecifier.java
@@ -23,8 +23,6 @@
import android.os.Parcelable;
import android.text.TextUtils;
-import com.android.internal.util.Preconditions;
-
import java.util.Objects;
/**
@@ -43,7 +41,9 @@
private final String mInterfaceName;
public TestNetworkSpecifier(@NonNull String interfaceName) {
- Preconditions.checkStringNotEmpty(interfaceName);
+ if (TextUtils.isEmpty(interfaceName)) {
+ throw new IllegalArgumentException("Empty interfaceName");
+ }
mInterfaceName = interfaceName;
}
diff --git a/framework/src/android/net/TransportInfo.java b/framework/src/android/net/TransportInfo.java
index aa4bbb0..fa889ea 100644
--- a/framework/src/android/net/TransportInfo.java
+++ b/framework/src/android/net/TransportInfo.java
@@ -29,35 +29,47 @@
public interface TransportInfo {
/**
- * Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that
- * were set based on the permissions of the process that originally received it.
+ * Create a copy of a {@link TransportInfo} with some fields redacted based on the permissions
+ * held by the receiving app.
*
- * <p>By default {@link TransportInfo} does not preserve such fields during parceling, as
- * they should not be shared outside of the process that receives them without appropriate
- * checks.
+ * <p>
+ * Usage by connectivity stack:
+ * <ul>
+ * <li> Connectivity stack will invoke {@link #getApplicableRedactions()} to find the list
+ * of redactions that are required by this {@link TransportInfo} instance.</li>
+ * <li> Connectivity stack then loops through each bit in the bitmask returned and checks if the
+ * receiving app holds the corresponding permission.
+ * <ul>
+ * <li> If the app holds the corresponding permission, the bit is cleared from the
+ * |redactions| bitmask. </li>
+ * <li> If the app does not hold the corresponding permission, the bit is retained in the
+ * |redactions| bitmask. </li>
+ * </ul>
+ * <li> Connectivity stack then invokes {@link #makeCopy(long)} with the necessary |redactions|
+ * to create a copy to send to the corresponding app. </li>
+ * </ul>
+ * </p>
*
- * @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept
- * when parceling
- * @return Copy of this instance.
+ * @param redactions bitmask of redactions that needs to be performed on this instance.
+ * @return Copy of this instance with the necessary redactions.
* @hide
*/
- @SystemApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
- default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
+ default TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
return this;
}
/**
- * Returns whether this TransportInfo type has location sensitive fields or not (helps
- * to determine whether to perform a location permission check or not before sending to
- * apps).
+ * Returns a bitmask of all the applicable redactions (based on the permissions held by the
+ * receiving app) to be performed on this TransportInfo.
*
- * @return {@code true} if this instance contains location sensitive info, {@code false}
- * otherwise.
+ * @return bitmask of redactions applicable on this instance.
+ * @see #makeCopy(long)
* @hide
*/
- @SystemApi
- default boolean hasLocationSensitiveFields() {
- return false;
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ default @NetworkCapabilities.RedactionType long getApplicableRedactions() {
+ return NetworkCapabilities.REDACT_NONE;
}
}
diff --git a/framework/src/android/net/UidRange.java b/framework/src/android/net/UidRange.java
index 26518d3..bc67c74 100644
--- a/framework/src/android/net/UidRange.java
+++ b/framework/src/android/net/UidRange.java
@@ -20,8 +20,11 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Range;
import java.util.Collection;
+import java.util.Set;
/**
* An inclusive range of UIDs.
@@ -149,4 +152,32 @@
}
return false;
}
+
+ /**
+ * Convert a set of {@code Range<Integer>} to a set of {@link UidRange}.
+ */
+ @Nullable
+ public static ArraySet<UidRange> fromIntRanges(@Nullable Set<Range<Integer>> ranges) {
+ if (null == ranges) return null;
+
+ final ArraySet<UidRange> uids = new ArraySet<>();
+ for (Range<Integer> range : ranges) {
+ uids.add(new UidRange(range.getLower(), range.getUpper()));
+ }
+ return uids;
+ }
+
+ /**
+ * Convert a set of {@link UidRange} to a set of {@code Range<Integer>}.
+ */
+ @Nullable
+ public static ArraySet<Range<Integer>> toIntRanges(@Nullable Set<UidRange> ranges) {
+ if (null == ranges) return null;
+
+ final ArraySet<Range<Integer>> uids = new ArraySet<>();
+ for (UidRange range : ranges) {
+ uids.add(new Range<Integer>(range.start, range.stop));
+ }
+ return uids;
+ }
}
diff --git a/framework/src/android/net/VpnTransportInfo.java b/framework/src/android/net/VpnTransportInfo.java
index 340141b..cd8f4c0 100644
--- a/framework/src/android/net/VpnTransportInfo.java
+++ b/framework/src/android/net/VpnTransportInfo.java
@@ -22,9 +22,6 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.SparseArray;
-
-import com.android.internal.util.MessageUtils;
import java.util.Objects;
@@ -38,13 +35,10 @@
*/
@SystemApi(client = MODULE_LIBRARIES)
public final class VpnTransportInfo implements TransportInfo, Parcelable {
- private static final SparseArray<String> sTypeToString =
- MessageUtils.findMessageNames(new Class[]{VpnManager.class}, new String[]{"TYPE_VPN_"});
-
/** Type of this VPN. */
- @VpnManager.VpnType public final int type;
+ public final int type;
- public VpnTransportInfo(@VpnManager.VpnType int type) {
+ public VpnTransportInfo(int type) {
this.type = type;
}
@@ -63,8 +57,7 @@
@Override
public String toString() {
- final String typeString = sTypeToString.get(type, "VPN_TYPE_???");
- return String.format("VpnTransportInfo{%s}", typeString);
+ return String.format("VpnTransportInfo{type=%d}", type);
}
@Override
diff --git a/framework/src/android/net/apf/ApfCapabilities.java b/framework/src/android/net/apf/ApfCapabilities.java
index bf5b26e..85b2471 100644
--- a/framework/src/android/net/apf/ApfCapabilities.java
+++ b/framework/src/android/net/apf/ApfCapabilities.java
@@ -19,12 +19,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.Context;
import android.content.res.Resources;
+import android.net.ConnectivityResources;
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.R;
-
/**
* APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
* way to drop unwanted network packets to save power.
@@ -36,6 +36,8 @@
*/
@SystemApi
public final class ApfCapabilities implements Parcelable {
+ private static ConnectivityResources sResources;
+
/**
* Version of APF instruction set supported for packet filtering. 0 indicates no support for
* packet filtering using APF programs.
@@ -65,6 +67,14 @@
apfPacketFormat = in.readInt();
}
+ @NonNull
+ private static synchronized ConnectivityResources getResources(@NonNull Context ctx) {
+ if (sResources == null) {
+ sResources = new ConnectivityResources(ctx);
+ }
+ return sResources;
+ }
+
@Override
public int describeContents() {
@@ -121,13 +131,43 @@
* @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
*/
public static boolean getApfDrop8023Frames() {
- return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames);
+ // TODO(b/183076074): remove reading resources from system resources
+ final Resources systemRes = Resources.getSystem();
+ final int id = systemRes.getIdentifier("config_apfDrop802_3Frames", "bool", "android");
+ return systemRes.getBoolean(id);
+ }
+
+ /**
+ * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
+ * @hide
+ */
+ public static boolean getApfDrop8023Frames(@NonNull Context context) {
+ final ConnectivityResources res = getResources(context);
+ // TODO(b/183076074): use R.bool.config_apfDrop802_3Frames directly
+ final int id = res.get().getIdentifier("config_apfDrop802_3Frames", "bool",
+ res.getResourcesContext().getPackageName());
+ return res.get().getBoolean(id);
}
/**
* @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped.
*/
public static @NonNull int[] getApfEtherTypeBlackList() {
- return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList);
+ // TODO(b/183076074): remove reading resources from system resources
+ final Resources systemRes = Resources.getSystem();
+ final int id = systemRes.getIdentifier("config_apfEthTypeBlackList", "array", "android");
+ return systemRes.getIntArray(id);
+ }
+
+ /**
+ * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped.
+ * @hide
+ */
+ public static @NonNull int[] getApfEtherTypeDenyList(@NonNull Context context) {
+ final ConnectivityResources res = getResources(context);
+ // TODO(b/183076074): use R.array.config_apfEthTypeDenyList directly
+ final int id = res.get().getIdentifier("config_apfEthTypeDenyList", "array",
+ res.getResourcesContext().getPackageName());
+ return res.get().getIntArray(id);
}
}
diff --git a/framework/src/android/net/util/KeepaliveUtils.java b/framework/src/android/net/util/KeepaliveUtils.java
index bfc4563..8d7a0b3 100644
--- a/framework/src/android/net/util/KeepaliveUtils.java
+++ b/framework/src/android/net/util/KeepaliveUtils.java
@@ -19,12 +19,11 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
+import android.net.ConnectivityResources;
import android.net.NetworkCapabilities;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
-import com.android.internal.R;
-
/**
* Collection of utilities for socket keepalive offload.
*
@@ -52,8 +51,11 @@
public static int[] getSupportedKeepalives(@NonNull Context context) {
String[] res = null;
try {
- res = context.getResources().getStringArray(
- R.array.config_networkSupportedKeepaliveCount);
+ final ConnectivityResources connRes = new ConnectivityResources(context);
+ // TODO: use R.id.config_networkSupportedKeepaliveCount directly
+ final int id = connRes.get().getIdentifier("config_networkSupportedKeepaliveCount",
+ "array", connRes.getResourcesContext().getPackageName());
+ res = new ConnectivityResources(context).get().getStringArray(id);
} catch (Resources.NotFoundException unused) {
}
if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource");
diff --git a/framework/src/android/net/util/MultinetworkPolicyTracker.java b/framework/src/android/net/util/MultinetworkPolicyTracker.java
index 739ddad..0b42a00 100644
--- a/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ b/framework/src/android/net/util/MultinetworkPolicyTracker.java
@@ -16,8 +16,8 @@
package android.net.util;
-import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
-import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
+import static android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
@@ -27,6 +27,7 @@
import android.content.IntentFilter;
import android.content.res.Resources;
import android.database.ContentObserver;
+import android.net.ConnectivityResources;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
@@ -35,7 +36,6 @@
import android.telephony.TelephonyManager;
import android.util.Log;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import java.util.Arrays;
@@ -64,6 +64,7 @@
private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
private final Context mContext;
+ private final ConnectivityResources mResources;
private final Handler mHandler;
private final Runnable mAvoidBadWifiCallback;
private final List<Uri> mSettingsUris;
@@ -107,11 +108,12 @@
public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
mContext = ctx;
+ mResources = new ConnectivityResources(ctx);
mHandler = handler;
mAvoidBadWifiCallback = avoidBadWifiCallback;
mSettingsUris = Arrays.asList(
- Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
- Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
+ Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
+ Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
mResolver = mContext.getContentResolver();
mSettingObserver = new SettingObserver();
mBroadcastReceiver = new BroadcastReceiver() {
@@ -160,12 +162,16 @@
* Whether the device or carrier configuration disables avoiding bad wifi by default.
*/
public boolean configRestrictsAvoidBadWifi() {
- return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
+ // TODO: use R.integer.config_networkAvoidBadWifi directly
+ final int id = mResources.get().getIdentifier("config_networkAvoidBadWifi",
+ "integer", mResources.getResourcesContext().getPackageName());
+ return (getResourcesForActiveSubId().getInteger(id) == 0);
}
@NonNull
private Resources getResourcesForActiveSubId() {
- return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId);
+ return SubscriptionManager.getResourcesForSubId(
+ mResources.getResourcesContext(), mActiveSubId);
}
/**
@@ -205,8 +211,10 @@
* The default (device and carrier-dependent) value for metered multipath preference.
*/
public int configMeteredMultipathPreference() {
- return mContext.getResources().getInteger(
- R.integer.config_networkMeteredMultipathPreference);
+ // TODO: use R.integer.config_networkMeteredMultipathPreference directly
+ final int id = mResources.get().getIdentifier("config_networkMeteredMultipathPreference",
+ "integer", mResources.getResourcesContext().getPackageName());
+ return mResources.get().getInteger(id);
}
public void updateMeteredMultipathPreference() {
diff --git a/service/Android.bp b/service/Android.bp
index e65b7b4..1330e71 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -50,26 +50,56 @@
}
java_library {
- name: "service-connectivity",
+ name: "service-connectivity-pre-jarjar",
srcs: [
+ ":framework-connectivity-shared-srcs",
":connectivity-service-srcs",
],
- installable: true,
- jarjar_rules: "jarjar-rules.txt",
libs: [
"android.net.ipsec.ike",
"services.core",
"services.net",
"unsupportedappusage",
+ "ServiceConnectivityResources",
],
static_libs: [
"modules-utils-os",
"net-utils-device-common",
"net-utils-framework-common",
"netd-client",
+ "PlatformProperties",
+ "service-connectivity-protos",
],
apex_available: [
"//apex_available:platform",
"com.android.tethering",
],
}
+
+java_library {
+ name: "service-connectivity-protos",
+ proto: {
+ type: "nano",
+ },
+ srcs: [
+ ":system-messages-proto-src",
+ ],
+ libs: ["libprotobuf-java-nano"],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.tethering",
+ ],
+}
+
+java_library {
+ name: "service-connectivity",
+ installable: true,
+ static_libs: [
+ "service-connectivity-pre-jarjar",
+ ],
+ jarjar_rules: "jarjar-rules.txt",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.tethering",
+ ],
+}
diff --git a/service/ServiceConnectivityResources/Android.bp b/service/ServiceConnectivityResources/Android.bp
new file mode 100644
index 0000000..fa4501a
--- /dev/null
+++ b/service/ServiceConnectivityResources/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// APK to hold all the wifi overlayable resources.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_app {
+ name: "ServiceConnectivityResources",
+ sdk_version: "module_current",
+ resource_dirs: [
+ "res",
+ ],
+ privileged: true,
+ export_package_resources: true,
+ apex_available: [
+ "com.android.tethering",
+ ],
+ // TODO: use a dedicated cert once generated
+ certificate: "platform",
+}
diff --git a/service/ServiceConnectivityResources/AndroidManifest.xml b/service/ServiceConnectivityResources/AndroidManifest.xml
new file mode 100644
index 0000000..2c30302
--- /dev/null
+++ b/service/ServiceConnectivityResources/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<!-- Manifest for connectivity resources APK -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.connectivity.resources"
+ coreApp="true"
+ android:versionCode="1"
+ android:versionName="S-initial">
+ <application
+ android:label="@string/connectivityResourcesAppLabel"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true">
+ <!-- This is only used to identify this app by resolving the action.
+ The activity is never actually triggered. -->
+ <activity android:name="android.app.Activity" android:exported="true" android:enabled="true">
+ <intent-filter>
+ <action android:name="com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png b/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..74977e6
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png b/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..62e4fe9
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png b/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..c0586d8
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png b/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..86c34ed
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml b/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml
new file mode 100644
index 0000000..a271ca5
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="26.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#4DFFFFFF"
+ android:pathData="M19.1,14l-3.4,0l0,-1.5c0,-1.8 0.8,-2.8 1.5,-3.4C18.1,8.3 19.200001,8 20.6,8c1.2,0 2.3,0.3 3.1,0.8l1.9,-2.3C25.1,6.1 20.299999,2.1 13,2.1S0.9,6.1 0.4,6.5L13,22l0,0l0,0l0,0l0,0l6.5,-8.1L19.1,14z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19.5,17.799999c0,-0.8 0.1,-1.3 0.2,-1.6c0.2,-0.3 0.5,-0.7 1.1,-1.2c0.4,-0.4 0.7,-0.8 1,-1.1s0.4,-0.8 0.4,-1.2c0,-0.5 -0.1,-0.9 -0.4,-1.2c-0.3,-0.3 -0.7,-0.4 -1.2,-0.4c-0.4,0 -0.8,0.1 -1.1,0.3c-0.3,0.2 -0.4,0.6 -0.4,1.1l-1.9,0c0,-1 0.3,-1.7 1,-2.2c0.6,-0.5 1.5,-0.8 2.5,-0.8c1.1,0 2,0.3 2.6,0.8c0.6,0.5 0.9,1.3 0.9,2.3c0,0.7 -0.2,1.3 -0.6,1.8c-0.4,0.6 -0.9,1.1 -1.5,1.6c-0.3,0.3 -0.5,0.5 -0.6,0.7c-0.1,0.2 -0.1,0.6 -0.1,1L19.5,17.700001zM21.4,21l-1.9,0l0,-1.8l1.9,0L21.4,21z"/>
+</vector>
diff --git a/service/ServiceConnectivityResources/res/values-af/strings.xml b/service/ServiceConnectivityResources/res/values-af/strings.xml
new file mode 100644
index 0000000..68720d5
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-af/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Meld aan by Wi-Fi-netwerk"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Meld by netwerk aan"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het geen internettoegang nie"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tik vir opsies"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Selnetwerk het nie internettoegang nie"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netwerk het nie internettoegang nie"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Daar kan nie by private DNS-bediener ingegaan word nie"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het beperkte konnektiwiteit"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tik om in elk geval te koppel"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internettoegang het nie. Heffings kan geld."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"\'n onbekende netwerktipe"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiele data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-am/strings.xml b/service/ServiceConnectivityResources/res/values-am/strings.xml
new file mode 100644
index 0000000..78d9283
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-am/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ምንም የበይነ መረብ መዳረሻ የለም"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ለአማራጮች መታ ያድርጉ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"የተንቀሳቃሽ ስልክ አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"የግል ዲኤንኤስ አገልጋይ ሊደረስበት አይችልም"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> የተገደበ ግንኙነት አለው"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ለማንኛውም ለማገናኘት መታ ያድርጉ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"የተንቀሳቃሽ ስልክ ውሂብ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ብሉቱዝ"</item>
+ <item msgid="1616528372438698248">"ኤተርኔት"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ar/strings.xml b/service/ServiceConnectivityResources/res/values-ar/strings.xml
new file mode 100644
index 0000000..8698a7e
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ar/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"تسجيل الدخول إلى شبكة Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"تسجيل الدخول إلى الشبكة"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"لا يتوفّر في <xliff:g id="NETWORK_SSID">%1$s</xliff:g> إمكانية الاتصال بالإنترنت."</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"انقر للحصول على الخيارات."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"شبكة الجوّال هذه غير متصلة بالإنترنت"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"الشبكة غير متصلة بالإنترنت"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"لا يمكن الوصول إلى خادم أسماء نظام نطاقات خاص"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"إمكانية اتصال <xliff:g id="NETWORK_SSID">%1$s</xliff:g> محدودة."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"يمكنك النقر للاتصال على أي حال."</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نوع شبكة غير معروف"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"بيانات الجوّال"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"بلوتوث"</item>
+ <item msgid="1616528372438698248">"إيثرنت"</item>
+ <item msgid="9177085807664964627">"شبكة افتراضية خاصة (VPN)"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-as/strings.xml b/service/ServiceConnectivityResources/res/values-as/strings.xml
new file mode 100644
index 0000000..10b234a
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-as/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ৱাই-ফাই নেটৱৰ্কত ছাইন ইন কৰক"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"অধিক বিকল্পৰ বাবে টিপক"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ম’বাইল নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ব্যক্তিগত DNS ছাৰ্ভাৰ এক্সেছ কৰিব নোৱাৰি"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ সকলো সেৱাৰ এক্সেছ নাই"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"যিকোনো প্ৰকাৰে সংযোগ কৰিবলৈ টিপক"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>লৈ সলনি কৰা হ’ল"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"যেতিয়া <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ত ইণ্টাৰনেট নাথাকে, তেতিয়া ডিভাইচে <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ক ব্যৱহাৰ কৰে। মাচুল প্ৰযোজ্য হ\'ব পাৰে।"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>ৰ পৰা <xliff:g id="NEW_NETWORK">%2$s</xliff:g> লৈ সলনি কৰা হ’ল"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"অজ্ঞাত প্ৰকাৰৰ নেটৱৰ্ক"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ম’বাইল ডেটা"</item>
+ <item msgid="5520925862115353992">"ৱাই-ফাই"</item>
+ <item msgid="1055487873974272842">"ব্লুটুথ"</item>
+ <item msgid="1616528372438698248">"ইথাৰনেট"</item>
+ <item msgid="9177085807664964627">"ভিপিএন"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-az/strings.xml b/service/ServiceConnectivityResources/res/values-az/strings.xml
new file mode 100644
index 0000000..d75a204
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-az/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi şəbəkəsinə daxil ol"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Şəbəkəyə daxil olun"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> üçün internet girişi əlçatan deyil"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Seçimlər üçün tıklayın"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil şəbəkənin internetə girişi yoxdur"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Şəbəkənin internetə girişi yoxdur"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Özəl DNS serverinə giriş mümkün deyil"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> bağlantını məhdudlaşdırdı"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"İstənilən halda klikləyin"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin internetə girişi olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Xidmət haqqı tutula bilər."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"naməlum şəbəkə növü"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobil data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml b/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..11e4957
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavljivanje na WiFi mrežu"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prijavite se na mrežu"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Pristup privatnom DNS serveru nije uspeo"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu vezu"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da biste se ipak povezali"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznat tip mreže"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilni podaci"</item>
+ <item msgid="5520925862115353992">"WiFi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Eternet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-be/strings.xml b/service/ServiceConnectivityResources/res/values-be/strings.xml
new file mode 100644
index 0000000..6b0b1f1
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-be/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Уваход у сетку Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Увайдзіце ў сетку"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> не мае доступу ў інтэрнэт"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Дакраніцеся, каб убачыць параметры"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мабільная сетка не мае доступу ў інтэрнэт"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Сетка не мае доступу ў інтэрнэт"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> мае абмежаваную магчымасць падключэння"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Націсніце, каб падключыцца"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Прылада выкарыстоўвае сетку <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў сетцы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца плата."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"невядомы тып сеткі"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мабільная перадача даных"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-bg/strings.xml b/service/ServiceConnectivityResources/res/values-bg/strings.xml
new file mode 100644
index 0000000..6427bd0
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-bg/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Влизане в Wi-Fi мрежа"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Вход в мрежата"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> няма достъп до интернет"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Докоснете за опции"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилната мрежа няма достъп до интернет"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежата няма достъп до интернет"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не може да се осъществи достъп до частния DNS сървър"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена свързаност"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Докоснете, за да се свържете въпреки това"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"неизвестен тип мрежа"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобилни данни"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"виртуална частна мрежа (VPN)"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-bn/strings.xml b/service/ServiceConnectivityResources/res/values-bn/strings.xml
new file mode 100644
index 0000000..74d4cd6
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-bn/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ওয়াই-ফাই নেটওয়ার্কে সাইন-ইন করুন"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"নেটওয়ার্কে সাইন-ইন করুন"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর ইন্টারনেটে অ্যাক্সেস নেই"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"মোবাইল নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ব্যক্তিগত ডিএনএস সার্ভার অ্যাক্সেস করা যাবে না"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর সীমিত কানেক্টিভিটি আছে"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"তবুও কানেক্ট করতে ট্যাপ করুন"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এ ইন্টারনেট অ্যাক্সেস না থাকলে <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করা হয়৷ ডেটা চার্জ প্রযোজ্য৷"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"এই নেটওয়ার্কের প্রকার অজানা"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"মোবাইল ডেটা"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ব্লুটুথ"</item>
+ <item msgid="1616528372438698248">"ইথারনেট"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-bs/strings.xml b/service/ServiceConnectivityResources/res/values-bs/strings.xml
new file mode 100644
index 0000000..19f6e1a
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-bs/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavljivanje na WiFi mrežu"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava na mrežu"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nije moguće pristupiti privatnom DNS serveru"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da se ipak povežete"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, uređaj koristi mrežu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznata vrsta mreže"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"prijenos podataka na mobilnoj mreži"</item>
+ <item msgid="5520925862115353992">"WiFi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ca/strings.xml b/service/ServiceConnectivityResources/res/values-ca/strings.xml
new file mode 100644
index 0000000..c55684d
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ca/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Inicia la sessió a la xarxa Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Inicia la sessió a la xarxa"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no té accés a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca per veure les opcions"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"La xarxa mòbil no té accés a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"La xarxa no té accés a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No es pot accedir al servidor DNS privat"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> té una connectivitat limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca per connectar igualment"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'hi apliquin càrrecs."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"una tipus de xarxa desconegut"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dades mòbils"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-cs/strings.xml b/service/ServiceConnectivityResources/res/values-cs/strings.xml
new file mode 100644
index 0000000..fa8c411
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-cs/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Přihlásit se k síti Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Přihlásit se k síti"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá přístup k internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Klepnutím zobrazíte možnosti"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilní síť nemá přístup k internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Síť nemá přístup k internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nelze získat přístup k soukromému serveru DNS"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> umožňuje jen omezené připojení"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Klepnutím se i přesto připojíte"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznámý typ sítě"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilní data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-da/strings.xml b/service/ServiceConnectivityResources/res/values-da/strings.xml
new file mode 100644
index 0000000..f7be6df
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-da/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Log ind på Wi-Fi-netværk"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Log ind på netværk"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetforbindelse"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tryk for at se valgmuligheder"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnetværket har ingen internetadgang"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netværket har ingen internetadgang"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Der er ikke adgang til den private DNS-server"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrænset forbindelse"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tryk for at oprette forbindelse alligevel"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når der ikke er internetadgang via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Der opkræves muligvis betaling."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en ukendt netværkstype"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobildata"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-de/strings.xml b/service/ServiceConnectivityResources/res/values-de/strings.xml
new file mode 100644
index 0000000..1e7b80c
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-de/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"In WLAN anmelden"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Im Netzwerk anmelden"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> hat keinen Internetzugriff"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Für Optionen tippen"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiles Netzwerk hat keinen Internetzugriff"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netzwerk hat keinen Internetzugriff"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Schlechte Verbindung mit <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tippen, um die Verbindung trotzdem herzustellen"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Auf dem Gerät werden <xliff:g id="NEW_NETWORK">%1$s</xliff:g> genutzt, wenn über <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ein unbekannter Netzwerktyp"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"Mobile Daten"</item>
+ <item msgid="5520925862115353992">"WLAN"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-el/strings.xml b/service/ServiceConnectivityResources/res/values-el/strings.xml
new file mode 100644
index 0000000..89647fd
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-el/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Συνδεθείτε στο δίκτυο Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Σύνδεση στο δίκτυο"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Η εφαρμογή <xliff:g id="NETWORK_SSID">%1$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Πατήστε για να δείτε τις επιλογές"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Το δίκτυο κινητής τηλεφωνίας δεν έχει πρόσβαση στο διαδίκτυο."</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Το δίκτυο δεν έχει πρόσβαση στο διαδίκτυο."</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Δεν είναι δυνατή η πρόσβαση στον ιδιωτικό διακομιστή DNS."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Το δίκτυο <xliff:g id="NETWORK_SSID">%1$s</xliff:g> έχει περιορισμένη συνδεσιμότητα"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Πατήστε για σύνδεση ούτως ή άλλως"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Μπορεί να ισχύουν χρεώσεις."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"άγνωστος τύπος δικτύου"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"δεδομένα κινητής τηλεφωνίας"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml b/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml b/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml b/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml b/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..d29e2ec
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to a Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no Internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no Internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml b/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..cd69133
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Sign in to Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Sign in to network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no internet access"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tap for options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobile network has no internet access"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Network has no internet access"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Private DNS server cannot be accessed"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tap to connect anyway"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no internet access. Charges may apply."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"an unknown network type"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml b/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..9102dc0
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Accede a una red Wi-Fi."</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Acceder a la red"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>no tiene acceso a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Presiona para ver opciones"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"La red móvil no tiene acceso a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"La red no tiene acceso a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No se puede acceder al servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene conectividad limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Presiona para conectarte de todas formas"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tipo de red desconocido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"Datos móviles"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-es/strings.xml b/service/ServiceConnectivityResources/res/values-es/strings.xml
new file mode 100644
index 0000000..4c15566
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-es/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Iniciar sesión en red Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Iniciar sesión en la red"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no tiene acceso a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca para ver opciones"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"La red móvil no tiene acceso a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"La red no tiene acceso a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"No se ha podido acceder al servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene una conectividad limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca para conectarte de todas formas"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tipo de red desconocido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"datos móviles"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-et/strings.xml b/service/ServiceConnectivityResources/res/values-et/strings.xml
new file mode 100644
index 0000000..398223a
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-et/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Logi sisse WiFi-võrku"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Võrku sisselogimine"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Võrgul <xliff:g id="NETWORK_SSID">%1$s</xliff:g> puudub Interneti-ühendus"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Puudutage valikute nägemiseks"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiilsidevõrgul puudub Interneti-ühendus"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Võrgul puudub Interneti-ühendus"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Privaatsele DNS-serverile ei pääse juurde"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Võrgu <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ühendus on piiratud"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Puudutage, kui soovite siiski ühenduse luua"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub juurdepääs Internetile. Rakenduda võivad tasud."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tundmatu võrgutüüp"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiilne andmeside"</item>
+ <item msgid="5520925862115353992">"WiFi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-eu/strings.xml b/service/ServiceConnectivityResources/res/values-eu/strings.xml
new file mode 100644
index 0000000..dd70316
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-eu/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Hasi saioa Wi-Fi sarean"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Hasi saioa sarean"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Ezin da konektatu Internetera <xliff:g id="NETWORK_SSID">%1$s</xliff:g> sarearen bidez"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Sakatu aukerak ikusteko"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Sare mugikorra ezin da konektatu Internetera"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Sarea ezin da konektatu Internetera"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ezin da atzitu DNS zerbitzari pribatua"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sareak konektagarritasun murriztua du"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Sakatu hala ere konektatzeko"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"sare mota ezezaguna"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"datu-konexioa"</item>
+ <item msgid="5520925862115353992">"Wifia"</item>
+ <item msgid="1055487873974272842">"Bluetooth-a"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-fa/strings.xml b/service/ServiceConnectivityResources/res/values-fa/strings.xml
new file mode 100644
index 0000000..46a946c
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-fa/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ورود به شبکه Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ورود به سیستم شبکه"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> به اینترنت دسترسی ندارد"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"برای گزینهها ضربه بزنید"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"شبکه تلفن همراه به اینترنت دسترسی ندارد"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"شبکه به اینترنت دسترسی ندارد"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"سرور DNS خصوصی قابل دسترسی نیست"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> اتصال محدودی دارد"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"بههرصورت، برای اتصال ضربه بزنید"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> به اینترنت دسترسی نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده میکند. ممکن است هزینههایی اعمال شود."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نوع شبکه نامشخص"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"داده تلفن همراه"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"بلوتوث"</item>
+ <item msgid="1616528372438698248">"اترنت"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-fi/strings.xml b/service/ServiceConnectivityResources/res/values-fi/strings.xml
new file mode 100644
index 0000000..dd94441
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-fi/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Kirjaudu Wi-Fi-verkkoon"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Kirjaudu verkkoon"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ei ole yhteydessä internetiin"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Näytä vaihtoehdot napauttamalla."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiiliverkko ei ole yhteydessä internetiin"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Verkko ei ole yhteydessä internetiin"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ei pääsyä yksityiselle DNS-palvelimelle"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> toimii rajoitetulla yhteydellä"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Yhdistä napauttamalla"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tuntematon verkon tyyppi"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiilidata"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml b/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..02ef50b
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Connectez-vous au réseau Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Connectez-vous au réseau"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> n\'offre aucun accès à Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Touchez pour afficher les options"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Le réseau cellulaire n\'offre aucun accès à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Le réseau n\'offre aucun accès à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Impossible d\'accéder au serveur DNS privé"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> offre une connectivité limitée"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Touchez pour vous connecter quand même"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un type de réseau inconnu"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"données cellulaires"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"RPV"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-fr/strings.xml b/service/ServiceConnectivityResources/res/values-fr/strings.xml
new file mode 100644
index 0000000..08c9d81
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-fr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Connectez-vous au réseau Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Se connecter au réseau"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Aucune connexion à Internet pour <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Appuyez ici pour afficher des options."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Le réseau mobile ne dispose d\'aucun accès à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Le réseau ne dispose d\'aucun accès à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Impossible d\'accéder au serveur DNS privé"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"La connectivité de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> est limitée"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Appuyer pour se connecter quand même"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais peuvent s\'appliquer."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"type de réseau inconnu"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"données mobiles"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-gl/strings.xml b/service/ServiceConnectivityResources/res/values-gl/strings.xml
new file mode 100644
index 0000000..9f98055
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-gl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Inicia sesión na rede wifi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Inicia sesión na rede"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ten acceso a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toca para ver opcións."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A rede de telefonía móbil non ten acceso a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede non ten acceso a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Non se puido acceder ao servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"A conectividade de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> é limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toca para conectarte de todas formas"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tipo de rede descoñecido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"datos móbiles"</item>
+ <item msgid="5520925862115353992">"wifi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-gu/strings.xml b/service/ServiceConnectivityResources/res/values-gu/strings.xml
new file mode 100644
index 0000000..4ae5a2c
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-gu/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"વાઇ-ફાઇ નેટવર્ક પર સાઇન ઇન કરો"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"નેટવર્ક પર સાઇન ઇન કરો"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"વિકલ્પો માટે ટૅપ કરો"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"મોબાઇલ નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ખાનગી DNS સર્વર ઍક્સેસ કરી શકાતા નથી"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> મર્યાદિત કનેક્ટિવિટી ધરાવે છે"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"છતાં કનેક્ટ કરવા માટે ટૅપ કરો"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g>નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"અજાણ્યો નેટવર્ક પ્રકાર"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"મોબાઇલ ડેટા"</item>
+ <item msgid="5520925862115353992">"વાઇ-ફાઇ"</item>
+ <item msgid="1055487873974272842">"બ્લૂટૂથ"</item>
+ <item msgid="1616528372438698248">"ઇથરનેટ"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-hi/strings.xml b/service/ServiceConnectivityResources/res/values-hi/strings.xml
new file mode 100644
index 0000000..eff1b60
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-hi/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"वाई-फ़ाई नेटवर्क में साइन इन करें"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"नेटवर्क में साइन इन करें"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> का इंटरनेट नहीं चल रहा है"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"विकल्पों के लिए टैप करें"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"इस नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"निजी डीएनएस सर्वर को ऐक्सेस नहीं किया जा सकता"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> की कनेक्टिविटी सीमित है"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"फिर भी कनेक्ट करने के लिए टैप करें"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में इंटरनेट की सुविधा नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का इस्तेमाल करता है. इसके लिए शुल्क लिया जा सकता है."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"अज्ञात नेटवर्क प्रकार"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+ <item msgid="5520925862115353992">"वाई-फ़ाई"</item>
+ <item msgid="1055487873974272842">"ब्लूटूथ"</item>
+ <item msgid="1616528372438698248">"ईथरनेट"</item>
+ <item msgid="9177085807664964627">"वीपीएन"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-hr/strings.xml b/service/ServiceConnectivityResources/res/values-hr/strings.xml
new file mode 100644
index 0000000..52bfb93
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-hr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijava na Wi-Fi mrežu"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava na mrežu"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dodirnite za opcije"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilna mreža nema pristup internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mreža nema pristup internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nije moguće pristupiti privatnom DNS poslužitelju"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dodirnite da biste se ipak povezali"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> > <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznata vrsta mreže"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilni podaci"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-hu/strings.xml b/service/ServiceConnectivityResources/res/values-hu/strings.xml
new file mode 100644
index 0000000..2ff59b5
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-hu/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Bejelentkezés Wi-Fi hálózatba"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Bejelentkezés a hálózatba"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózaton nincs internet-hozzáférés"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Koppintson a beállítások megjelenítéséhez"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A mobilhálózaton nincs internet-hozzáférés"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A hálózaton nincs internet-hozzáférés"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"A privát DNS-kiszolgálóhoz nem lehet hozzáférni"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózat korlátozott kapcsolatot biztosít"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Koppintson, ha mindenképpen csatlakozni szeretne"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internet-hozzáférés <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ismeretlen hálózati típus"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiladatok"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-hy/strings.xml b/service/ServiceConnectivityResources/res/values-hy/strings.xml
new file mode 100644
index 0000000..b35d31c
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-hy/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Մուտք գործեք Wi-Fi ցանց"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Մուտք գործեք ցանց"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցը չունի մուտք ինտերնետին"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Բջջային ցանցը չի ապահովում ինտերնետ կապ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Ցանցը միացված չէ ինտերնետին"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Մասնավոր DNS սերվերն անհասանելի է"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցի կապը սահմանափակ է"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Հպեք՝ միանալու համար"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Երբ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցում ինտերնետ կապ չի լինում, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Նման դեպքում կարող են վճարներ գանձվել:"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ցանցի անհայտ տեսակ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"բջջային ինտերնետ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-in/strings.xml b/service/ServiceConnectivityResources/res/values-in/strings.xml
new file mode 100644
index 0000000..27d7d89
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-in/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Login ke jaringan Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Login ke jaringan"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tidak memiliki akses internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ketuk untuk melihat opsi"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Jaringan seluler tidak memiliki akses internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Jaringan tidak memiliki akses internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Server DNS pribadi tidak dapat diakses"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> memiliki konektivitas terbatas"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ketuk untuk tetap menyambungkan"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"jenis jaringan yang tidak dikenal"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"data seluler"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-is/strings.xml b/service/ServiceConnectivityResources/res/values-is/strings.xml
new file mode 100644
index 0000000..97f42dc
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-is/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Skrá inn á Wi-Fi net"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Skrá inn á net"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> er ekki með internetaðgang"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ýttu til að sjá valkosti"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Farsímakerfið er ekki tengt við internetið"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netkerfið er ekki tengt við internetið"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Ekki næst í DNS-einkaþjón"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Tengigeta <xliff:g id="NETWORK_SSID">%1$s</xliff:g> er takmörkuð"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ýttu til að tengjast samt"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld kunna að eiga við."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"óþekkt tegund netkerfis"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"farsímagögn"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-it/strings.xml b/service/ServiceConnectivityResources/res/values-it/strings.xml
new file mode 100644
index 0000000..7836101
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-it/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Accedi a rete Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Accedi alla rete"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ha accesso a Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tocca per le opzioni"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"La rete mobile non ha accesso a Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"La rete non ha accesso a Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Non è possibile accedere al server DNS privato"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ha una connettività limitata"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tocca per connettere comunque"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"tipo di rete sconosciuto"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dati mobili"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-iw/strings.xml b/service/ServiceConnectivityResources/res/values-iw/strings.xml
new file mode 100644
index 0000000..f322b99
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-iw/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"היכנס לרשת Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"היכנס לרשת"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"ל-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> אין גישה לאינטרנט"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"הקש לקבלת אפשרויות"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"לרשת הסלולרית אין גישה לאינטרנט"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"לרשת אין גישה לאינטרנט"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"לא ניתן לגשת לשרת DNS הפרטי"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"הקישוריות של <xliff:g id="NETWORK_SSID">%1$s</xliff:g> מוגבלת"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"כדי להתחבר למרות זאת יש להקיש"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"סוג רשת לא מזוהה"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"חבילת גלישה"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ja/strings.xml b/service/ServiceConnectivityResources/res/values-ja/strings.xml
new file mode 100644
index 0000000..1aa3216
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ja/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fiネットワークにログイン"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ネットワークにログインしてください"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> はインターネットにアクセスできません"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"タップしてその他のオプションを表示"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"モバイル ネットワークがインターネットに接続されていません"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ネットワークがインターネットに接続されていません"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"プライベート DNS サーバーにアクセスできません"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> の接続が制限されています"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"接続するにはタップしてください"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"デバイスで「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明なネットワーク タイプ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"モバイルデータ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"イーサネット"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ka/strings.xml b/service/ServiceConnectivityResources/res/values-ka/strings.xml
new file mode 100644
index 0000000..61d21b5
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ka/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi ქსელთან დაკავშირება"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ქსელში შესვლა"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ს არ აქვს ინტერნეტზე წვდომა"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"შეეხეთ ვარიანტების სანახავად"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"მობილურ ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"პირად DNS სერვერზე წვდომა შეუძლებელია"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ის კავშირები შეზღუდულია"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"შეეხეთ, თუ მაინც გსურთ დაკავშირება"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"უცნობი ტიპის ქსელი"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"მობილური ინტერნეტი"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-kk/strings.xml b/service/ServiceConnectivityResources/res/values-kk/strings.xml
new file mode 100644
index 0000000..969aaef
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-kk/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi желісіне кіру"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Желіге кіру"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің интернетті пайдалану мүмкіндігі шектеулі."</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Опциялар үшін түртіңіз"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобильдік желі интернетке қосылмаған."</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Желі интернетке қосылмаған."</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Жеке DNS серверіне кіру мүмкін емес."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің қосылу мүмкіндігі шектеулі."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Бәрібір жалғау үшін түртіңіз."</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"желі түрі белгісіз"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобильдік деректер"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-km/strings.xml b/service/ServiceConnectivityResources/res/values-km/strings.xml
new file mode 100644
index 0000000..da3c337
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-km/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ចូលបណ្ដាញវ៉ាយហ្វាយ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ចូលទៅបណ្តាញ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ប៉ះសម្រាប់ជម្រើស"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"បណ្ដាញទូរសព្ទចល័តមិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"បណ្ដាញមិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"មិនអាចចូលប្រើម៉ាស៊ីនមេ DNS ឯកជនបានទេ"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មានការតភ្ជាប់មានកម្រិត"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"មិនអីទេ ចុចភ្ជាប់ចុះ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> មិនមានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតថ្លៃលើការប្រើប្រាស់ទិន្នន័យ។"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ប្រភេទបណ្តាញមិនស្គាល់"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ទិន្នន័យទូរសព្ទចល័ត"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ប៊្លូធូស"</item>
+ <item msgid="1616528372438698248">"អ៊ីសឺរណិត"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-kn/strings.xml b/service/ServiceConnectivityResources/res/values-kn/strings.xml
new file mode 100644
index 0000000..3b5e047
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-kn/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ನೆಟ್ವರ್ಕ್ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ಖಾಸಗಿ DNS ಸರ್ವರ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಸೀಮಿತ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿದೆ"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ಹೇಗಾದರೂ ಸಂಪರ್ಕಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ಅಪರಿಚಿತ ನೆಟ್ವರ್ಕ್ ಪ್ರಕಾರ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ಮೊಬೈಲ್ ಡೇಟಾ"</item>
+ <item msgid="5520925862115353992">"ವೈ-ಫೈ"</item>
+ <item msgid="1055487873974272842">"ಬ್ಲೂಟೂತ್"</item>
+ <item msgid="1616528372438698248">"ಇಥರ್ನೆಟ್"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ko/strings.xml b/service/ServiceConnectivityResources/res/values-ko/strings.xml
new file mode 100644
index 0000000..874bd75
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ko/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi 네트워크에 로그인"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"네트워크에 로그인"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>이(가) 인터넷에 액세스할 수 없습니다."</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"탭하여 옵션 보기"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"모바일 네트워크에 인터넷이 연결되어 있지 않습니다."</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"네트워크에 인터넷이 연결되어 있지 않습니다."</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"비공개 DNS 서버에 액세스할 수 없습니다."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>에서 연결을 제한했습니다."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"계속 연결하려면 탭하세요."</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>(으)로 인터넷에 연결할 수 없는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>이(가) 사용됩니다. 요금이 부과될 수 있습니다."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"알 수 없는 네트워크 유형"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"모바일 데이터"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"블루투스"</item>
+ <item msgid="1616528372438698248">"이더넷"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ky/strings.xml b/service/ServiceConnectivityResources/res/values-ky/strings.xml
new file mode 100644
index 0000000..1ace4dc
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ky/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi түйүнүнө кирүү"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Тармакка кирүү"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> Интернетке туташуусу жок"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилдик Интернет жок"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Тармактын Интернет жок"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Жеке DNS сервери жеткиликсиз"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> байланышы чектелген"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Баары бир туташуу үчүн таптаңыз"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"белгисиз тармак түрү"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобилдик трафик"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-lo/strings.xml b/service/ServiceConnectivityResources/res/values-lo/strings.xml
new file mode 100644
index 0000000..3db497e
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-lo/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ເຄືອຂ່າຍມືຖືບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ເຄືອຂ່າຍບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ບໍ່ສາມາດເຂົ້າເຖິງເຊີບເວີ DNS ສ່ວນຕົວໄດ້"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ມີການເຊື່ອມຕໍ່ທີ່ຈຳກັດ"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ແຕະເພື່ອຢືນຢັນການເຊື່ອມຕໍ່"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ອິນເຕີເນັດມືຖື"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"ອີເທີເນັດ"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-lt/strings.xml b/service/ServiceConnectivityResources/res/values-lt/strings.xml
new file mode 100644
index 0000000..c639c1f
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-lt/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prisijungti prie „Wi-Fi“ tinklo"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prisijungti prie tinklo"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ negali pasiekti interneto"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Palieskite, kad būtų rodomos parinktys."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiliojo ryšio tinkle nėra prieigos prie interneto"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Tinkle nėra prieigos prie interneto"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Privataus DNS serverio negalima pasiekti"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ ryšys apribotas"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Palieskite, jei vis tiek norite prisijungti"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Įrenginyje naudojamas kitas tinklas (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>), kai dabartiniame tinkle (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nežinomas tinklo tipas"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiliojo ryšio duomenys"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Eternetas"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-lv/strings.xml b/service/ServiceConnectivityResources/res/values-lv/strings.xml
new file mode 100644
index 0000000..5774603
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-lv/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Pierakstieties Wi-Fi tīklā"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Pierakstīšanās tīklā"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nav piekļuves internetam"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Pieskarieties, lai skatītu iespējas."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilajā tīklā nav piekļuves internetam."</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Tīklā nav piekļuves internetam."</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Nevar piekļūt privātam DNS serverim."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ir ierobežota savienojamība"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Lai tik un tā izveidotu savienojumu, pieskarieties"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kad vienā tīklā (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nav piekļuves internetam, ierīcē tiek izmantots cits tīkls (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>). Var tikt piemērota maksa."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nezināms tīkla veids"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilie dati"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml b/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+ <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+ Internet access. Actual device behaviour is controlled by
+ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml b/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+ <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+ Internet access. Actual device behaviour is controlled by
+ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
new file mode 100644
index 0000000..7e7025f
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+ <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+ Internet access. Actual device behaviour is controlled by
+ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
+</resources>
\ No newline at end of file
diff --git a/service/ServiceConnectivityResources/res/values-mk/strings.xml b/service/ServiceConnectivityResources/res/values-mk/strings.xml
new file mode 100644
index 0000000..053c7cf
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mk/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Најавете се на мрежа на Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Најавете се на мрежа"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема интернет-пристап"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Допрете за опции"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилната мрежа нема интернет-пристап"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежата нема интернет-пристап"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Не може да се пристапи до приватниот DNS-сервер"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена поврзливост"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Допрете за да се поврзете и покрај тоа"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"непознат тип мрежа"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобилен интернет"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Етернет"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ml/strings.xml b/service/ServiceConnectivityResources/res/values-ml/strings.xml
new file mode 100644
index 0000000..3e80cf1
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ml/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"വൈഫൈ നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"മൊബെെൽ നെറ്റ്വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"നെറ്റ്വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"സ്വകാര്യ DNS സെർവർ ആക്സസ് ചെയ്യാനാവില്ല"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് പരിമിതമായ കണക്റ്റിവിറ്റി ഉണ്ട്"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ഏതുവിധേനയും കണക്റ്റ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-ന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്വർക്കിലേക്ക് മാറി"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"തിരിച്ചറിയാനാകാത്ത ഒരു നെറ്റ്വർക്ക് തരം"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"മൊബൈൽ ഡാറ്റ"</item>
+ <item msgid="5520925862115353992">"വൈഫൈ"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"ഇതര്നെറ്റ്"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-mn/strings.xml b/service/ServiceConnectivityResources/res/values-mn/strings.xml
new file mode 100644
index 0000000..214fc0c
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mn/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi сүлжээнд нэвтэрнэ үү"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Сүлжээнд нэвтэрнэ үү"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-д интернэтийн хандалт алга"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Сонголт хийхийн тулд товшино уу"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобайл сүлжээнд интернэт хандалт байхгүй байна"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Сүлжээнд интернэт хандалт байхгүй байна"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Хувийн DNS серверт хандах боломжгүй байна"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> зарим үйлчилгээнд хандах боломжгүй байна"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ямар ч тохиолдолд холбогдохын тулд товших"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернет холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"сүлжээний тодорхойгүй төрөл"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобайл дата"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Этернэт"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-mr/strings.xml b/service/ServiceConnectivityResources/res/values-mr/strings.xml
new file mode 100644
index 0000000..c4b1998
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-mr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"वाय-फाय नेटवर्कमध्ये साइन इन करा"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"नेटवर्कवर साइन इन करा"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला इंटरनेट अॅक्सेस नाही"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"पर्यायांसाठी टॅप करा"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"खाजगी DNS सर्व्हर ॲक्सेस करू शकत नाही"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला मर्यादित कनेक्टिव्हिटी आहे"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"तरीही कनेक्ट करण्यासाठी टॅप करा"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेटचा अॅक्सेस नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरते. शुल्क लागू शकते."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"अज्ञात नेटवर्क प्रकार"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+ <item msgid="5520925862115353992">"वाय-फाय"</item>
+ <item msgid="1055487873974272842">"ब्लूटूथ"</item>
+ <item msgid="1616528372438698248">"इथरनेट"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ms/strings.xml b/service/ServiceConnectivityResources/res/values-ms/strings.xml
new file mode 100644
index 0000000..529d0bd
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ms/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Log masuk ke rangkaian Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Log masuk ke rangkaian"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiada akses Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Ketik untuk mendapatkan pilihan"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Rangkaian mudah alih tiada akses Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Rangkaian tiada akses Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Pelayan DNS peribadi tidak boleh diakses"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> mempunyai kesambungan terhad"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ketik untuk menyambung juga"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"jenis rangkaian tidak diketahui"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"data mudah alih"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-my/strings.xml b/service/ServiceConnectivityResources/res/values-my/strings.xml
new file mode 100644
index 0000000..50590fa
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-my/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ဝိုင်ဖိုင်ကွန်ရက်သို့ လက်မှတ်ထိုးဝင်ပါ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"မိုဘိုင်းကွန်ရက်တွင် အင်တာနက်ချိတ်ဆက်မှု မရှိပါ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ကွန်ရက်တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"သီးသန့် ဒီအန်အက်စ် (DNS) ဆာဗာကို သုံး၍မရပါ။"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် ချိတ်ဆက်မှုကို ကန့်သတ်ထားသည်"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"မည်သို့ပင်ဖြစ်စေ ချိတ်ဆက်ရန် တို့ပါ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် စက်ပစ္စည်းသည် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"မိုဘိုင်းဒေတာ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ဘလူးတုသ်"</item>
+ <item msgid="1616528372438698248">"အီသာနက်"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-nb/strings.xml b/service/ServiceConnectivityResources/res/values-nb/strings.xml
new file mode 100644
index 0000000..b89d198
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-nb/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Logg på Wi-Fi-nettverket"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Logg på nettverk"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internettilkobling"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Trykk for å få alternativer"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnettverket har ingen internettilgang"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Nettverket har ingen internettilgang"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Den private DNS-tjeneren kan ikke nås"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrenset tilkobling"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Trykk for å koble til likevel"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en ukjent nettverkstype"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobildata"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ne/strings.xml b/service/ServiceConnectivityResources/res/values-ne/strings.xml
new file mode 100644
index 0000000..bdcfa3b
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ne/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi नेटवर्कमा साइन इन गर्नुहोस्"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"सञ्जालमा साइन इन गर्नुहोस्"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को इन्टरनेटमाथि पहुँच छैन"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"मोबाइल नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"निजी DNS सर्भरमाथि पहुँच प्राप्त गर्न सकिँदैन"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को जडान सीमित छ"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"जसरी भए पनि जडान गर्न ट्याप गर्नुहोस्"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मार्फत इन्टरनेटमाथि पहुँच राख्न नसकेको अवस्थामा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> प्रयोग गर्दछ। शुल्क लाग्न सक्छ।"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"मोबाइल डेटा"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"ब्लुटुथ"</item>
+ <item msgid="1616528372438698248">"इथरनेट"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-nl/strings.xml b/service/ServiceConnectivityResources/res/values-nl/strings.xml
new file mode 100644
index 0000000..8ecff6e
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-nl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Inloggen bij wifi-netwerk"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Inloggen bij netwerk"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft geen internettoegang"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tik voor opties"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobiel netwerk heeft geen internettoegang"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Netwerk heeft geen internettoegang"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Geen toegang tot privé-DNS-server"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft beperkte connectiviteit"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tik om toch verbinding te maken"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"een onbekend netwerktype"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobiele data"</item>
+ <item msgid="5520925862115353992">"Wifi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-or/strings.xml b/service/ServiceConnectivityResources/res/values-or/strings.xml
new file mode 100644
index 0000000..6ec1f9d
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-or/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ୱାଇ-ଫାଇ ନେଟୱର୍କରେ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ନେଟ୍ୱର୍କରେ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ବିକଳ୍ପ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ମୋବାଇଲ୍ ନେଟ୍ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ନେଟ୍ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ବ୍ୟକ୍ତିଗତ DNS ସର୍ଭର୍ ଆକ୍ସେସ୍ କରିହେବ ନାହିଁ"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ସୀମିତ ସଂଯୋଗ ଅଛି"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ତଥାପି ଯୋଗାଯୋଗ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ର ଇଣ୍ଟରନେଟ୍ ଆକ୍ସେସ୍ ନଥିବାବେଳେ ଡିଭାଇସ୍ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ବ୍ୟବହାର କରିଥାଏ। ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ।"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ରୁ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ଏକ ଅଜଣା ନେଟ୍ୱର୍କ ପ୍ରକାର"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ମୋବାଇଲ୍ ଡାଟା"</item>
+ <item msgid="5520925862115353992">"ୱାଇ-ଫାଇ"</item>
+ <item msgid="1055487873974272842">"ବ୍ଲୁଟୁଥ"</item>
+ <item msgid="1616528372438698248">"ଇଥରନେଟ୍"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-pa/strings.xml b/service/ServiceConnectivityResources/res/values-pa/strings.xml
new file mode 100644
index 0000000..e948193
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-pa/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ਨਿੱਜੀ ਡੋਮੇਨ ਨਾਮ ਪ੍ਰਣਾਲੀ (DNS) ਸਰਵਰ \'ਤੇ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਸੀਮਤ ਕਨੈਕਟੀਵਿਟੀ ਹੈ"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ਫਿਰ ਵੀ ਕਨੈਕਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ਮੋਬਾਈਲ ਡਾਟਾ"</item>
+ <item msgid="5520925862115353992">"ਵਾਈ-ਫਾਈ"</item>
+ <item msgid="1055487873974272842">"ਬਲੂਟੁੱਥ"</item>
+ <item msgid="1616528372438698248">"ਈਥਰਨੈੱਟ"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-pl/strings.xml b/service/ServiceConnectivityResources/res/values-pl/strings.xml
new file mode 100644
index 0000000..038328f
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-pl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Zaloguj się w sieci Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Zaloguj się do sieci"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nie ma dostępu do internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Kliknij, by wyświetlić opcje"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Sieć komórkowa nie ma dostępu do internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Sieć nie ma dostępu do internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Brak dostępu do prywatnego serwera DNS"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ma ograniczoną łączność"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Kliknij, by mimo to nawiązać połączenie"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nieznany typ sieci"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilna transmisja danych"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml b/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..fe37405
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Fazer login na rede Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Fazer login na rede"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para ver opções"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível acessar o servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para conectar mesmo assim"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dados móveis"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml b/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..69060f7
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Iniciar sessão na rede Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Início de sessão na rede"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para obter mais opções"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível aceder ao servidor DNS."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conetividade limitada."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para ligar mesmo assim."</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem aplicar-se custos."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dados móveis"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-pt/strings.xml b/service/ServiceConnectivityResources/res/values-pt/strings.xml
new file mode 100644
index 0000000..fe37405
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-pt/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Fazer login na rede Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Fazer login na rede"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Toque para ver opções"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"A rede móvel não tem acesso à Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"A rede não tem acesso à Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Não é possível acessar o servidor DNS privado"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Toque para conectar mesmo assim"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"um tipo de rede desconhecido"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dados móveis"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ro/strings.xml b/service/ServiceConnectivityResources/res/values-ro/strings.xml
new file mode 100644
index 0000000..227b7be
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ro/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Conectați-vă la rețeaua Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Conectați-vă la rețea"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nu are acces la internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Atingeți pentru opțiuni"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Rețeaua mobilă nu are acces la internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Rețeaua nu are acces la internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Serverul DNS privat nu poate fi accesat"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> are conectivitate limitată"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Atingeți pentru a vă conecta oricum"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tip de rețea necunoscut"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"date mobile"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ru/strings.xml b/service/ServiceConnectivityResources/res/values-ru/strings.xml
new file mode 100644
index 0000000..18acf81
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ru/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Подключение к Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Регистрация в сети"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Сеть \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" не подключена к Интернету"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Нажмите, чтобы показать варианты."</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобильная сеть не подключена к Интернету"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Сеть не подключена к Интернету"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Доступа к частному DNS-серверу нет."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Подключение к сети \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" ограничено"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Нажмите, чтобы подключиться"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"неизвестный тип сети"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобильный Интернет"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-si/strings.xml b/service/ServiceConnectivityResources/res/values-si/strings.xml
new file mode 100644
index 0000000..6307c2b
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-si/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi ජාලයට පුරනය වන්න"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ජාලයට පුරනය වන්න"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට අන්තර්ජාල ප්රවේශය නැත"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"විකල්ප සඳහා තට්ටු කරන්න"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"ජංගම ජාලවලට අන්තර්ජාල ප්රවේශය නැත"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"ජාලයට අන්තර්ජාල ප්රවේශය නැත"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"පුද්ගලික DNS සේවාදායකයට ප්රවේශ වීමට නොහැකිය"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට සීමිත සබැඳුම් හැකියාවක් ඇත"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"කෙසේ වෙතත් ඉදිරියට යාමට තට්ටු කරන්න"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"නොදන්නා ජාල වර්ගයකි"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"ජංගම දත්ත"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"බ්ලූටූත්"</item>
+ <item msgid="1616528372438698248">"ඊතර්නෙට්"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-sk/strings.xml b/service/ServiceConnectivityResources/res/values-sk/strings.xml
new file mode 100644
index 0000000..e894fef
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-sk/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prihlásiť sa do siete Wi‑Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prihlásenie do siete"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá prístup k internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Klepnutím získate možnosti"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilná sieť nemá prístup k internetu"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Sieť nemá prístup k internetu"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"K súkromnému serveru DNS sa nepodarilo získať prístup"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> má obmedzené pripojenie"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Ak sa chcete aj napriek tomu pripojiť, klepnite"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Keď <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznámy typ siete"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobilné dáta"</item>
+ <item msgid="5520925862115353992">"Wi‑Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-sl/strings.xml b/service/ServiceConnectivityResources/res/values-sl/strings.xml
new file mode 100644
index 0000000..954b324
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-sl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Prijavite se v omrežje Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Prijava v omrežje"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Omrežje <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nima dostopa do interneta"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Dotaknite se za možnosti"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilno omrežje nima dostopa do interneta"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Omrežje nima dostopa do interneta"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Do zasebnega strežnika DNS ni mogoče dostopati"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Povezljivost omrežja <xliff:g id="NETWORK_SSID">%1$s</xliff:g> je omejena"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Dotaknite se, da kljub temu vzpostavite povezavo"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"neznana vrsta omrežja"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"prenos podatkov v mobilnem omrežju"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-sq/strings.xml b/service/ServiceConnectivityResources/res/values-sq/strings.xml
new file mode 100644
index 0000000..bd5d052
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-sq/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Identifikohu në rrjetin Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Identifikohu në rrjet"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nuk ka qasje në internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Trokit për opsionet"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Rrjeti celular nuk ka qasje në internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Rrjeti nuk ka qasje në internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Serveri privat DNS nuk mund të qaset"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ka lidhshmëri të kufizuar"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Trokit për t\'u lidhur gjithsesi"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"një lloj rrjeti i panjohur"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"të dhënat celulare"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Eternet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-sr/strings.xml b/service/ServiceConnectivityResources/res/values-sr/strings.xml
new file mode 100644
index 0000000..8bedbff
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-sr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Пријављивање на WiFi мрежу"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Пријавите се на мрежу"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема приступ интернету"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Додирните за опције"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилна мрежа нема приступ интернету"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Мрежа нема приступ интернету"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Приступ приватном DNS серверу није успео"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничену везу"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Додирните да бисте се ипак повезали"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"непознат тип мреже"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобилни подаци"</item>
+ <item msgid="5520925862115353992">"WiFi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Етернет"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-sv/strings.xml b/service/ServiceConnectivityResources/res/values-sv/strings.xml
new file mode 100644
index 0000000..b3f1763
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-sv/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Logga in på ett Wi-Fi-nätverk"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Logga in på nätverket"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetanslutning"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Tryck för alternativ"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobilnätverket har ingen internetanslutning"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Nätverket har ingen internetanslutning"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Det går inte att komma åt den privata DNS-servern."</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begränsad anslutning"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Tryck för att ansluta ändå"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"en okänd nätverkstyp"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobildata"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-sw/strings.xml b/service/ServiceConnectivityResources/res/values-sw/strings.xml
new file mode 100644
index 0000000..9674654
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-sw/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Ingia kwa mtandao wa Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Ingia katika mtandao"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> haina uwezo wa kufikia intaneti"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Gusa ili upate chaguo"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mtandao wa simu hauna uwezo wa kufikia intaneti"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mtandao hauna uwezo wa kufikia intaneti"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Seva ya faragha ya DNS haiwezi kufikiwa"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ina muunganisho unaofikia huduma chache."</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Gusa ili uunganishe tu"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina intaneti. Huenda ukalipishwa."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"aina ya mtandao isiyojulikana"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"data ya simu"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethaneti"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ta/strings.xml b/service/ServiceConnectivityResources/res/values-ta/strings.xml
new file mode 100644
index 0000000..12604cb
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ta/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"வைஃபை நெட்வொர்க்கில் உள்நுழையவும்"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"விருப்பங்களுக்கு, தட்டவும்"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"மொபைல் நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"தனிப்பட்ட DNS சேவையகத்தை அணுக இயலாது"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> வரம்பிற்கு உட்பட்ட இணைப்புநிலையைக் கொண்டுள்ளது"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"எப்படியேனும் இணைப்பதற்குத் தட்டவும்"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> நெட்வொர்க்கில் இண்டர்நெட் அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g> நெட்வொர்க்கைப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"தெரியாத நெட்வொர்க் வகை"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"மொபைல் டேட்டா"</item>
+ <item msgid="5520925862115353992">"வைஃபை"</item>
+ <item msgid="1055487873974272842">"புளூடூத்"</item>
+ <item msgid="1616528372438698248">"ஈத்தர்நெட்"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-te/strings.xml b/service/ServiceConnectivityResources/res/values-te/strings.xml
new file mode 100644
index 0000000..84a8640
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-te/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"ఎంపికల కోసం నొక్కండి"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"మొబైల్ నెట్వర్క్కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"నెట్వర్క్కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"ప్రైవేట్ DNS సర్వర్ను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> పరిమిత కనెక్టివిటీని కలిగి ఉంది"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"ఏదేమైనా కనెక్ట్ చేయడానికి నొక్కండి"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"తెలియని నెట్వర్క్ రకం"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"మొబైల్ డేటా"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"బ్లూటూత్"</item>
+ <item msgid="1616528372438698248">"ఈథర్నెట్"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-th/strings.xml b/service/ServiceConnectivityResources/res/values-th/strings.xml
new file mode 100644
index 0000000..1616e51
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-th/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"ลงชื่อเข้าใช้เครือข่าย"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"แตะเพื่อดูตัวเลือก"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"เครือข่ายมือถือไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"เครือข่ายไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"เข้าถึงเซิร์ฟเวอร์ DNS ไม่ได้"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> มีการเชื่อมต่อจำกัด"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"แตะเพื่อเชื่อมต่อ"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้ โดยอาจมีค่าบริการ"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"เน็ตมือถือ"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"บลูทูธ"</item>
+ <item msgid="1616528372438698248">"อีเทอร์เน็ต"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-tl/strings.xml b/service/ServiceConnectivityResources/res/values-tl/strings.xml
new file mode 100644
index 0000000..3bf1ce4
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-tl/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Mag-sign in sa Wi-Fi network"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Mag-sign in sa network"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Walang access sa internet ang <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"I-tap para sa mga opsyon"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Walang access sa internet ang mobile network"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Walang access sa internet ang network"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Hindi ma-access ang pribadong DNS server"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Limitado ang koneksyon ng <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"I-tap para kumonekta pa rin"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"isang hindi kilalang uri ng network"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobile data"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-tr/strings.xml b/service/ServiceConnectivityResources/res/values-tr/strings.xml
new file mode 100644
index 0000000..5c326e5
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-tr/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Kablosuz ağda oturum açın"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Ağda oturum açın"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ağının internet bağlantısı yok"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Seçenekler için dokunun"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil ağın internet bağlantısı yok"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Ağın internet bağlantısı yok"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Gizli DNS sunucusuna erişilemiyor"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sınırlı bağlantıya sahip"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Yine de bağlanmak için dokunun"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının internet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"bilinmeyen ağ türü"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobil veri"</item>
+ <item msgid="5520925862115353992">"Kablosuz"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-uk/strings.xml b/service/ServiceConnectivityResources/res/values-uk/strings.xml
new file mode 100644
index 0000000..d1382da
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-uk/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Вхід у мережу Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Вхід у мережу"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"Мережа <xliff:g id="NETWORK_SSID">%1$s</xliff:g> не має доступу до Інтернету"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Торкніться, щоб відкрити опції"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Мобільна мережа не має доступу до Інтернету"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Мережа не має доступу до Інтернету"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Немає доступу до приватного DNS-сервера"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"Підключення до мережі <xliff:g id="NETWORK_SSID">%1$s</xliff:g> обмежено"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Натисніть, щоб усе одно підключитися"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету, використовується <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Може стягуватися плата."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"невідомий тип мережі"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"мобільне передавання даних"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"Мережа VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-ur/strings.xml b/service/ServiceConnectivityResources/res/values-ur/strings.xml
new file mode 100644
index 0000000..3c031ad
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-ur/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi نیٹ ورک میں سائن ان کریں"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"نیٹ ورک میں سائن ان کریں"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"اختیارات کیلئے تھپتھپائیں"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"موبائل نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"نجی DNS سرور تک رسائی حاصل نہیں کی جا سکی"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کی کنیکٹوٹی محدود ہے"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"بہر حال منسلک کرنے کے لیے تھپتھپائیں"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کو انٹرنیٹ تک رسائی نہیں ہوتی ہے تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کا استعمال کرتا ہے۔ چارجز لاگو ہو سکتے ہیں۔"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"نیٹ ورک کی نامعلوم قسم"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"موبائل ڈیٹا"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"بلوٹوتھ"</item>
+ <item msgid="1616528372438698248">"ایتھرنیٹ"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-uz/strings.xml b/service/ServiceConnectivityResources/res/values-uz/strings.xml
new file mode 100644
index 0000000..7518db3
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-uz/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Wi-Fi tarmoqqa kirish"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Tarmoqqa kirish"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda internetga ruxsati yoʻq"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Variantlarni ko‘rsatish uchun bosing"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mobil tarmoq internetga ulanmagan"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Tarmoq internetga ulanmagan"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Xususiy DNS server ishlamayapti"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda aloqa cheklangan"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Baribir ulash uchun bosing"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Yangi ulanish: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Agar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmoqda internet uzilsa, qurilma <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ga ulanadi. Sarflangan trafik uchun haq olinishi mumkin."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"noma’lum tarmoq turi"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"mobil internet"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-vi/strings.xml b/service/ServiceConnectivityResources/res/values-vi/strings.xml
new file mode 100644
index 0000000..d2284d4
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-vi/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Đăng nhập vào mạng Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Đăng nhập vào mạng"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> không có quyền truy cập Internet"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Nhấn để biết tùy chọn"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Mạng di động không có quyền truy cập Internet"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Mạng không có quyền truy cập Internet"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Không thể truy cập máy chủ DNS riêng tư"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> có khả năng kết nối giới hạn"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Nhấn để tiếp tục kết nối"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"loại mạng không xác định"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"dữ liệu di động"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"Bluetooth"</item>
+ <item msgid="1616528372438698248">"Ethernet"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml b/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..813482b
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"登录到WLAN网络"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"登录到网络"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 无法访问互联网"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"点按即可查看相关选项"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"此移动网络无法访问互联网"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"此网络无法访问互联网"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"无法访问私人 DNS 服务器"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的连接受限"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"点按即可继续连接"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"设备会在<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>无法访问互联网时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"未知网络类型"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"移动数据"</item>
+ <item msgid="5520925862115353992">"WLAN"</item>
+ <item msgid="1055487873974272842">"蓝牙"</item>
+ <item msgid="1616528372438698248">"以太网"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml b/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..676404f
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"登入 Wi-Fi 網絡"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"登入網絡"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>未有連接至互聯網"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"輕按即可查看選項"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"流動網絡並未連接互聯網"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"網絡並未連接互聯網"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"無法存取私人 DNS 伺服器"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>連線受限"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"仍要輕按以連結至此網絡"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"裝置會在 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 無法連線至互聯網時使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明網絡類型"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"流動數據"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"藍牙"</item>
+ <item msgid="1616528372438698248">"以太網"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml b/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..f355138
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"登入 Wi-Fi 網路"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"登入網路"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 沒有網際網路連線"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"輕觸即可查看選項"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"這個行動網路沒有網際網路連線"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"這個網路沒有網際網路連線"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"無法存取私人 DNS 伺服器"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的連線能力受限"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"輕觸即可繼續連線"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"裝置會在無法連上「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」時切換至「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」(可能需要支付相關費用)。"</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"不明的網路類型"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"行動數據"</item>
+ <item msgid="5520925862115353992">"Wi-Fi"</item>
+ <item msgid="1055487873974272842">"藍牙"</item>
+ <item msgid="1616528372438698248">"乙太網路"</item>
+ <item msgid="9177085807664964627">"VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values-zu/strings.xml b/service/ServiceConnectivityResources/res/values-zu/strings.xml
new file mode 100644
index 0000000..55fefb7
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values-zu/strings.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="wifi_available_sign_in" msgid="381054692557675237">"Ngena ngemvume kunethiwekhi ye-Wi-Fi"</string>
+ <string name="network_available_sign_in" msgid="1520342291829283114">"Ngena ngemvume kunethiwekhi"</string>
+ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) -->
+ <string name="wifi_no_internet" msgid="1386911698276448061">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ayinakho ukufinyelela kwe-inthanethi"</string>
+ <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Thepha ukuze uthole izinketho"</string>
+ <string name="mobile_no_internet" msgid="4014455157529909781">"Inethiwekhi yeselula ayinakho ukufinyelela kwe-inthanethi"</string>
+ <string name="other_networks_no_internet" msgid="6698711684200067033">"Inethiwekhi ayinakho ukufinyelela kwenethiwekhi"</string>
+ <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Iseva eyimfihlo ye-DNS ayikwazi ukufinyelelwa"</string>
+ <string name="network_partial_connectivity" msgid="4791024923851432291">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> inokuxhumeka okukhawulelwe"</string>
+ <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Thepha ukuze uxhume noma kunjalo"</string>
+ <string name="network_switch_metered" msgid="1531869544142283384">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
+ <string name="network_switch_metered_detail" msgid="1358296010128405906">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> inganakho ukufinyelela kwe-inthanethi. Kungasebenza izindleko."</string>
+ <string name="network_switch_metered_toast" msgid="501662047275723743">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
+ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"uhlobo olungaziwa lwenethiwekhi"</string>
+ <string-array name="network_switch_type_name">
+ <item msgid="2255670471736226365">"idatha yeselula"</item>
+ <item msgid="5520925862115353992">"I-Wi-Fi"</item>
+ <item msgid="1055487873974272842">"I-Bluetooth"</item>
+ <item msgid="1616528372438698248">"I-Ethernet"</item>
+ <item msgid="9177085807664964627">"I-VPN"</item>
+ </string-array>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml
new file mode 100644
index 0000000..71674e4
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values/config.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Configuration values for ConnectivityService
+ DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
+ Overlay package following the overlayable.xml configuration in the same directory:
+ https://source.android.com/devices/architecture/rros -->
+<resources>
+
+ <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
+ If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+ and if that value is empty, the framework will use a hard-coded default.
+ This is *NOT* a URL that will always be used by the system network validation to detect
+ captive portals: NetworkMonitor may use different strategies and will not necessarily use
+ this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
+ instead. -->
+ <!--suppress CheckTagEmptyBody -->
+ <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
+
+ <!-- The maximum duration (in milliseconds) we expect a network transition to take -->
+ <integer name="config_networkTransitionTimeout">60000</integer>
+
+ <!-- Configuration of network interfaces that support WakeOnLAN -->
+ <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
+ <!--
+ <item>wlan0</item>
+ <item>eth0</item>
+ -->
+ </string-array>
+
+ <string-array translatable="false" name="config_legacy_networktype_restore_timers">
+ <item>2,60000</item><!-- mobile_mms -->
+ <item>3,60000</item><!-- mobile_supl -->
+ <item>4,60000</item><!-- mobile_dun -->
+ <item>5,60000</item><!-- mobile_hipri -->
+ <item>10,60000</item><!-- mobile_fota -->
+ <item>11,60000</item><!-- mobile_ims -->
+ <item>12,60000</item><!-- mobile_cbs -->
+ </string-array>
+
+ <!-- Whether the APF Filter in the device should filter out IEEE 802.3 Frames
+ Those frames are identified by the field Eth-type having values
+ less than 0x600 -->
+ <bool translatable="false" name="config_apfDrop802_3Frames">true</bool>
+
+ <!-- An array of Denylisted EtherType, packets with EtherTypes within this array
+ will be dropped
+ TODO: need to put proper values, these are for testing purposes only -->
+ <integer-array translatable="false" name="config_apfEthTypeDenyList">
+ <item>0x88A2</item>
+ <item>0x88A4</item>
+ <item>0x88B8</item>
+ <item>0x88CD</item>
+ <item>0x88E3</item>
+ </integer-array>
+
+ <!-- Default supported concurrent socket keepalive slots per transport type, used by
+ ConnectivityManager.createSocketKeepalive() for calculating the number of keepalive
+ offload slots that should be reserved for privileged access. This string array should be
+ overridden by the device to present the capability of creating socket keepalives. -->
+ <!-- An Array of "[NetworkCapabilities.TRANSPORT_*],[supported keepalives] -->
+ <string-array translatable="false" name="config_networkSupportedKeepaliveCount">
+ <item>0,1</item>
+ <item>1,3</item>
+ </string-array>
+
+
+ <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
+ device behaviour is controlled by the metered multipath preference in
+ ConnectivitySettingsManager. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkMeteredMultipathPreference">0</integer>
+
+ <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
+ Internet access. Actual device behaviour is controlled by
+ Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
+ <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
+
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml
new file mode 100644
index 0000000..25e19ce
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <overlayable name="ServiceConnectivityResourcesConfig">
+ <policy type="product|system|vendor">
+ <!-- Configuration values for ConnectivityService -->
+ <item type="array" name="config_legacy_networktype_restore_timers"/>
+ <item type="string" name="config_networkCaptivePortalServerUrl"/>
+ <item type="integer" name="config_networkTransitionTimeout"/>
+ <item type="array" name="config_wakeonlan_supported_interfaces"/>
+ <item type="bool" name="config_apfDrop802_3Frames"/>
+ <item type="array" name="config_apfEthTypeDenyList"/>
+ <item type="integer" name="config_networkMeteredMultipathPreference"/>
+ <item type="array" name="config_networkSupportedKeepaliveCount"/>
+ <item type="integer" name="config_networkAvoidBadWifi"/>
+
+ </policy>
+ </overlayable>
+</resources>
diff --git a/service/ServiceConnectivityResources/res/values/strings.xml b/service/ServiceConnectivityResources/res/values/strings.xml
new file mode 100644
index 0000000..b2fa5f5
--- /dev/null
+++ b/service/ServiceConnectivityResources/res/values/strings.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- The System Connectivity Resources package is an internal system package that provides
+ configuration values for system networking that were pre-configured in the device. This
+ is the name of the package to display in the list of system apps. [CHAR LIMIT=40] -->
+ <string name="connectivityResourcesAppLabel">System Connectivity Resources</string>
+
+ <!-- A notification is shown when a wifi captive portal network is detected. This is the notification's title. -->
+ <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
+
+ <!-- A notification is shown when a captive portal network is detected. This is the notification's title. -->
+ <string name="network_available_sign_in">Sign in to network</string>
+
+ <!-- A notification is shown when a captive portal network is detected. This is the notification's message. -->
+ <string name="network_available_sign_in_detailed"><xliff:g id="network_ssid">%1$s</xliff:g></string>
+
+ <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's title. -->
+ <string name="wifi_no_internet"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has no internet access</string>
+
+ <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
+ <string name="wifi_no_internet_detailed">Tap for options</string>
+
+ <!-- A notification is shown when the user connects to a mobile network without internet access. This is the notification's title. -->
+ <string name="mobile_no_internet">Mobile network has no internet access</string>
+
+ <!-- A notification is shown when the user connects to a non-mobile and non-wifi network without internet access. This is the notification's title. -->
+ <string name="other_networks_no_internet">Network has no internet access</string>
+
+ <!-- A notification is shown when connected network without internet due to private dns validation failed. This is the notification's message. [CHAR LIMIT=NONE] -->
+ <string name="private_dns_broken_detailed">Private DNS server cannot be accessed</string>
+
+ <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's title. [CHAR LIMIT=50] -->
+ <string name="network_partial_connectivity"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has limited connectivity</string>
+
+ <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's message. [CHAR LIMIT=50] -->
+ <string name="network_partial_connectivity_detailed">Tap to connect anyway</string>
+
+ <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
+ <string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string>
+
+ <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's message. %1$s is the network that the device switched to, e.g., cellular data. %2$s is the network type the device switched from, e.g., Wi-Fi. Both are strings in the network_switch_type_name array. -->
+ <string name="network_switch_metered_detail">Device uses <xliff:g id="new_network">%1$s</xliff:g> when <xliff:g id="previous_network">%2$s</xliff:g> has no internet access. Charges may apply.</string>
+
+ <!-- A toast might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the text of the toast. %1$s is the network that the device switched from, e.g., Wi-Fi. %2$s is the network type the device switched from, e.g., cellular data. Both are strings in the network_switch_type_name array. -->
+ <string name="network_switch_metered_toast">Switched from <xliff:g id="previous_network">%1$s</xliff:g> to <xliff:g id="new_network">%2$s</xliff:g></string>
+
+ <!-- Network type names used in the network_switch_metered and network_switch_metered_detail strings. These must be kept in the sync with the values NetworkCapabilities.TRANSPORT_xxx values, and in the same order. -->
+ <string-array name="network_switch_type_name">
+ <item>mobile data</item>
+ <item>Wi-Fi</item>
+ <item>Bluetooth</item>
+ <item>Ethernet</item>
+ <item>VPN</item>
+ </string-array>
+
+ <!-- Network type name displayed if one of the types is not found in network_switch_type_name. -->
+ <string name="network_switch_type_name_unknown">an unknown network type</string>
+
+</resources>
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index d8205bf..5caa11b 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -1,2 +1,17 @@
+rule android.sysprop.** com.android.connectivity.sysprop.@1
rule com.android.net.module.util.** com.android.connectivity.net-utils.@1
-rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
\ No newline at end of file
+rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
+
+# internal util classes
+# Exclude AsyncChannel. TODO: remove AsyncChannel usage in ConnectivityService
+rule com.android.internal.util.AsyncChannel* @0
+# Exclude LocationPermissionChecker. This is going to be moved to libs/net
+rule com.android.internal.util.LocationPermissionChecker* @0
+rule android.util.LocalLog* com.android.connectivity.util.LocalLog@1
+# android.util.IndentingPrintWriter* should use a different package name from
+# the one in com.android.internal.util
+rule android.util.IndentingPrintWriter* android.connectivity.util.IndentingPrintWriter@1
+rule com.android.internal.util.** com.android.connectivity.util.@1
+
+rule com.android.internal.messages.** com.android.connectivity.messages.@1
+rule com.google.protobuf.** com.android.connectivity.protobuf.@1
diff --git a/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl b/service/proto/connectivityproto.proto
similarity index 69%
copy from framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
copy to service/proto/connectivityproto.proto
index 7979afc..a992d7c 100644
--- a/framework/src/android/net/IOnSetOemNetworkPreferenceListener.aidl
+++ b/service/proto/connectivityproto.proto
@@ -1,12 +1,11 @@
-/**
- *
+/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,9 +14,7 @@
* limitations under the License.
*/
-package android.net;
+syntax = "proto2";
-/** @hide */
-oneway interface IOnSetOemNetworkPreferenceListener {
- void onComplete();
-}
+// Connectivity protos can be created in this directory. Note this file must be included before
+// building system-messages-proto, otherwise it will not build by itself.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index afa3bd1..0c42585 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -17,6 +17,10 @@
package com.android.server;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
+import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
@@ -26,17 +30,35 @@
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY;
+import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
+import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
+import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
import static android.net.ConnectivityManager.TYPE_NONE;
+import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_VPN;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
@@ -50,11 +72,14 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
+import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.uidRulesToString;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
+import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static android.os.Process.INVALID_UID;
import static android.os.Process.VPN_UID;
@@ -85,7 +110,11 @@
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.BlockedReason;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivityManager.RestrictBackgroundStatus;
+import android.net.ConnectivityResources;
+import android.net.ConnectivitySettingsManager;
import android.net.DataStallReportParcelable;
import android.net.DnsResolverServiceManager;
import android.net.ICaptivePortal;
@@ -94,10 +123,10 @@
import android.net.IDnsResolver;
import android.net.INetd;
import android.net.INetworkActivityListener;
+import android.net.INetworkAgent;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkPolicyListener;
-import android.net.IOnSetOemNetworkPreferenceListener;
+import android.net.IOnCompleteListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses;
@@ -110,13 +139,14 @@
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
-import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMonitorManager;
import android.net.NetworkPolicyManager;
+import android.net.NetworkPolicyManager.NetworkPolicyCallback;
import android.net.NetworkProvider;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStackClient;
@@ -187,18 +217,16 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
-import com.android.connectivity.aidl.INetworkAgent;
-import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.modules.utils.BasicShellCommandHandler;
import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
+import com.android.net.module.util.LocationPermissionChecker;
import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.net.module.util.PermissionUtils;
import com.android.server.connectivity.AutodestructReference;
@@ -213,9 +241,9 @@
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.NetworkRanker;
import com.android.server.connectivity.PermissionMonitor;
+import com.android.server.connectivity.ProfileNetworkPreferences;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.net.NetworkPolicyManagerInternal;
import libcore.io.IoUtils;
@@ -263,7 +291,7 @@
/**
* Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
* by OEMs for configuration purposes, as this value is overridden by
- * Settings.Global.CAPTIVE_PORTAL_HTTP_URL.
+ * ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL.
* R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
* (preferably via runtime resource overlays).
*/
@@ -296,7 +324,7 @@
protected int mNascentDelayMs;
// How long to delay to removal of a pending intent based request.
- // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
+ // See ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
private final int mReleasePendingIntentDelayMs;
private MockableSystemProperties mSystemProperties;
@@ -309,14 +337,13 @@
private volatile boolean mLockdownEnabled;
/**
- * Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal
- * handler thread, they don't need a lock.
+ * Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in
+ * internal handler thread, they don't need a lock.
*/
- private SparseIntArray mUidRules = new SparseIntArray();
- /** Flag indicating if background data is restricted. */
- private boolean mRestrictBackground;
+ private SparseIntArray mUidBlockedReasons = new SparseIntArray();
private final Context mContext;
+ private final ConnectivityResources mResources;
// The Context is created for UserHandle.ALL.
private final Context mUserAllContext;
private final Dependencies mDeps;
@@ -329,7 +356,6 @@
protected INetd mNetd;
private NetworkStatsManager mStatsManager;
private NetworkPolicyManager mPolicyManager;
- private NetworkPolicyManagerInternal mPolicyManagerInternal;
private final NetdCallback mNetdCallback;
/**
@@ -487,16 +513,6 @@
// Handle private DNS validation status updates.
private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
- /**
- * Used to handle onUidRulesChanged event from NetworkPolicyManagerService.
- */
- private static final int EVENT_UID_RULES_CHANGED = 39;
-
- /**
- * Used to handle onRestrictBackgroundChanged event from NetworkPolicyManagerService.
- */
- private static final int EVENT_DATA_SAVER_CHANGED = 40;
-
/**
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
* been tested.
@@ -556,8 +572,8 @@
private static final int EVENT_SET_REQUIRE_VPN_FOR_UIDS = 47;
/**
- * used internally when setting the default networks for OemNetworkPreferences.
- * obj = OemNetworkPreferences
+ * Used internally when setting the default networks for OemNetworkPreferences.
+ * obj = Pair<OemNetworkPreferences, listener>
*/
private static final int EVENT_SET_OEM_NETWORK_PREFERENCE = 48;
@@ -567,6 +583,19 @@
private static final int EVENT_REPORT_NETWORK_ACTIVITY = 49;
/**
+ * Used internally when setting a network preference for a user profile.
+ * obj = Pair<ProfileNetworkPreference, Listener>
+ */
+ private static final int EVENT_SET_PROFILE_NETWORK_PREFERENCE = 50;
+
+ /**
+ * Event to specify that reasons for why an uid is blocked changed.
+ * arg1 = uid
+ * arg2 = blockedReasons
+ */
+ private static final int EVENT_UID_BLOCKED_REASON_CHANGED = 51;
+
+ /**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
*/
@@ -604,7 +633,6 @@
private Intent mInitialBroadcast;
private PowerManager.WakeLock mNetTransitionWakeLock;
- private int mNetTransitionWakeLockTimeout;
private final PowerManager.WakeLock mPendingIntentWakeLock;
// A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
@@ -616,11 +644,8 @@
private UserManager mUserManager;
- private NetworkConfig[] mNetConfigs;
- private int mNetworksDefined;
-
// the set of network types that can only be enabled by system/sig apps
- private List mProtectedNetworks;
+ private List<Integer> mProtectedNetworks;
private Set<String> mWolSupportedInterfaces;
@@ -710,18 +735,63 @@
* They are therefore not thread-safe with respect to each other.
* - getNetworkForType() can be called at any time on binder threads. It is synchronized
* on mTypeLists to be thread-safe with respect to a concurrent remove call.
+ * - getRestoreTimerForType(type) is also synchronized on mTypeLists.
* - dump is thread-safe with respect to concurrent add and remove calls.
*/
private final ArrayList<NetworkAgentInfo> mTypeLists[];
@NonNull
private final ConnectivityService mService;
+ // Restore timers for requestNetworkForFeature (network type -> timer in ms). Types without
+ // an entry have no timer (equivalent to -1). Lazily loaded.
+ @NonNull
+ private ArrayMap<Integer, Integer> mRestoreTimers = new ArrayMap<>();
+
LegacyTypeTracker(@NonNull ConnectivityService service) {
mService = service;
mTypeLists = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
}
- public void addSupportedType(int type) {
+ public void loadSupportedTypes(@NonNull Context ctx, @NonNull TelephonyManager tm) {
+ final PackageManager pm = ctx.getPackageManager();
+ if (pm.hasSystemFeature(FEATURE_WIFI)) {
+ addSupportedType(TYPE_WIFI);
+ }
+ if (pm.hasSystemFeature(FEATURE_WIFI_DIRECT)) {
+ addSupportedType(TYPE_WIFI_P2P);
+ }
+ if (tm.isDataCapable()) {
+ // Telephony does not have granular support for these types: they are either all
+ // supported, or none is supported
+ addSupportedType(TYPE_MOBILE);
+ addSupportedType(TYPE_MOBILE_MMS);
+ addSupportedType(TYPE_MOBILE_SUPL);
+ addSupportedType(TYPE_MOBILE_DUN);
+ addSupportedType(TYPE_MOBILE_HIPRI);
+ addSupportedType(TYPE_MOBILE_FOTA);
+ addSupportedType(TYPE_MOBILE_IMS);
+ addSupportedType(TYPE_MOBILE_CBS);
+ addSupportedType(TYPE_MOBILE_IA);
+ addSupportedType(TYPE_MOBILE_EMERGENCY);
+ }
+ if (pm.hasSystemFeature(FEATURE_BLUETOOTH)) {
+ addSupportedType(TYPE_BLUETOOTH);
+ }
+ if (pm.hasSystemFeature(FEATURE_WATCH)) {
+ // TYPE_PROXY is only used on Wear
+ addSupportedType(TYPE_PROXY);
+ }
+ // Ethernet is often not specified in the configs, although many devices can use it via
+ // USB host adapters. Add it as long as the ethernet service is here.
+ if (ctx.getSystemService(Context.ETHERNET_SERVICE) != null) {
+ addSupportedType(TYPE_ETHERNET);
+ }
+
+ // Always add TYPE_VPN as a supported type
+ addSupportedType(TYPE_VPN);
+ }
+
+ private void addSupportedType(int type) {
if (mTypeLists[type] != null) {
throw new IllegalStateException(
"legacy list for type " + type + "already initialized");
@@ -742,6 +812,35 @@
return null;
}
+ public int getRestoreTimerForType(int type) {
+ synchronized (mTypeLists) {
+ if (mRestoreTimers == null) {
+ mRestoreTimers = loadRestoreTimers();
+ }
+ return mRestoreTimers.getOrDefault(type, -1);
+ }
+ }
+
+ private ArrayMap<Integer, Integer> loadRestoreTimers() {
+ final String[] configs = mService.mResources.get().getStringArray(
+ com.android.connectivity.resources.R.array
+ .config_legacy_networktype_restore_timers);
+ final ArrayMap<Integer, Integer> ret = new ArrayMap<>(configs.length);
+ for (final String config : configs) {
+ final String[] splits = TextUtils.split(config, ",");
+ if (splits.length != 2) {
+ logwtf("Invalid restore timer token count: " + config);
+ continue;
+ }
+ try {
+ ret.put(Integer.parseInt(splits[0]), Integer.parseInt(splits[1]));
+ } catch (NumberFormatException e) {
+ logwtf("Invalid restore timer number format: " + config, e);
+ }
+ }
+ return ret;
+ }
+
private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
boolean isDefaultNetwork) {
if (DBG) {
@@ -1012,6 +1111,13 @@
}
/**
+ * Get the {@link ConnectivityResources} to use in ConnectivityService.
+ */
+ public ConnectivityResources getResources(@NonNull Context ctx) {
+ return new ConnectivityResources(ctx);
+ }
+
+ /**
* Create a HandlerThread to use in ConnectivityService.
*/
public HandlerThread makeHandlerThread() {
@@ -1043,8 +1149,8 @@
/**
* @see NetworkUtils#queryUserAccess(int, int)
*/
- public boolean queryUserAccess(int uid, int netId) {
- return NetworkUtils.queryUserAccess(uid, netId);
+ public boolean queryUserAccess(int uid, Network network, ConnectivityService cs) {
+ return cs.queryUserAccess(uid, network);
}
/**
@@ -1093,13 +1199,14 @@
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
mContext = Objects.requireNonNull(context, "missing Context");
+ mResources = deps.getResources(mContext);
mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
mMetricsLog = logger;
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultRequest();
mDefaultRequest = new NetworkRequestInfo(
- defaultInternetRequest, null,
+ Process.myUid(), defaultInternetRequest, null,
new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
@@ -1127,7 +1234,7 @@
new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper());
mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
+ ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
// TODO: Consider making the timer customizable.
@@ -1135,9 +1242,6 @@
mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
- mPolicyManagerInternal = Objects.requireNonNull(
- LocalServices.getService(NetworkPolicyManagerInternal.class),
- "missing NetworkPolicyManagerInternal");
mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver");
mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
@@ -1146,86 +1250,28 @@
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mLocationPermissionChecker = new LocationPermissionChecker(mContext);
- // To ensure uid rules are synchronized with Network Policy, register for
+ // To ensure uid state is synchronized with Network Policy, register for
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
// reading existing policy from disk.
- mPolicyManager.registerListener(mPolicyListener);
+ mPolicyManager.registerNetworkPolicyCallback(null, mPolicyCallback);
final PowerManager powerManager = (PowerManager) context.getSystemService(
Context.POWER_SERVICE);
mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mNetTransitionWakeLockTimeout = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_networkTransitionTimeout);
mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
-
- // TODO: What is the "correct" way to do determine if this is a wifi only device?
- boolean wifiOnly = mSystemProperties.getBoolean("ro.radio.noril", false);
- log("wifiOnly=" + wifiOnly);
- String[] naStrings = context.getResources().getStringArray(
- com.android.internal.R.array.networkAttributes);
- for (String naString : naStrings) {
- try {
- NetworkConfig n = new NetworkConfig(naString);
- if (VDBG) log("naString=" + naString + " config=" + n);
- if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
- loge("Error in networkAttributes - ignoring attempt to define type " +
- n.type);
- continue;
- }
- if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) {
- log("networkAttributes - ignoring mobile as this dev is wifiOnly " +
- n.type);
- continue;
- }
- if (mNetConfigs[n.type] != null) {
- loge("Error in networkAttributes - ignoring attempt to redefine type " +
- n.type);
- continue;
- }
- mLegacyTypeTracker.addSupportedType(n.type);
-
- mNetConfigs[n.type] = n;
- mNetworksDefined++;
- } catch(Exception e) {
- // ignore it - leave the entry null
- }
- }
-
- // Forcibly add TYPE_VPN as a supported type, if it has not already been added via config.
- if (mNetConfigs[TYPE_VPN] == null) {
- // mNetConfigs is used only for "restore time", which isn't applicable to VPNs, so we
- // don't need to add TYPE_VPN to mNetConfigs.
- mLegacyTypeTracker.addSupportedType(TYPE_VPN);
- mNetworksDefined++; // used only in the log() statement below.
- }
-
- // Do the same for Ethernet, since it's often not specified in the configs, although many
- // devices can use it via USB host adapters.
- if (mNetConfigs[TYPE_ETHERNET] == null
- && mContext.getSystemService(Context.ETHERNET_SERVICE) != null) {
- mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
- mNetworksDefined++;
- }
-
- if (VDBG) log("mNetworksDefined=" + mNetworksDefined);
-
- mProtectedNetworks = new ArrayList<Integer>();
+ mLegacyTypeTracker.loadSupportedTypes(mContext, mTelephonyManager);
+ mProtectedNetworks = new ArrayList<>();
int[] protectedNetworks = context.getResources().getIntArray(
com.android.internal.R.array.config_protectedNetworks);
for (int p : protectedNetworks) {
- if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
+ if (mLegacyTypeTracker.isTypeSupported(p) && !mProtectedNetworks.contains(p)) {
mProtectedNetworks.add(p);
} else {
if (DBG) loge("Ignoring protectedNetwork " + p);
}
}
- mWolSupportedInterfaces = new ArraySet(
- mContext.getResources().getStringArray(
- com.android.internal.R.array.config_wakeonlan_supported_interfaces));
-
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -1257,10 +1303,10 @@
mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
+ ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
LingerMonitor.DEFAULT_NOTIFICATION_DAILY_LIMIT);
final long rateLimit = Settings.Global.getLong(mContext.getContentResolver(),
- Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
+ ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
@@ -1271,20 +1317,31 @@
mDnsManager = new DnsManager(mContext, mDnsResolver);
registerPrivateDnsSettingsCallbacks();
+ // This NAI is a sentinel used to offer no service to apps that are on a multi-layer
+ // request that doesn't allow fallback to the default network. It should never be visible
+ // to apps. As such, it's not in the list of NAIs and doesn't need many of the normal
+ // arguments like the handler or the DnsResolver.
+ // TODO : remove this ; it is probably better handled with a sentinel request.
mNoServiceNetwork = new NetworkAgentInfo(null,
new Network(NO_SERVICE_NET_ID),
new NetworkInfo(TYPE_NONE, 0, "", ""),
- new LinkProperties(), new NetworkCapabilities(), 0, mContext,
- null, new NetworkAgentConfig(), this, null,
- null, 0, INVALID_UID, mQosCallbackTracker, mDeps);
+ new LinkProperties(), new NetworkCapabilities(),
+ new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
+ new NetworkAgentConfig(), this, null, null, 0, INVALID_UID, mQosCallbackTracker,
+ mDeps);
}
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
+ return createDefaultNetworkCapabilitiesForUidRange(new UidRange(uid, uid));
+ }
+
+ private static NetworkCapabilities createDefaultNetworkCapabilitiesForUidRange(
+ @NonNull final UidRange uids) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
- netCap.setSingleUid(uid);
+ netCap.setUids(UidRange.toIntRanges(Collections.singleton(uids)));
return netCap;
}
@@ -1356,8 +1413,7 @@
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- networkRequest, null,
- new Binder(),
+ Process.myUid(), networkRequest, null, new Binder(),
NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */));
} else {
@@ -1367,10 +1423,10 @@
}
private void handleConfigureAlwaysOnNetworks() {
- handleAlwaysOnNetworkRequest(
- mDefaultMobileDataRequest, Settings.Global.MOBILE_DATA_ALWAYS_ON, true);
- handleAlwaysOnNetworkRequest(mDefaultWifiRequest, Settings.Global.WIFI_ALWAYS_REQUESTED,
- false);
+ handleAlwaysOnNetworkRequest(mDefaultMobileDataRequest,
+ ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON, true /* defaultValue */);
+ handleAlwaysOnNetworkRequest(mDefaultWifiRequest,
+ ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED, false /* defaultValue */);
handleAlwaysOnNetworkRequest(mDefaultVehicleRequest,
com.android.internal.R.bool.config_vehicleInternalNetworkAlwaysRequested);
}
@@ -1383,12 +1439,12 @@
// Watch for whether or not to keep mobile data always on.
mSettingsObserver.observe(
- Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
+ Settings.Global.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
// Watch for whether or not to keep wifi always on.
mSettingsObserver.observe(
- Settings.Global.getUriFor(Settings.Global.WIFI_ALWAYS_REQUESTED),
+ Settings.Global.getUriFor(ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED),
EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
}
@@ -1504,7 +1560,7 @@
final int requestId = nri.getActiveRequest() != null
? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId;
mNetworkInfoBlockingLogs.log(String.format(
- "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
+ "%s %d(%d) on netId %d", action, nri.mAsUid, requestId, net.getNetId()));
}
/**
@@ -1720,12 +1776,13 @@
nai.network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
nc, false /* includeLocationSensitiveInfo */,
- mDeps.getCallingUid(), callingPackageName, callingAttributionTag));
+ getCallingPid(), mDeps.getCallingUid(), callingPackageName,
+ callingAttributionTag));
}
}
// No need to check mLockdownEnabled. If it's true, getVpnUnderlyingNetworks returns null.
- final Network[] networks = getVpnUnderlyingNetworks(Binder.getCallingUid());
+ final Network[] networks = getVpnUnderlyingNetworks(mDeps.getCallingUid());
if (null != networks) {
for (final Network network : networks) {
final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
@@ -1735,7 +1792,7 @@
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
nc,
false /* includeLocationSensitiveInfo */,
- mDeps.getCallingUid(), callingPackageName,
+ getCallingPid(), mDeps.getCallingUid(), callingPackageName,
callingAttributionTag));
}
}
@@ -1818,7 +1875,7 @@
return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
getNetworkCapabilitiesInternal(network),
false /* includeLocationSensitiveInfo */,
- mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
+ getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
}
@VisibleForTesting
@@ -1837,40 +1894,137 @@
return newNc;
}
- private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName,
- @Nullable String callingAttributionTag) {
- final long token = Binder.clearCallingIdentity();
- try {
- return mLocationPermissionChecker.checkLocationPermission(
- callerPkgName, callingAttributionTag, callerUid, null /* message */);
- } finally {
- Binder.restoreCallingIdentity(token);
+ /**
+ * Wrapper used to cache the permission check results performed for the corresponding
+ * app. This avoid performing multiple permission checks for different fields in
+ * NetworkCapabilities.
+ * Note: This wrapper does not support any sort of invalidation and thus must not be
+ * persistent or long-lived. It may only be used for the time necessary to
+ * compute the redactions required by one particular NetworkCallback or
+ * synchronous call.
+ */
+ private class RedactionPermissionChecker {
+ private final int mCallingPid;
+ private final int mCallingUid;
+ @NonNull private final String mCallingPackageName;
+ @Nullable private final String mCallingAttributionTag;
+
+ private Boolean mHasLocationPermission = null;
+ private Boolean mHasLocalMacAddressPermission = null;
+ private Boolean mHasSettingsPermission = null;
+
+ RedactionPermissionChecker(int callingPid, int callingUid,
+ @NonNull String callingPackageName, @Nullable String callingAttributionTag) {
+ mCallingPid = callingPid;
+ mCallingUid = callingUid;
+ mCallingPackageName = callingPackageName;
+ mCallingAttributionTag = callingAttributionTag;
}
+
+ private boolean hasLocationPermissionInternal() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mLocationPermissionChecker.checkLocationPermission(
+ mCallingPackageName, mCallingAttributionTag, mCallingUid,
+ null /* message */);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Returns whether the app holds location permission or not (might return cached result
+ * if the permission was already checked before).
+ */
+ public boolean hasLocationPermission() {
+ if (mHasLocationPermission == null) {
+ // If there is no cached result, perform the check now.
+ mHasLocationPermission = hasLocationPermissionInternal();
+ }
+ return mHasLocationPermission;
+ }
+
+ /**
+ * Returns whether the app holds local mac address permission or not (might return cached
+ * result if the permission was already checked before).
+ */
+ public boolean hasLocalMacAddressPermission() {
+ if (mHasLocalMacAddressPermission == null) {
+ // If there is no cached result, perform the check now.
+ mHasLocalMacAddressPermission =
+ checkLocalMacAddressPermission(mCallingPid, mCallingUid);
+ }
+ return mHasLocalMacAddressPermission;
+ }
+
+ /**
+ * Returns whether the app holds settings permission or not (might return cached
+ * result if the permission was already checked before).
+ */
+ public boolean hasSettingsPermission() {
+ if (mHasSettingsPermission == null) {
+ // If there is no cached result, perform the check now.
+ mHasSettingsPermission = checkSettingsPermission(mCallingPid, mCallingUid);
+ }
+ return mHasSettingsPermission;
+ }
+ }
+
+ private static boolean shouldRedact(@NetworkCapabilities.RedactionType long redactions,
+ @NetworkCapabilities.NetCapability long redaction) {
+ return (redactions & redaction) != 0;
+ }
+
+ /**
+ * Use the provided |applicableRedactions| to check the receiving app's
+ * permissions and clear/set the corresponding bit in the returned bitmask. The bitmask
+ * returned will be used to ensure the necessary redactions are performed by NetworkCapabilities
+ * before being sent to the corresponding app.
+ */
+ private @NetworkCapabilities.RedactionType long retrieveRequiredRedactions(
+ @NetworkCapabilities.RedactionType long applicableRedactions,
+ @NonNull RedactionPermissionChecker redactionPermissionChecker,
+ boolean includeLocationSensitiveInfo) {
+ long redactions = applicableRedactions;
+ if (shouldRedact(redactions, REDACT_FOR_ACCESS_FINE_LOCATION)) {
+ if (includeLocationSensitiveInfo
+ && redactionPermissionChecker.hasLocationPermission()) {
+ redactions &= ~REDACT_FOR_ACCESS_FINE_LOCATION;
+ }
+ }
+ if (shouldRedact(redactions, REDACT_FOR_LOCAL_MAC_ADDRESS)) {
+ if (redactionPermissionChecker.hasLocalMacAddressPermission()) {
+ redactions &= ~REDACT_FOR_LOCAL_MAC_ADDRESS;
+ }
+ }
+ if (shouldRedact(redactions, REDACT_FOR_NETWORK_SETTINGS)) {
+ if (redactionPermissionChecker.hasSettingsPermission()) {
+ redactions &= ~REDACT_FOR_NETWORK_SETTINGS;
+ }
+ }
+ return redactions;
}
@VisibleForTesting
@Nullable
NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
@Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo,
- int callerUid, @NonNull String callerPkgName, @Nullable String callingAttributionTag) {
+ int callingPid, int callingUid, @NonNull String callingPkgName,
+ @Nullable String callingAttributionTag) {
if (nc == null) {
return null;
}
- Boolean hasLocationPermission = null;
- final NetworkCapabilities newNc;
// Avoid doing location permission check if the transport info has no location sensitive
// data.
- if (includeLocationSensitiveInfo
- && nc.getTransportInfo() != null
- && nc.getTransportInfo().hasLocationSensitiveFields()) {
- hasLocationPermission =
- hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
- newNc = new NetworkCapabilities(nc, hasLocationPermission);
- } else {
- newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */);
- }
+ final RedactionPermissionChecker redactionPermissionChecker =
+ new RedactionPermissionChecker(callingPid, callingUid, callingPkgName,
+ callingAttributionTag);
+ final long redactions = retrieveRequiredRedactions(
+ nc.getApplicableRedactions(), redactionPermissionChecker,
+ includeLocationSensitiveInfo);
+ final NetworkCapabilities newNc = new NetworkCapabilities(nc, redactions);
// Reset owner uid if not destined for the owner app.
- if (callerUid != nc.getOwnerUid()) {
+ if (callingUid != nc.getOwnerUid()) {
newNc.setOwnerUid(INVALID_UID);
return newNc;
}
@@ -1879,23 +2033,17 @@
// Owner UIDs already checked above. No need to re-check.
return newNc;
}
- // If the caller does not want location sensitive data & target SDK >= S, then mask info.
- // Else include the owner UID iff the caller has location permission to provide backwards
+ // If the calling does not want location sensitive data & target SDK >= S, then mask info.
+ // Else include the owner UID iff the calling has location permission to provide backwards
// compatibility for older apps.
if (!includeLocationSensitiveInfo
&& isTargetSdkAtleast(
- Build.VERSION_CODES.S, callerUid, callerPkgName)) {
+ Build.VERSION_CODES.S, callingUid, callingPkgName)) {
newNc.setOwnerUid(INVALID_UID);
return newNc;
}
-
- if (hasLocationPermission == null) {
- // Location permission not checked yet, check now for masking owner UID.
- hasLocationPermission =
- hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
- }
// Reset owner uid if the app has no location permission.
- if (!hasLocationPermission) {
+ if (!redactionPermissionChecker.hasLocationPermission()) {
newNc.setOwnerUid(INVALID_UID);
}
return newNc;
@@ -1927,6 +2075,8 @@
private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc,
int callerUid, String callerPackageName) {
if (!checkSettingsPermission()) {
+ // There is no need to track the effective UID of the request here. If the caller lacks
+ // the settings permission, the effective UID is the same as the calling ID.
nc.setSingleUid(callerUid);
}
nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
@@ -1942,6 +2092,18 @@
}
}
+ @Override
+ public @RestrictBackgroundStatus int getRestrictBackgroundStatusByCaller() {
+ enforceAccessPermission();
+ final int callerUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mPolicyManager.getRestrictBackgroundStatus(callerUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
// TODO: Consider delete this function or turn it into a no-op method.
@Override
public NetworkState[] getAllNetworkState() {
@@ -2177,53 +2339,17 @@
}
}
- private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() {
+ private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() {
@Override
- public void onUidRulesChanged(int uid, int uidRules) {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_RULES_CHANGED, uid, uidRules));
- }
- @Override
- public void onRestrictBackgroundChanged(boolean restrictBackground) {
- // caller is NPMS, since we only register with them
- if (LOGD_BLOCKED_NETWORKINFO) {
- log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
- }
- mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_DATA_SAVER_CHANGED, restrictBackground ? 1 : 0, 0));
+ public void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED,
+ uid, blockedReasons));
}
};
- void handleUidRulesChanged(int uid, int newRules) {
- // skip update when we've already applied rules
- final int oldRules = mUidRules.get(uid, RULE_NONE);
- if (oldRules == newRules) return;
-
- maybeNotifyNetworkBlockedForNewUidRules(uid, newRules);
-
- if (newRules == RULE_NONE) {
- mUidRules.delete(uid);
- } else {
- mUidRules.put(uid, newRules);
- }
- }
-
- void handleRestrictBackgroundChanged(boolean restrictBackground) {
- if (mRestrictBackground == restrictBackground) return;
-
- final List<UidRange> blockedRanges = mVpnBlockedUidRanges;
- for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- final boolean curMetered = nai.networkCapabilities.isMetered();
- maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
- restrictBackground, blockedRanges, blockedRanges);
- }
-
- mRestrictBackground = restrictBackground;
- }
-
- private boolean isUidBlockedByRules(int uid, int uidRules, boolean isNetworkMetered,
- boolean isBackgroundRestricted) {
- return mPolicyManager.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered,
- isBackgroundRestricted);
+ private void handleUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
+ maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
+ setUidBlockedReasons(uid, blockedReasons);
}
private boolean checkAnyPermissionOf(String... permissions) {
@@ -2410,6 +2536,11 @@
mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService");
}
+ private boolean checkLocalMacAddressPermission(int pid, int uid) {
+ return PERMISSION_GRANTED == mContext.checkPermission(
+ Manifest.permission.LOCAL_MAC_ADDRESS, pid, uid);
+ }
+
private void sendConnectedBroadcast(NetworkInfo info) {
sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
}
@@ -2594,13 +2725,6 @@
} catch (RemoteException | ServiceSpecificException e) {
loge("Can't set TCP buffer sizes:" + e);
}
-
- final Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.TCP_DEFAULT_INIT_RWND,
- mSystemProperties.getInt("net.tcp.default_init_rwnd", 0));
- if (rwndValue != 0) {
- mSystemProperties.setTcpInitRwnd(rwndValue);
- }
}
@Override
@@ -2617,9 +2741,8 @@
// if the system property isn't set, use the value for the apn type
int ret = RESTORE_DEFAULT_NETWORK_DELAY;
- if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
- (mNetConfigs[networkType] != null)) {
- ret = mNetConfigs[networkType].restoreTime;
+ if (mLegacyTypeTracker.isTypeSupported(networkType)) {
+ ret = mLegacyTypeTracker.getRestoreTimerForType(networkType);
}
return ret;
}
@@ -2705,19 +2828,16 @@
pw.decreaseIndent();
pw.println();
- pw.print("Restrict background: ");
- pw.println(mRestrictBackground);
- pw.println();
-
pw.println("Status for known UIDs:");
pw.increaseIndent();
- final int size = mUidRules.size();
+ final int size = mUidBlockedReasons.size();
for (int i = 0; i < size; i++) {
// Don't crash if the array is modified while dumping in bugreports.
try {
- final int uid = mUidRules.keyAt(i);
- final int uidRules = mUidRules.get(uid, RULE_NONE);
- pw.println("UID=" + uid + " rules=" + uidRulesToString(uidRules));
+ final int uid = mUidBlockedReasons.keyAt(i);
+ final int blockedReasons = mUidBlockedReasons.valueAt(i);
+ pw.println("UID=" + uid + " blockedReasons="
+ + blockedReasonsToString(blockedReasons));
} catch (ArrayIndexOutOfBoundsException e) {
pw.println(" ArrayIndexOutOfBoundsException");
} catch (ConcurrentModificationException e) {
@@ -2852,7 +2972,7 @@
if (0 == defaultRequest.mRequests.size()) {
pw.println("none, this should never occur.");
} else {
- pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids());
+ pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUidRanges());
}
pw.decreaseIndent();
pw.decreaseIndent();
@@ -2947,12 +3067,15 @@
break;
}
case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
- updateNetworkScore(nai, msg.arg1);
+ updateNetworkScore(nai, (NetworkScore) arg.second);
break;
}
case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
if (nai.everConnected) {
loge("ERROR: cannot call explicitlySelected on already-connected network");
+ // Note that if the NAI had been connected, this would affect the
+ // score, and therefore would require re-mixing the score and performing
+ // a rematch.
}
nai.networkAgentConfig.explicitlySelected = toBool(msg.arg1);
nai.networkAgentConfig.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2);
@@ -3058,7 +3181,8 @@
nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= visible;
if (nai.lastCaptivePortalDetected &&
- Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
+ ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID
+ == getCaptivePortalMode()) {
if (DBG) log("Avoiding captive portal network: " + nai.toShortString());
nai.onPreventAutomaticReconnect();
teardownUnneededNetwork(nai);
@@ -3169,8 +3293,8 @@
private int getCaptivePortalMode() {
return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_MODE,
- Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+ ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE,
+ ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
}
private boolean maybeHandleNetworkAgentInfoMessage(Message msg) {
@@ -3580,6 +3704,7 @@
mDnsManager.removeNetwork(nai.network);
}
mNetIdManager.releaseNetId(nai.network.getNetId());
+ nai.onNetworkDisconnected();
}
private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -3638,7 +3763,7 @@
log("Replacing " + existingRequest.mRequests.get(0) + " with "
+ nri.mRequests.get(0) + " because their intents matched.");
}
- handleReleaseNetworkRequest(existingRequest.mRequests.get(0), getCallingUid(),
+ handleReleaseNetworkRequest(existingRequest.mRequests.get(0), mDeps.getCallingUid(),
/* callOnUnavailable */ false);
}
handleRegisterNetworkRequest(nri);
@@ -3654,6 +3779,7 @@
mNetworkRequestInfoLogs.log("REGISTER " + nri);
for (final NetworkRequest req : nri.mRequests) {
mNetworkRequests.put(req, nri);
+ // TODO: Consider update signal strength for other types.
if (req.isListen()) {
for (final NetworkAgentInfo network : mNetworkAgentInfos) {
if (req.networkCapabilities.hasSignalStrength()
@@ -3746,18 +3872,19 @@
// listen requests won't keep up a network satisfying it. If this is not a multilayer
// request, return immediately. For multilayer requests, check to see if any of the
// multilayer requests may have a potential satisfier.
- if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
+ if (!nri.isMultilayerRequest() && (nri.mRequests.get(0).isListen()
+ || nri.mRequests.get(0).isListenForBest())) {
return false;
}
for (final NetworkRequest req : nri.mRequests) {
// This multilayer listen request is satisfied therefore no further requests need to be
// evaluated deeming this network not a potential satisfier.
- if (req.isListen() && nri.getActiveRequest() == req) {
+ if ((req.isListen() || req.isListenForBest()) && nri.getActiveRequest() == req) {
return false;
}
// As non-multilayer listen requests have already returned, the below would only happen
// for a multilayer request therefore continue to the next request if available.
- if (req.isListen()) {
+ if (req.isListen() || req.isListenForBest()) {
continue;
}
// If this Network is already the highest scoring Network for a request, or if
@@ -3797,8 +3924,7 @@
? mNetworkRequests.get(request) : getNriForAppRequest(request);
if (nri != null) {
- if (Process.SYSTEM_UID != callingUid && Process.NETWORK_STACK_UID != callingUid
- && nri.mUid != callingUid) {
+ if (Process.SYSTEM_UID != callingUid && nri.mUid != callingUid) {
log(String.format("UID %d attempted to %s for unowned request %s",
callingUid, requestedOperation, nri));
return null;
@@ -4035,6 +4161,7 @@
// network, we should respect the user's option and don't need to popup the
// PARTIAL_CONNECTIVITY notification to user again.
nai.networkAgentConfig.acceptPartialConnectivity = accept;
+ nai.updateScoreForNetworkAgentConfigUpdate();
rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
@@ -4297,7 +4424,7 @@
Intent intent = new Intent(action);
if (type != NotificationType.PRIVATE_DNS_BROKEN) {
- intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.getNetId()), null));
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK, nai.network);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Some OEMs have their own Settings package. Thus, need to get the current using
// Settings package name instead of just use default name "com.android.settings".
@@ -4393,7 +4520,13 @@
final NetworkPolicyManager netPolicyManager =
mContext.getSystemService(NetworkPolicyManager.class);
- final int networkPreference = netPolicyManager.getMultipathPreference(network);
+ final long token = Binder.clearCallingIdentity();
+ final int networkPreference;
+ try {
+ networkPreference = netPolicyManager.getMultipathPreference(network);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
if (networkPreference != 0) {
return networkPreference;
}
@@ -4423,7 +4556,8 @@
break;
}
case EVENT_PROXY_HAS_CHANGED: {
- handleApplyDefaultProxy((ProxyInfo)msg.obj);
+ final Pair<Network, ProxyInfo> arg = (Pair<Network, ProxyInfo>) msg.obj;
+ handleApplyDefaultProxy(arg.second);
break;
}
case EVENT_REGISTER_NETWORK_PROVIDER: {
@@ -4511,22 +4645,24 @@
handlePrivateDnsValidationUpdate(
(PrivateDnsValidationUpdate) msg.obj);
break;
- case EVENT_UID_RULES_CHANGED:
- handleUidRulesChanged(msg.arg1, msg.arg2);
- break;
- case EVENT_DATA_SAVER_CHANGED:
- handleRestrictBackgroundChanged(toBool(msg.arg1));
+ case EVENT_UID_BLOCKED_REASON_CHANGED:
+ handleUidBlockedReasonChanged(msg.arg1, msg.arg2);
break;
case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
break;
case EVENT_SET_OEM_NETWORK_PREFERENCE: {
- final Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener> arg =
- (Pair<OemNetworkPreferences,
- IOnSetOemNetworkPreferenceListener>) msg.obj;
+ final Pair<OemNetworkPreferences, IOnCompleteListener> arg =
+ (Pair<OemNetworkPreferences, IOnCompleteListener>) msg.obj;
handleSetOemNetworkPreference(arg.first, arg.second);
break;
}
+ case EVENT_SET_PROFILE_NETWORK_PREFERENCE: {
+ final Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener> arg =
+ (Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener>)
+ msg.obj;
+ handleSetProfileNetworkPreference(arg.first, arg.second);
+ }
case EVENT_REPORT_NETWORK_ACTIVITY:
mNetworkActivityTracker.handleReportNetworkActivity();
break;
@@ -4600,7 +4736,9 @@
}
mWakelockLogs.log("ACQUIRE for " + forWhom);
Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
- mHandler.sendMessageDelayed(msg, mNetTransitionWakeLockTimeout);
+ final int lockTimeout = mResources.get().getInteger(
+ com.android.connectivity.resources.R.integer.config_networkTransitionTimeout);
+ mHandler.sendMessageDelayed(msg, lockTimeout);
}
// Called when we gain a new default network to release the network transition wakelock in a
@@ -4705,6 +4843,42 @@
nai.networkMonitor().forceReevaluation(uid);
}
+ // TODO: call into netd.
+ private boolean queryUserAccess(int uid, Network network) {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai == null) return false;
+
+ // Any UID can use its default network.
+ if (nai == getDefaultNetworkForUid(uid)) return true;
+
+ // Privileged apps can use any network.
+ if (mPermissionMonitor.hasRestrictedNetworksPermission(uid)) {
+ return true;
+ }
+
+ // An unprivileged UID can use a VPN iff the VPN applies to it.
+ if (nai.isVPN()) {
+ return nai.networkCapabilities.appliesToUid(uid);
+ }
+
+ // An unprivileged UID can bypass the VPN that applies to it only if it can protect its
+ // sockets, i.e., if it is the owner.
+ final NetworkAgentInfo vpn = getVpnForUid(uid);
+ if (vpn != null && !vpn.networkAgentConfig.allowBypass
+ && uid != vpn.networkCapabilities.getOwnerUid()) {
+ return false;
+ }
+
+ // The UID's permission must be at least sufficient for the network. Since the restricted
+ // permission was already checked above, that just leaves background networks.
+ if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
+ return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
+ }
+
+ // Unrestricted network. Anyone gets to use it.
+ return true;
+ }
+
/**
* Returns information about the proxy a certain network is using. If given a null network, it
* it will return the proxy for the bound network for the caller app or the default proxy if
@@ -4725,7 +4899,7 @@
return null;
}
return getLinkPropertiesProxyInfo(activeNetwork);
- } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network.getNetId())) {
+ } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network, this)) {
// Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
// caller may not have.
return getLinkPropertiesProxyInfo(network);
@@ -4823,6 +4997,10 @@
Log.wtf(TAG, s);
}
+ private static void logwtf(String s, Throwable t) {
+ Log.wtf(TAG, s, t);
+ }
+
private static void loge(String s) {
Log.e(TAG, s);
}
@@ -4948,7 +5126,7 @@
@Override
public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
+ enforceNetworkStackOrSettingsPermission();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS,
encodeBool(requireVpn), 0 /* arg2 */, ranges));
}
@@ -4977,8 +5155,8 @@
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
final boolean curMetered = nai.networkCapabilities.isMetered();
- maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
- mRestrictBackground, mVpnBlockedUidRanges, newVpnBlockedUidRanges);
+ maybeNotifyNetworkBlocked(nai, curMetered, curMetered,
+ mVpnBlockedUidRanges, newVpnBlockedUidRanges);
}
mVpnBlockedUidRanges = newVpnBlockedUidRanges;
@@ -4986,7 +5164,7 @@
@Override
public void setLegacyLockdownVpnEnabled(boolean enabled) {
- enforceSettingsPermission();
+ enforceNetworkStackOrSettingsPermission();
mHandler.post(() -> mLockdownEnabled = enabled);
}
@@ -5095,6 +5273,9 @@
private void onUserRemoved(UserHandle user) {
mPermissionMonitor.onUserRemoved(user);
+ // If there was a network preference for this user, remove it.
+ handleSetProfileNetworkPreference(new ProfileNetworkPreferences.Preference(user, null),
+ null /* listener */);
if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
handleSetOemNetworkPreference(mOemNetworkPreferences, null);
}
@@ -5223,6 +5404,8 @@
boolean mPendingIntentSent;
@Nullable
final Messenger mMessenger;
+
+ // Information about the caller that caused this object to be created.
@Nullable
private final IBinder mBinder;
final int mPid;
@@ -5230,6 +5413,13 @@
final @NetworkCallback.Flag int mCallbackFlags;
@Nullable
final String mCallingAttributionTag;
+
+ // Effective UID of this request. This is different from mUid when a privileged process
+ // files a request on behalf of another UID. This UID is used to determine blocked status,
+ // UID matching, and so on. mUid above is used for permission checks and to enforce the
+ // maximum limit of registered callbacks per UID.
+ final int mAsUid;
+
// In order to preserve the mapping of NetworkRequest-to-callback when apps register
// callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
// maintained for keying off of. This is only a concern when the original nri
@@ -5253,17 +5443,16 @@
private Set<UidRange> getUids() {
// networkCapabilities.getUids() returns a defensive copy.
// multilayer requests will all have the same uids so return the first one.
- final Set<UidRange> uids = null == mRequests.get(0).networkCapabilities.getUids()
- ? new ArraySet<>() : mRequests.get(0).networkCapabilities.getUids();
- return uids;
+ final Set<UidRange> uids = mRequests.get(0).networkCapabilities.getUidRanges();
+ return (null == uids) ? new ArraySet<>() : uids;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
- @Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, pi, callingAttributionTag);
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r,
+ @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
+ this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag);
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
@Nullable String callingAttributionTag) {
ensureAllNetworkRequestsHaveType(r);
@@ -5274,6 +5463,7 @@
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
+ mAsUid = asUid;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
/**
* Location sensitive data not included in pending intent. Only included in
@@ -5283,14 +5473,15 @@
mCallingAttributionTag = callingAttributionTag;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
@Nullable final IBinder binder,
@NetworkCallback.Flag int callbackFlags,
@Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, m, binder, callbackFlags, callingAttributionTag);
+ this(asUid, Collections.singletonList(r), r, m, binder, callbackFlags,
+ callingAttributionTag);
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m,
@Nullable final IBinder binder,
@NetworkCallback.Flag int callbackFlags,
@@ -5303,6 +5494,7 @@
mBinder = binder;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
+ mAsUid = asUid;
mPendingIntent = null;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
mCallbackFlags = callbackFlags;
@@ -5345,18 +5537,19 @@
mBinder = nri.mBinder;
mPid = nri.mPid;
mUid = nri.mUid;
+ mAsUid = nri.mAsUid;
mPendingIntent = nri.mPendingIntent;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r) {
- this(Collections.singletonList(r));
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
+ this(asUid, Collections.singletonList(r));
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r) {
- this(r, r.get(0), null /* pi */, null /* callingAttributionTag */);
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r) {
+ this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */);
}
// True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -5392,9 +5585,10 @@
@Override
public String toString() {
- return "uid/pid:" + mUid + "/" + mPid + " active request Id: "
+ final String asUidString = (mAsUid == mUid) ? "" : " asUid: " + mAsUid;
+ return "uid/pid:" + mUid + "/" + mPid + asUidString + " activeRequest: "
+ (mActiveRequest == null ? null : mActiveRequest.requestId)
- + " callback request Id: "
+ + " callbackRequest: "
+ mNetworkRequestForCallback.requestId
+ " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
@@ -5495,7 +5689,7 @@
}
@Override
- public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
+ public NetworkRequest requestNetwork(int asUid, NetworkCapabilities networkCapabilities,
int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
int legacyType, int callbackFlags, @NonNull String callingPackageName,
@Nullable String callingAttributionTag) {
@@ -5507,6 +5701,12 @@
}
final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities;
final int callingUid = mDeps.getCallingUid();
+ // Privileged callers can track the default network of another UID by passing in a UID.
+ if (asUid != Process.INVALID_UID) {
+ enforceSettingsPermission();
+ } else {
+ asUid = callingUid;
+ }
final NetworkRequest.Type reqType;
try {
reqType = NetworkRequest.Type.values()[reqTypeInt];
@@ -5516,10 +5716,10 @@
switch (reqType) {
case TRACK_DEFAULT:
// If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
- // is unused and will be replaced by ones appropriate for the caller.
- // This allows callers to keep track of the default network for their app.
+ // is unused and will be replaced by ones appropriate for the UID (usually, the
+ // calling app). This allows callers to keep track of the default network.
networkCapabilities = copyDefaultNetworkCapabilitiesForUid(
- defaultNc, callingUid, callingPackageName);
+ defaultNc, asUid, callingUid, callingPackageName);
enforceAccessPermission();
break;
case TRACK_SYSTEM_DEFAULT:
@@ -5538,8 +5738,10 @@
// request if the app changes network state. http://b/29964605
enforceMeteredApnPolicy(networkCapabilities);
break;
- case TRACK_BEST:
- throw new UnsupportedOperationException("Not implemented yet");
+ case LISTEN_FOR_BEST:
+ enforceAccessPermission();
+ networkCapabilities = new NetworkCapabilities(networkCapabilities);
+ break;
default:
throw new IllegalArgumentException("Unsupported request type " + reqType);
}
@@ -5547,11 +5749,17 @@
ensureSufficientPermissionsForRequest(networkCapabilities,
Binder.getCallingPid(), callingUid, callingPackageName);
- // Set the UID range for this request to the single UID of the requester, or to an empty
- // set of UIDs if the caller has the appropriate permission and UIDs have not been set.
+ // Enforce FOREGROUND if the caller does not have permission to use background network.
+ if (reqType == LISTEN_FOR_BEST) {
+ restrictBackgroundRequestForCaller(networkCapabilities);
+ }
+
+ // Set the UID range for this request to the single UID of the requester, unless the
+ // requester has the permission to specify other UIDs.
// This will overwrite any allowed UIDs in the requested capabilities. Though there
// are no visible methods to set the UIDs, an app could use reflection to try and get
// networks for other apps so it's essential that the UIDs are overwritten.
+ // Also set the requester UID and package name in the request.
restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
callingUid, callingPackageName);
@@ -5563,7 +5771,8 @@
final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
final NetworkRequestInfo nri = getNriToRegister(
- networkRequest, messenger, binder, callbackFlags, callingAttributionTag);
+ asUid, networkRequest, messenger, binder, callbackFlags,
+ callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
// For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
@@ -5590,25 +5799,27 @@
* requests registered to track the default request. If there is currently a per-app default
* tracking the app requestor, then we need to create a version of this nri that mirrors that of
* the tracking per-app default so that callbacks are sent to the app requestor appropriately.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param nr the network request for the nri.
* @param msgr the messenger for the nri.
* @param binder the binder for the nri.
* @param callingAttributionTag the calling attribution tag for the nri.
* @return the nri to register.
*/
- private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr,
+ private NetworkRequestInfo getNriToRegister(final int asUid, @NonNull final NetworkRequest nr,
@Nullable final Messenger msgr, @Nullable final IBinder binder,
@NetworkCallback.Flag int callbackFlags,
@Nullable String callingAttributionTag) {
final List<NetworkRequest> requests;
if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) {
requests = copyDefaultNetworkRequestsForUid(
- nr.getRequestorUid(), nr.getRequestorPackageName());
+ asUid, nr.getRequestorUid(), nr.getRequestorPackageName());
} else {
requests = Collections.singletonList(nr);
}
return new NetworkRequestInfo(
- requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
+ asUid, requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
}
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
@@ -5689,8 +5900,8 @@
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
- NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
+ NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
+ callingAttributionTag);
if (DBG) log("pendingRequest for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
nri));
@@ -5700,14 +5911,14 @@
private void releasePendingNetworkRequestWithDelay(PendingIntent operation) {
mHandler.sendMessageDelayed(
mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
- getCallingUid(), 0, operation), mReleasePendingIntentDelayMs);
+ mDeps.getCallingUid(), 0, operation), mReleasePendingIntentDelayMs);
}
@Override
public void releasePendingNetworkRequest(PendingIntent operation) {
Objects.requireNonNull(operation, "PendingIntent cannot be null.");
mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
- getCallingUid(), 0, operation));
+ mDeps.getCallingUid(), 0, operation));
}
// In order to implement the compatibility measure for pre-M apps that call
@@ -5757,7 +5968,7 @@
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags,
+ new NetworkRequestInfo(callingUid, networkRequest, messenger, binder, callbackFlags,
callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
@@ -5782,8 +5993,8 @@
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
+ NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
+ callingAttributionTag);
if (VDBG) log("pendingListenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5804,7 +6015,7 @@
public void releaseNetworkRequest(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(), 0, networkRequest));
+ EVENT_RELEASE_NETWORK_REQUEST, mDeps.getCallingUid(), 0, networkRequest));
}
private void handleRegisterNetworkProvider(NetworkProviderInfo npi) {
@@ -5885,10 +6096,16 @@
@GuardedBy("mBlockedAppUids")
private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
- // Current OEM network preferences.
+ // Current OEM network preferences. This object must only be written to on the handler thread.
+ // Since it is immutable and always non-null, other threads may read it if they only care
+ // about seeing a consistent object but not that it is current.
@NonNull
private OemNetworkPreferences mOemNetworkPreferences =
new OemNetworkPreferences.Builder().build();
+ // Current per-profile network preferences. This object follows the same threading rules as
+ // the OEM network preferences above.
+ @NonNull
+ private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
// The always-on request for an Internet-capable network that apps without a specific default
// fall back to.
@@ -5927,33 +6144,37 @@
/**
* Get a copy of the network requests of the default request that is currently tracking the
* given uid.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param requestorUid the uid to check the default for.
* @param requestorPackageName the requestor's package name.
* @return a copy of the default's NetworkRequest that is tracking the given uid.
*/
@NonNull
private List<NetworkRequest> copyDefaultNetworkRequestsForUid(
- @NonNull final int requestorUid, @NonNull final String requestorPackageName) {
+ final int asUid, final int requestorUid, @NonNull final String requestorPackageName) {
return copyNetworkRequestsForUid(
- getDefaultRequestTrackingUid(requestorUid).mRequests,
- requestorUid, requestorPackageName);
+ getDefaultRequestTrackingUid(asUid).mRequests,
+ asUid, requestorUid, requestorPackageName);
}
/**
* Copy the given nri's NetworkRequest collection.
* @param requestsToCopy the NetworkRequest collection to be copied.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param requestorUid the uid to set on the copied collection.
* @param requestorPackageName the package name to set on the copied collection.
* @return the copied NetworkRequest collection.
*/
@NonNull
private List<NetworkRequest> copyNetworkRequestsForUid(
- @NonNull final List<NetworkRequest> requestsToCopy, @NonNull final int requestorUid,
- @NonNull final String requestorPackageName) {
+ @NonNull final List<NetworkRequest> requestsToCopy, final int asUid,
+ final int requestorUid, @NonNull final String requestorPackageName) {
final List<NetworkRequest> requests = new ArrayList<>();
for (final NetworkRequest nr : requestsToCopy) {
requests.add(new NetworkRequest(copyDefaultNetworkCapabilitiesForUid(
- nr.networkCapabilities, requestorUid, requestorPackageName),
+ nr.networkCapabilities, asUid, requestorUid, requestorPackageName),
nr.legacyType, nextNetworkRequestId(), nr.type));
}
return requests;
@@ -5961,12 +6182,17 @@
@NonNull
private NetworkCapabilities copyDefaultNetworkCapabilitiesForUid(
- @NonNull final NetworkCapabilities netCapToCopy, @NonNull final int requestorUid,
- @NonNull final String requestorPackageName) {
+ @NonNull final NetworkCapabilities netCapToCopy, final int asUid,
+ final int requestorUid, @NonNull final String requestorPackageName) {
+ // These capabilities are for a TRACK_DEFAULT callback, so:
+ // 1. Remove NET_CAPABILITY_VPN, because it's (currently!) the only difference between
+ // mDefaultRequest and a per-UID default request.
+ // TODO: stop depending on the fact that these two unrelated things happen to be the same
+ // 2. Always set the UIDs to asUid. restrictRequestUidsForCallerAndSetRequestorInfo will
+ // not do this in the case of a privileged application.
final NetworkCapabilities netCap = new NetworkCapabilities(netCapToCopy);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
- netCap.setSingleUid(requestorUid);
- netCap.setUids(new ArraySet<>());
+ netCap.setSingleUid(asUid);
restrictRequestUidsForCallerAndSetRequestorInfo(
netCap, requestorUid, requestorPackageName);
return netCap;
@@ -6047,7 +6273,7 @@
for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
// Currently, all network requests will have the same uids therefore checking the first
// one is sufficient. If/when uids are tracked at the nri level, this can change.
- final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUids();
+ final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUidRanges();
if (null == uids) {
continue;
}
@@ -6078,20 +6304,6 @@
return nai == getDefaultNetwork();
}
- // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
- // changes that would conflict throughout the automerger graph. Having this method temporarily
- // helps with the process of going through with all these dependent changes across the entire
- // tree.
- /**
- * Register a new agent. {@see #registerNetworkAgent} below.
- */
- public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
- LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig) {
- return registerNetworkAgent(na, networkInfo, linkProperties, networkCapabilities,
- currentScore, networkAgentConfig, NetworkProvider.ID_NONE);
- }
-
/**
* Register a new agent with ConnectivityService to handle a network.
*
@@ -6102,7 +6314,7 @@
* later : see {@link #updateLinkProperties}.
* @param networkCapabilities the initial capabilites of this network. They can be updated
* later : see {@link #updateCapabilities}.
- * @param currentScore the initial score of the network. See
+ * @param initialScore the initial score of the network. See
* {@link NetworkAgentInfo#getCurrentScore}.
* @param networkAgentConfig metadata about the network. This is never updated.
* @param providerId the ID of the provider owning this NetworkAgent.
@@ -6110,10 +6322,12 @@
*/
public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
+ @NonNull NetworkScore initialScore, NetworkAgentConfig networkAgentConfig,
+ int providerId) {
Objects.requireNonNull(networkInfo, "networkInfo must not be null");
Objects.requireNonNull(linkProperties, "linkProperties must not be null");
Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null");
+ Objects.requireNonNull(initialScore, "initialScore must not be null");
Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null");
if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
@@ -6125,7 +6339,7 @@
final long token = Binder.clearCallingIdentity();
try {
return registerNetworkAgentInternal(na, networkInfo, linkProperties,
- networkCapabilities, currentScore, networkAgentConfig, providerId, uid);
+ networkCapabilities, initialScore, networkAgentConfig, providerId, uid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -6133,7 +6347,8 @@
private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig, int providerId, int uid) {
+ NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, int providerId,
+ int uid) {
if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
// Strictly, sanitizing here is unnecessary as the capabilities will be sanitized in
// the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
@@ -6499,7 +6714,7 @@
return;
}
- final Set<UidRange> ranges = nai.networkCapabilities.getUids();
+ final Set<UidRange> ranges = nai.networkCapabilities.getUidRanges();
final int vpnAppUid = nai.networkCapabilities.getOwnerUid();
// TODO: this create a window of opportunity for apps to receive traffic between the time
// when the old rules are removed and the time when new rules are added. To fix this,
@@ -6514,6 +6729,11 @@
}
private void updateWakeOnLan(@NonNull LinkProperties lp) {
+ if (mWolSupportedInterfaces == null) {
+ mWolSupportedInterfaces = new ArraySet<>(mResources.get().getStringArray(
+ com.android.connectivity.resources.R.array
+ .config_wakeonlan_supported_interfaces));
+ }
lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName()));
}
@@ -6750,8 +6970,8 @@
final boolean meteredChanged = oldMetered != newMetered;
if (meteredChanged) {
- maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
- mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges);
+ maybeNotifyNetworkBlocked(nai, oldMetered, newMetered,
+ mVpnBlockedUidRanges, mVpnBlockedUidRanges);
}
final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
@@ -6859,8 +7079,8 @@
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
NetworkCapabilities newNc) {
- Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
- Set<UidRange> newRanges = null == newNc ? null : newNc.getUids();
+ Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUidRanges();
+ Set<UidRange> newRanges = null == newNc ? null : newNc.getUidRanges();
if (null == prevRanges) prevRanges = new ArraySet<>();
if (null == newRanges) newRanges = new ArraySet<>();
final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges);
@@ -7096,7 +7316,7 @@
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, includeLocationSensitiveInfo, nri.mUid,
+ nc, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
@@ -7117,7 +7337,7 @@
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, includeLocationSensitiveInfo, nri.mUid,
+ netCap, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
break;
@@ -7784,6 +8004,7 @@
updateCapabilitiesForNetwork(networkAgent);
}
networkAgent.created = true;
+ networkAgent.onNetworkCreated();
}
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
@@ -7852,7 +8073,7 @@
}
}
- private void updateNetworkScore(@NonNull final NetworkAgentInfo nai, final int score) {
+ private void updateNetworkScore(@NonNull final NetworkAgentInfo nai, final NetworkScore score) {
if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + score);
nai.setScore(score);
rematchAllNetworksAndRequests();
@@ -7871,12 +8092,11 @@
return;
}
+ final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
final boolean metered = nai.networkCapabilities.isMetered();
- boolean blocked;
- blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges);
- blocked |= isUidBlockedByRules(nri.mUid, mUidRules.get(nri.mUid),
- metered, mRestrictBackground);
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
+ final boolean vpnBlocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE,
+ getBlockedState(blockedReasons, metered, vpnBlocked));
}
// Notify the requests on this NAI that the network is now lingered.
@@ -7885,6 +8105,21 @@
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
}
+ private static int getBlockedState(int reasons, boolean metered, boolean vpnBlocked) {
+ if (!metered) reasons &= ~BLOCKED_METERED_REASON_MASK;
+ return vpnBlocked
+ ? reasons | BLOCKED_REASON_LOCKDOWN_VPN
+ : reasons & ~BLOCKED_REASON_LOCKDOWN_VPN;
+ }
+
+ private void setUidBlockedReasons(int uid, @BlockedReason int blockedReasons) {
+ if (blockedReasons == BLOCKED_REASON_NONE) {
+ mUidBlockedReasons.delete(uid);
+ } else {
+ mUidBlockedReasons.put(uid, blockedReasons);
+ }
+ }
+
/**
* Notify of the blocked state apps with a registered callback matching a given NAI.
*
@@ -7892,59 +8127,56 @@
* any given nai, all requests need to be considered according to the uid who filed it.
*
* @param nai The target NetworkAgentInfo.
- * @param oldMetered True if the previous network capabilities is metered.
- * @param newRestrictBackground True if data saver is enabled.
+ * @param oldMetered True if the previous network capabilities were metered.
+ * @param newMetered True if the current network capabilities are metered.
+ * @param oldBlockedUidRanges list of UID ranges previously blocked by lockdown VPN.
+ * @param newBlockedUidRanges list of UID ranges blocked by lockdown VPN.
*/
private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
- boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground,
- List<UidRange> oldBlockedUidRanges, List<UidRange> newBlockedUidRanges) {
+ boolean newMetered, List<UidRange> oldBlockedUidRanges,
+ List<UidRange> newBlockedUidRanges) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
- final int uidRules = mUidRules.get(nri.mUid);
- final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked;
- oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges);
- newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
- ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges)
+ final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
+ final boolean oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
+ final boolean newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
+ ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges)
: oldVpnBlocked;
- oldBlocked = oldVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, oldMetered,
- oldRestrictBackground);
- newBlocked = newVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, newMetered,
- newRestrictBackground);
-
- if (oldBlocked != newBlocked) {
+ final int oldBlockedState = getBlockedState(blockedReasons, oldMetered, oldVpnBlocked);
+ final int newBlockedState = getBlockedState(blockedReasons, newMetered, newVpnBlocked);
+ if (oldBlockedState != newBlockedState) {
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
- encodeBool(newBlocked));
+ newBlockedState);
}
}
}
/**
- * Notify apps with a given UID of the new blocked state according to new uid rules.
+ * Notify apps with a given UID of the new blocked state according to new uid state.
* @param uid The uid for which the rules changed.
- * @param newRules The new rules to apply.
+ * @param blockedReasons The reasons for why an uid is blocked.
*/
- private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) {
+ private void maybeNotifyNetworkBlockedForNewState(int uid, @BlockedReason int blockedReasons) {
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
final boolean metered = nai.networkCapabilities.isMetered();
final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
- final boolean oldBlocked, newBlocked;
- oldBlocked = vpnBlocked || isUidBlockedByRules(
- uid, mUidRules.get(uid), metered, mRestrictBackground);
- newBlocked = vpnBlocked || isUidBlockedByRules(
- uid, newRules, metered, mRestrictBackground);
- if (oldBlocked == newBlocked) {
+
+ final int oldBlockedState = getBlockedState(
+ mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked);
+ final int newBlockedState = getBlockedState(blockedReasons, metered, vpnBlocked);
+ if (oldBlockedState == newBlockedState) {
continue;
}
- final int arg = encodeBool(newBlocked);
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
- if (nri != null && nri.mUid == uid) {
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg);
+ if (nri != null && nri.mAsUid == uid) {
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
+ newBlockedState);
}
}
}
@@ -8075,15 +8307,15 @@
@Override
public String getCaptivePortalServerUrl() {
enforceNetworkStackOrSettingsPermission();
- String settingUrl = mContext.getResources().getString(
- R.string.config_networkCaptivePortalServerUrl);
+ String settingUrl = mResources.get().getString(
+ com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
if (!TextUtils.isEmpty(settingUrl)) {
return settingUrl;
}
settingUrl = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+ ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL);
if (!TextUtils.isEmpty(settingUrl)) {
return settingUrl;
}
@@ -8165,11 +8397,11 @@
// restore private DNS settings to default mode (opportunistic)
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
+ ConnectivitySettingsManager.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
}
Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
+ ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null);
}
@Override
@@ -8282,7 +8514,7 @@
final NetworkAgentInfo vpn = getVpnForUid(uid);
if (vpn == null || getVpnType(vpn) != VpnManager.TYPE_VPN_SERVICE
- || vpn.networkCapabilities.getOwnerUid() != Binder.getCallingUid()) {
+ || vpn.networkCapabilities.getOwnerUid() != mDeps.getCallingUid()) {
return INVALID_UID;
}
@@ -8708,7 +8940,7 @@
// nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in
// handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the
// callback's binder death.
- final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId);
+ final NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, requestWithId);
final ConnectivityDiagnosticsCallbackInfo cbInfo =
new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName);
@@ -8874,13 +9106,13 @@
private int transportTypeToLegacyType(int type) {
switch (type) {
case NetworkCapabilities.TRANSPORT_CELLULAR:
- return ConnectivityManager.TYPE_MOBILE;
+ return TYPE_MOBILE;
case NetworkCapabilities.TRANSPORT_WIFI:
- return ConnectivityManager.TYPE_WIFI;
+ return TYPE_WIFI;
case NetworkCapabilities.TRANSPORT_BLUETOOTH:
- return ConnectivityManager.TYPE_BLUETOOTH;
+ return TYPE_BLUETOOTH;
case NetworkCapabilities.TRANSPORT_ETHERNET:
- return ConnectivityManager.TYPE_ETHERNET;
+ return TYPE_ETHERNET;
default:
loge("Unexpected transport in transportTypeToLegacyType: " + type);
}
@@ -8921,13 +9153,13 @@
if (networkAgent.networkCapabilities.hasTransport(
NetworkCapabilities.TRANSPORT_CELLULAR)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
+ ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE,
10);
type = NetworkCapabilities.TRANSPORT_CELLULAR;
} else if (networkAgent.networkCapabilities.hasTransport(
NetworkCapabilities.TRANSPORT_WIFI)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+ ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI,
15);
type = NetworkCapabilities.TRANSPORT_WIFI;
} else {
@@ -9095,6 +9327,143 @@
mQosCallbackTracker.unregisterCallback(callback);
}
+ // Network preference per-profile and OEM network preferences can't be set at the same
+ // time, because it is unclear what should happen if both preferences are active for
+ // one given UID. To make it possible, the stack would have to clarify what would happen
+ // in case both are active at the same time. The implementation may have to be adjusted
+ // to implement the resulting rules. For example, a priority could be defined between them,
+ // where the OEM preference would be considered less or more important than the enterprise
+ // preference ; this would entail implementing the priorities somehow, e.g. by doing
+ // UID arithmetic with UID ranges or passing a priority to netd so that the routing rules
+ // are set at the right level. Other solutions are possible, e.g. merging of the
+ // preferences for the relevant UIDs.
+ private static void throwConcurrentPreferenceException() {
+ throw new IllegalStateException("Can't set NetworkPreferenceForUser and "
+ + "set OemNetworkPreference at the same time");
+ }
+
+ /**
+ * Request that a user profile is put by default on a network matching a given preference.
+ *
+ * See the documentation for the individual preferences for a description of the supported
+ * behaviors.
+ *
+ * @param profile the profile concerned.
+ * @param preference the preference for this profile, as one of the PROFILE_NETWORK_PREFERENCE_*
+ * constants.
+ * @param listener an optional listener to listen for completion of the operation.
+ */
+ @Override
+ public void setProfileNetworkPreference(@NonNull final UserHandle profile,
+ @ConnectivityManager.ProfileNetworkPreference final int preference,
+ @Nullable final IOnCompleteListener listener) {
+ Objects.requireNonNull(profile);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ if (DBG) {
+ log("setProfileNetworkPreference " + profile + " to " + preference);
+ }
+ if (profile.getIdentifier() < 0) {
+ throw new IllegalArgumentException("Must explicitly specify a user handle ("
+ + "UserHandle.CURRENT not supported)");
+ }
+ final UserManager um;
+ try {
+ um = mContext.createContextAsUser(profile, 0 /* flags */)
+ .getSystemService(UserManager.class);
+ } catch (IllegalStateException e) {
+ throw new IllegalArgumentException("Profile does not exist");
+ }
+ if (!um.isManagedProfile()) {
+ throw new IllegalArgumentException("Profile must be a managed profile");
+ }
+ // Strictly speaking, mOemNetworkPreferences should only be touched on the
+ // handler thread. However it is an immutable object, so reading the reference is
+ // safe - it's just possible the value is slightly outdated. For the final check,
+ // see #handleSetProfileNetworkPreference. But if this can be caught here it is a
+ // lot easier to understand, so opportunistically check it.
+ if (!mOemNetworkPreferences.isEmpty()) {
+ throwConcurrentPreferenceException();
+ }
+ final NetworkCapabilities nc;
+ switch (preference) {
+ case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT:
+ nc = null;
+ break;
+ case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE:
+ final UidRange uids = UidRange.createForUser(profile);
+ nc = createDefaultNetworkCapabilitiesForUidRange(uids);
+ nc.addCapability(NET_CAPABILITY_ENTERPRISE);
+ nc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Invalid preference in setProfileNetworkPreference");
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_PROFILE_NETWORK_PREFERENCE,
+ new Pair<>(new ProfileNetworkPreferences.Preference(profile, nc), listener)));
+ }
+
+ private void validateNetworkCapabilitiesOfProfileNetworkPreference(
+ @Nullable final NetworkCapabilities nc) {
+ if (null == nc) return; // Null caps are always allowed. It means to remove the setting.
+ ensureRequestableCapabilities(nc);
+ }
+
+ private ArraySet<NetworkRequestInfo> createNrisFromProfileNetworkPreferences(
+ @NonNull final ProfileNetworkPreferences prefs) {
+ final ArraySet<NetworkRequestInfo> result = new ArraySet<>();
+ for (final ProfileNetworkPreferences.Preference pref : prefs.preferences) {
+ // The NRI for a user should be comprised of two layers:
+ // - The request for the capabilities
+ // - The request for the default network, for fallback. Create an image of it to
+ // have the correct UIDs in it (also a request can only be part of one NRI, because
+ // of lookups in 1:1 associations like mNetworkRequests).
+ // Note that denying a fallback can be implemented simply by not adding the second
+ // request.
+ final ArrayList<NetworkRequest> nrs = new ArrayList<>();
+ nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
+ nrs.add(createDefaultRequest());
+ setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
+ final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs);
+ result.add(nri);
+ }
+ return result;
+ }
+
+ private void handleSetProfileNetworkPreference(
+ @NonNull final ProfileNetworkPreferences.Preference preference,
+ @Nullable final IOnCompleteListener listener) {
+ // setProfileNetworkPreference and setOemNetworkPreference are mutually exclusive, in
+ // particular because it's not clear what preference should win in case both apply
+ // to the same app.
+ // The binder call has already checked this, but as mOemNetworkPreferences is only
+ // touched on the handler thread, it's theoretically not impossible that it has changed
+ // since.
+ if (!mOemNetworkPreferences.isEmpty()) {
+ // This may happen on a device with an OEM preference set when a user is removed.
+ // In this case, it's safe to ignore. In particular this happens in the tests.
+ loge("handleSetProfileNetworkPreference, but OEM network preferences not empty");
+ return;
+ }
+
+ validateNetworkCapabilitiesOfProfileNetworkPreference(preference.capabilities);
+
+ mProfileNetworkPreferences = mProfileNetworkPreferences.plus(preference);
+ final ArraySet<NetworkRequestInfo> nris =
+ createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences);
+ replaceDefaultNetworkRequestsForPreference(nris);
+ // Finally, rematch.
+ rematchAllNetworksAndRequests();
+
+ if (null != listener) {
+ try {
+ listener.onComplete();
+ } catch (RemoteException e) {
+ loge("Listener for setProfileNetworkPreference has died");
+ }
+ }
+ }
+
private void enforceAutomotiveDevice() {
final boolean isAutomotiveDevice =
mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
@@ -9113,17 +9482,26 @@
* Calling this will overwrite the existing preference.
*
* @param preference {@link OemNetworkPreferences} The application network preference to be set.
- * @param listener {@link ConnectivityManager.OnSetOemNetworkPreferenceListener} Listener used
+ * @param listener {@link ConnectivityManager.OnCompleteListener} Listener used
* to communicate completion of setOemNetworkPreference();
*/
@Override
public void setOemNetworkPreference(
@NonNull final OemNetworkPreferences preference,
- @Nullable final IOnSetOemNetworkPreferenceListener listener) {
+ @Nullable final IOnCompleteListener listener) {
enforceAutomotiveDevice();
enforceOemNetworkPreferencesPermission();
+ if (!mProfileNetworkPreferences.isEmpty()) {
+ // Strictly speaking, mProfileNetworkPreferences should only be touched on the
+ // handler thread. However it is an immutable object, so reading the reference is
+ // safe - it's just possible the value is slightly outdated. For the final check,
+ // see #handleSetOemPreference. But if this can be caught here it is a
+ // lot easier to understand, so opportunistically check it.
+ throwConcurrentPreferenceException();
+ }
+
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
validateOemNetworkPreferences(preference);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
@@ -9142,11 +9520,22 @@
private void handleSetOemNetworkPreference(
@NonNull final OemNetworkPreferences preference,
- @Nullable final IOnSetOemNetworkPreferenceListener listener) {
+ @Nullable final IOnCompleteListener listener) {
Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
if (DBG) {
log("set OEM network preferences :" + preference.toString());
}
+ // setProfileNetworkPreference and setOemNetworkPreference are mutually exclusive, in
+ // particular because it's not clear what preference should win in case both apply
+ // to the same app.
+ // The binder call has already checked this, but as mOemNetworkPreferences is only
+ // touched on the handler thread, it's theoretically not impossible that it has changed
+ // since.
+ if (!mProfileNetworkPreferences.isEmpty()) {
+ logwtf("handleSetOemPreference, but per-profile network preferences not empty");
+ return;
+ }
+
final ArraySet<NetworkRequestInfo> nris =
new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
replaceDefaultNetworkRequestsForPreference(nris);
@@ -9206,7 +9595,7 @@
}
// Include this nri if it will be tracked by the new per-app default requests.
final boolean isNriGoingToBeTracked =
- getDefaultRequestTrackingUid(nri.mUid) != mDefaultRequest;
+ getDefaultRequestTrackingUid(nri.mAsUid) != mDefaultRequest;
if (isNriGoingToBeTracked) {
defaultCallbackRequests.add(nri);
}
@@ -9228,7 +9617,7 @@
final ArraySet<NetworkRequestInfo> callbackRequestsToRegister = new ArraySet<>();
for (final NetworkRequestInfo callbackRequest : perAppCallbackRequestsForUpdate) {
final NetworkRequestInfo trackingNri =
- getDefaultRequestTrackingUid(callbackRequest.mUid);
+ getDefaultRequestTrackingUid(callbackRequest.mAsUid);
// If this nri is not being tracked, the change it back to an untracked nri.
if (trackingNri == mDefaultRequest) {
@@ -9238,21 +9627,20 @@
continue;
}
- final String requestorPackageName =
- callbackRequest.mRequests.get(0).getRequestorPackageName();
+ final NetworkRequest request = callbackRequest.mRequests.get(0);
callbackRequestsToRegister.add(new NetworkRequestInfo(
callbackRequest,
copyNetworkRequestsForUid(
- trackingNri.mRequests, callbackRequest.mUid, requestorPackageName)));
+ trackingNri.mRequests, callbackRequest.mAsUid,
+ callbackRequest.mUid, request.getRequestorPackageName())));
}
return callbackRequestsToRegister;
}
private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
@NonNull final Set<UidRange> uids) {
- final Set<UidRange> ranges = new ArraySet<>(uids);
for (final NetworkRequest req : requests) {
- req.networkCapabilities.setUids(ranges);
+ req.networkCapabilities.setUids(UidRange.toIntRanges(uids));
}
}
@@ -9348,7 +9736,7 @@
ranges.add(new UidRange(uid, uid));
}
setNetworkRequestUids(requests, ranges);
- return new NetworkRequestInfo(requests);
+ return new NetworkRequestInfo(Process.myUid(), requests);
}
private NetworkRequest createUnmeteredNetworkRequest() {
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index ee61067..f566277 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -90,7 +90,12 @@
mCm = mContext.getSystemService(ConnectivityManager.class);
mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
TEST_NETWORK_PROVIDER_NAME);
- mCm.registerNetworkProvider(mNetworkProvider);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCm.registerNetworkProvider(mNetworkProvider);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 4f6b530..ffeb77d 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -16,23 +16,23 @@
package com.android.server.connectivity;
-import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
+import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
-import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES;
-import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
-import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
-import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
import android.net.IDnsResolver;
import android.net.InetAddresses;
import android.net.LinkProperties;
@@ -127,13 +127,17 @@
private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
- public static PrivateDnsConfig getPrivateDnsConfig(ContentResolver cr) {
- final String mode = getPrivateDnsMode(cr);
+ /**
+ * Get PrivateDnsConfig.
+ */
+ public static PrivateDnsConfig getPrivateDnsConfig(Context context) {
+ final String mode = ConnectivityManager.getPrivateDnsMode(context);
final boolean useTls = !TextUtils.isEmpty(mode) && !PRIVATE_DNS_MODE_OFF.equals(mode);
if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(mode)) {
- final String specifier = getStringSetting(cr, PRIVATE_DNS_SPECIFIER);
+ final String specifier = getStringSetting(context.getContentResolver(),
+ PRIVATE_DNS_SPECIFIER);
return new PrivateDnsConfig(specifier, null);
}
@@ -268,7 +272,7 @@
}
public PrivateDnsConfig getPrivateDnsConfig() {
- return getPrivateDnsConfig(mContentResolver);
+ return getPrivateDnsConfig(mContext);
}
public void removeNetwork(Network network) {
@@ -479,13 +483,6 @@
return result;
}
- private static String getPrivateDnsMode(ContentResolver cr) {
- String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
- if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
- if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
- return mode;
- }
-
private static String getStringSetting(ContentResolver cr, String which) {
return Settings.Global.getString(cr, which);
}
diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java
new file mode 100644
index 0000000..028cfee
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/FullScore.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.net.NetworkAgentConfig;
+import android.net.NetworkCapabilities;
+import android.net.NetworkScore;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.StringJoiner;
+
+/**
+ * This class represents how desirable a network is.
+ *
+ * FullScore is very similar to NetworkScore, but it contains the bits that are managed
+ * by ConnectivityService. This provides static guarantee that all users must know whether
+ * they are handling a score that had the CS-managed bits set.
+ */
+public class FullScore {
+ // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
+ // a migration.
+ private final int mLegacyInt;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"POLICY_"}, value = {
+ POLICY_IS_VALIDATED,
+ POLICY_IS_VPN,
+ POLICY_EVER_USER_SELECTED,
+ POLICY_ACCEPT_UNVALIDATED
+ })
+ public @interface Policy {
+ }
+
+ // Agent-managed policies are in NetworkScore. They start from 1.
+ // CS-managed policies, counting from 63 downward
+ // This network is validated. CS-managed because the source of truth is in NetworkCapabilities.
+ /** @hide */
+ public static final int POLICY_IS_VALIDATED = 63;
+
+ // This is a VPN and behaves as one for scoring purposes.
+ /** @hide */
+ public static final int POLICY_IS_VPN = 62;
+
+ // This network has been selected by the user manually from settings or a 3rd party app
+ // at least once. {@see NetworkAgentConfig#explicitlySelected}.
+ /** @hide */
+ public static final int POLICY_EVER_USER_SELECTED = 61;
+
+ // The user has indicated in UI that this network should be used even if it doesn't
+ // validate. {@see NetworkAgentConfig#acceptUnvalidated}.
+ /** @hide */
+ public static final int POLICY_ACCEPT_UNVALIDATED = 60;
+
+ // To help iterate when printing
+ @VisibleForTesting
+ static final int MIN_CS_MANAGED_POLICY = POLICY_ACCEPT_UNVALIDATED;
+ @VisibleForTesting
+ static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED;
+
+ @VisibleForTesting
+ static @NonNull String policyNameOf(final int policy) {
+ switch (policy) {
+ case POLICY_IS_VALIDATED: return "IS_VALIDATED";
+ case POLICY_IS_VPN: return "IS_VPN";
+ case POLICY_EVER_USER_SELECTED: return "EVER_USER_SELECTED";
+ case POLICY_ACCEPT_UNVALIDATED: return "ACCEPT_UNVALIDATED";
+ }
+ throw new IllegalArgumentException("Unknown policy : " + policy);
+ }
+
+ // Bitmask of all the policies applied to this score.
+ private final long mPolicies;
+
+ FullScore(final int legacyInt, final long policies) {
+ mLegacyInt = legacyInt;
+ mPolicies = policies;
+ }
+
+ /**
+ * Given a score supplied by the NetworkAgent and CS-managed objects, produce a full score.
+ *
+ * @param score the score supplied by the agent
+ * @param caps the NetworkCapabilities of the network
+ * @param config the NetworkAgentConfig of the network
+ * @return an FullScore that is appropriate to use for ranking.
+ */
+ public static FullScore fromNetworkScore(@NonNull final NetworkScore score,
+ @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config) {
+ return withPolicies(score.getLegacyInt(), caps.hasCapability(NET_CAPABILITY_VALIDATED),
+ caps.hasTransport(TRANSPORT_VPN),
+ config.explicitlySelected,
+ config.acceptUnvalidated);
+ }
+
+ /**
+ * Return a new score given updated caps and config.
+ *
+ * @param caps the NetworkCapabilities of the network
+ * @param config the NetworkAgentConfig of the network
+ * @return a score with the policies from the arguments reset
+ */
+ public FullScore mixInScore(@NonNull final NetworkCapabilities caps,
+ @NonNull final NetworkAgentConfig config) {
+ return withPolicies(mLegacyInt, caps.hasCapability(NET_CAPABILITY_VALIDATED),
+ caps.hasTransport(TRANSPORT_VPN),
+ config.explicitlySelected,
+ config.acceptUnvalidated);
+ }
+
+ private static FullScore withPolicies(@NonNull final int legacyInt,
+ final boolean isValidated,
+ final boolean isVpn,
+ final boolean everUserSelected,
+ final boolean acceptUnvalidated) {
+ return new FullScore(legacyInt,
+ (isValidated ? 1L << POLICY_IS_VALIDATED : 0)
+ | (isVpn ? 1L << POLICY_IS_VPN : 0)
+ | (everUserSelected ? 1L << POLICY_EVER_USER_SELECTED : 0)
+ | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0));
+ }
+
+ /**
+ * For backward compatibility, get the legacy int.
+ * This will be removed before S is published.
+ */
+ public int getLegacyInt() {
+ return getLegacyInt(false /* pretendValidated */);
+ }
+
+ public int getLegacyIntAsValidated() {
+ return getLegacyInt(true /* pretendValidated */);
+ }
+
+ // TODO : remove these two constants
+ // Penalty applied to scores of Networks that have not been validated.
+ private static final int UNVALIDATED_SCORE_PENALTY = 40;
+
+ // Score for a network that can be used unvalidated
+ private static final int ACCEPT_UNVALIDATED_NETWORK_SCORE = 100;
+
+ private int getLegacyInt(boolean pretendValidated) {
+ // If the user has chosen this network at least once, give it the maximum score when
+ // checking to pretend it's validated, or if it doesn't need to validate because the
+ // user said to use it even if it doesn't validate.
+ // This ensures that networks that have been selected in UI are not torn down before the
+ // user gets a chance to prefer it when a higher-scoring network (e.g., Ethernet) is
+ // available.
+ if (hasPolicy(POLICY_EVER_USER_SELECTED)
+ && (hasPolicy(POLICY_ACCEPT_UNVALIDATED) || pretendValidated)) {
+ return ACCEPT_UNVALIDATED_NETWORK_SCORE;
+ }
+
+ int score = mLegacyInt;
+ // Except for VPNs, networks are subject to a penalty for not being validated.
+ // Apply the penalty unless the network is a VPN, or it's validated or pretending to be.
+ if (!hasPolicy(POLICY_IS_VALIDATED) && !pretendValidated && !hasPolicy(POLICY_IS_VPN)) {
+ score -= UNVALIDATED_SCORE_PENALTY;
+ }
+ if (score < 0) score = 0;
+ return score;
+ }
+
+ /**
+ * @return whether this score has a particular policy.
+ */
+ @VisibleForTesting
+ public boolean hasPolicy(final int policy) {
+ return 0 != (mPolicies & (1L << policy));
+ }
+
+ // Example output :
+ // Score(50 ; Policies : EVER_USER_SELECTED&IS_VALIDATED)
+ @Override
+ public String toString() {
+ final StringJoiner sj = new StringJoiner(
+ "&", // delimiter
+ "Score(" + mLegacyInt + " ; Policies : ", // prefix
+ ")"); // suffix
+ for (int i = NetworkScore.MIN_AGENT_MANAGED_POLICY;
+ i <= NetworkScore.MAX_AGENT_MANAGED_POLICY; ++i) {
+ if (hasPolicy(i)) sj.add(policyNameOf(i));
+ }
+ for (int i = MIN_CS_MANAGED_POLICY; i <= MAX_CS_MANAGED_POLICY; ++i) {
+ if (hasPolicy(i)) sj.add(policyNameOf(i));
+ }
+ return sj.toString();
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 803cc9d..97df5bf 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -25,6 +25,8 @@
import android.net.CaptivePortalData;
import android.net.IDnsResolver;
import android.net.INetd;
+import android.net.INetworkAgent;
+import android.net.INetworkAgentRegistry;
import android.net.INetworkMonitor;
import android.net.LinkProperties;
import android.net.NattKeepalivePacketData;
@@ -35,6 +37,7 @@
import android.net.NetworkInfo;
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkStateSnapshot;
import android.net.QosCallbackException;
import android.net.QosFilter;
@@ -46,12 +49,11 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
-import com.android.connectivity.aidl.INetworkAgent;
-import com.android.connectivity.aidl.INetworkAgentRegistry;
import com.android.internal.util.WakeupMessage;
import com.android.server.ConnectivityService;
@@ -302,8 +304,9 @@
// validated).
private boolean mInactive;
- // This represents the quality of the network with no clear scale.
- private int mScore;
+ // This represents the quality of the network. As opposed to NetworkScore, FullScore includes
+ // the ConnectivityService-managed bits.
+ private FullScore mScore;
// The list of NetworkRequests being satisfied by this Network.
private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
@@ -338,7 +341,8 @@
private final QosCallbackTracker mQosCallbackTracker;
public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
- @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, int score, Context context,
+ @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc,
+ @NonNull NetworkScore score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
QosCallbackTracker qosCallbackTracker, ConnectivityService.Dependencies deps) {
@@ -354,12 +358,12 @@
networkInfo = info;
linkProperties = lp;
networkCapabilities = nc;
- mScore = score;
+ networkAgentConfig = config;
+ setScore(score); // uses members networkCapabilities and networkAgentConfig
clatd = new Nat464Xlat(this, netd, dnsResolver, deps);
mConnService = connService;
mContext = context;
mHandler = handler;
- networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
mQosCallbackTracker = qosCallbackTracker;
@@ -573,6 +577,28 @@
}
}
+ /**
+ * Notify the NetworkAgent that the network is successfully connected.
+ */
+ public void onNetworkCreated() {
+ try {
+ networkAgent.onNetworkCreated();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending network created event", e);
+ }
+ }
+
+ /**
+ * Notify the NetworkAgent that the network is disconnected and destroyed.
+ */
+ public void onNetworkDisconnected() {
+ try {
+ networkAgent.onNetworkDisconnected();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending network disconnected event", e);
+ }
+ }
+
// TODO: consider moving out of NetworkAgentInfo into its own class
private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
private final Handler mHandler;
@@ -603,9 +629,9 @@
}
@Override
- public void sendScore(int score) {
- mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED, score, 0,
- new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
+ public void sendScore(@NonNull final NetworkScore score) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED,
+ new Pair<>(NetworkAgentInfo.this, score)).sendToTarget();
}
@Override
@@ -630,7 +656,13 @@
@Override
public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
- mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes);
+ mQosCallbackTracker.sendEventEpsQosSessionAvailable(qosCallbackId, session, attributes);
+ }
+
+ @Override
+ public void sendNrQosSessionAvailable(final int qosCallbackId, final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ mQosCallbackTracker.sendEventNrQosSessionAvailable(qosCallbackId, session, attributes);
}
@Override
@@ -665,6 +697,7 @@
@NonNull final NetworkCapabilities nc) {
final NetworkCapabilities oldNc = networkCapabilities;
networkCapabilities = nc;
+ mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig);
final NetworkMonitorManager nm = mNetworkMonitor;
if (nm != null) {
nm.notifyNetworkCapabilitiesChanged(nc);
@@ -717,6 +750,7 @@
break;
case LISTEN:
+ case LISTEN_FOR_BEST:
case TRACK_DEFAULT:
case TRACK_SYSTEM_DEFAULT:
break;
@@ -841,30 +875,6 @@
return isVPN();
}
- private int getCurrentScore(boolean pretendValidated) {
- // TODO: We may want to refactor this into a NetworkScore class that takes a base score from
- // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
- // score. The NetworkScore class would provide a nice place to centralize score constants
- // so they are not scattered about the transports.
-
- // If this network is explicitly selected and the user has decided to use it even if it's
- // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly
- // selected and we're trying to see what its score could be. This ensures that we don't tear
- // down an explicitly selected network before the user gets a chance to prefer it when
- // a higher-scoring network (e.g., Ethernet) is available.
- if (networkAgentConfig.explicitlySelected
- && (networkAgentConfig.acceptUnvalidated || pretendValidated)) {
- return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
- }
-
- int score = mScore;
- if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
- score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
- }
- if (score < 0) score = 0;
- return score;
- }
-
// Return true on devices configured to ignore score penalty for wifi networks
// that become unvalidated (b/31075769).
private boolean ignoreWifiUnvalidationPenalty() {
@@ -877,17 +887,29 @@
// Get the current score for this Network. This may be modified from what the
// NetworkAgent sent, as it has modifiers applied to it.
public int getCurrentScore() {
- return getCurrentScore(false);
+ return mScore.getLegacyInt();
}
// Get the current score for this Network as if it was validated. This may be modified from
// what the NetworkAgent sent, as it has modifiers applied to it.
public int getCurrentScoreAsValidated() {
- return getCurrentScore(true);
+ return mScore.getLegacyIntAsValidated();
}
- public void setScore(final int score) {
- mScore = score;
+ /**
+ * Mix-in the ConnectivityService-managed bits in the score.
+ */
+ public void setScore(final NetworkScore score) {
+ mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig);
+ }
+
+ /**
+ * Update the ConnectivityService-managed bits in the score.
+ *
+ * Call this after updating the network agent config.
+ */
+ public void updateScoreForNetworkAgentConfigUpdate() {
+ mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig);
}
/**
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 508739f..0c0d459 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -28,6 +28,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.net.ConnectivityResources;
import android.net.NetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo;
@@ -40,7 +42,7 @@
import android.util.SparseIntArray;
import android.widget.Toast;
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -82,6 +84,7 @@
// The context is for the current user (system server)
private final Context mContext;
+ private final Resources mResources;
private final TelephonyManager mTelephonyManager;
// The notification manager is created from a context for User.ALL, so notifications
// will be sent to all users.
@@ -96,6 +99,7 @@
(NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */)
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationTypeMap = new SparseIntArray();
+ mResources = new ConnectivityResources(mContext).get();
}
@VisibleForTesting
@@ -113,20 +117,19 @@
return -1;
}
- private static String getTransportName(final int transportType) {
- Resources r = Resources.getSystem();
- String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
+ private String getTransportName(final int transportType) {
+ String[] networkTypes = mResources.getStringArray(R.array.network_switch_type_name);
try {
return networkTypes[transportType];
} catch (IndexOutOfBoundsException e) {
- return r.getString(R.string.network_switch_type_name_unknown);
+ return mResources.getString(R.string.network_switch_type_name_unknown);
}
}
private static int getIcon(int transportType) {
return (transportType == TRANSPORT_WIFI)
- ? R.drawable.stat_notify_wifi_in_range : // TODO: Distinguish ! from ?.
- R.drawable.stat_notify_rssi_in_range;
+ ? R.drawable.stat_notify_wifi_in_range // TODO: Distinguish ! from ?.
+ : R.drawable.stat_notify_rssi_in_range;
}
/**
@@ -156,7 +159,7 @@
final String tag = tagFor(id);
final int eventId = notifyType.eventId;
final int transportType;
- final String name;
+ final CharSequence name;
if (nai != null) {
transportType = approximateTransportType(nai);
final String extraInfo = nai.networkInfo.getExtraInfo();
@@ -194,10 +197,10 @@
tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
}
- Resources r = mContext.getResources();
+ final Resources r = mResources;
final CharSequence title;
final CharSequence details;
- int icon = getIcon(transportType);
+ Icon icon = Icon.createWithResource(r, getIcon(transportType));
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet, name);
details = r.getString(R.string.wifi_no_internet_detailed);
@@ -272,8 +275,7 @@
.setSmallIcon(icon)
.setAutoCancel(true)
.setTicker(title)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
+ .setColor(mContext.getColor(android.R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentIntent(intent)
.setLocalOnly(true)
@@ -353,7 +355,7 @@
public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
String fromTransport = getTransportName(approximateTransportType(fromNai));
String toTransport = getTransportName(approximateTransportType(toNai));
- String text = mContext.getResources().getString(
+ String text = mResources.getString(
R.string.network_switch_metered_toast, fromTransport, toTransport);
Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 488677a..3711679 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -271,6 +271,13 @@
return mApps.containsKey(uid);
}
+ /**
+ * Returns whether the given uid has permission to use restricted networks.
+ */
+ public synchronized boolean hasRestrictedNetworksPermission(int uid) {
+ return Boolean.TRUE.equals(mApps.get(uid));
+ }
+
private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
List<Integer> network = new ArrayList<>();
List<Integer> system = new ArrayList<>();
diff --git a/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java b/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java
new file mode 100644
index 0000000..dd2815d
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/ProfileNetworkPreferences.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.NetworkCapabilities;
+import android.os.UserHandle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A data class containing all the per-profile network preferences.
+ *
+ * A given profile can only have one preference.
+ */
+public class ProfileNetworkPreferences {
+ /**
+ * A single preference, as it applies to a given user profile.
+ */
+ public static class Preference {
+ @NonNull public final UserHandle user;
+ // Capabilities are only null when sending an object to remove the setting for a user
+ @Nullable public final NetworkCapabilities capabilities;
+
+ public Preference(@NonNull final UserHandle user,
+ @Nullable final NetworkCapabilities capabilities) {
+ this.user = user;
+ this.capabilities = null == capabilities ? null : new NetworkCapabilities(capabilities);
+ }
+
+ /** toString */
+ public String toString() {
+ return "[ProfileNetworkPreference user=" + user + " caps=" + capabilities + "]";
+ }
+ }
+
+ @NonNull public final List<Preference> preferences;
+
+ public ProfileNetworkPreferences() {
+ preferences = Collections.EMPTY_LIST;
+ }
+
+ private ProfileNetworkPreferences(@NonNull final List<Preference> list) {
+ preferences = Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Returns a new object consisting of this object plus the passed preference.
+ *
+ * If a preference already exists for the same user, it will be replaced by the passed
+ * preference. Passing a Preference object containing a null capabilities object is equivalent
+ * to (and indeed, implemented as) removing the preference for this user.
+ */
+ public ProfileNetworkPreferences plus(@NonNull final Preference pref) {
+ final ArrayList<Preference> newPrefs = new ArrayList<>();
+ for (final Preference existingPref : preferences) {
+ if (!existingPref.user.equals(pref.user)) {
+ newPrefs.add(existingPref);
+ }
+ }
+ if (null != pref.capabilities) {
+ newPrefs.add(pref);
+ }
+ return new ProfileNetworkPreferences(newPrefs);
+ }
+
+ public boolean isEmpty() {
+ return preferences.isEmpty();
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index d83ff83..f572b46 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -16,10 +16,10 @@
package com.android.server.connectivity;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC;
-import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_HOST;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PAC;
+import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PORT;
import static android.provider.Settings.Global.HTTP_PROXY;
import android.annotation.NonNull;
@@ -27,6 +27,8 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.net.Network;
+import android.net.PacProxyManager;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -36,6 +38,7 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.net.module.util.ProxyUtils;
@@ -67,7 +70,7 @@
// is not set. Individual networks have their own settings that override this. This member
// is set through setDefaultProxy, which is called when the default network changes proxies
// in its LinkProperties, or when ConnectivityService switches to a new default network, or
- // when PacProxyInstaller resolves the proxy.
+ // when PacProxyService resolves the proxy.
@Nullable
@GuardedBy("mProxyLock")
private volatile ProxyInfo mDefaultProxy = null;
@@ -77,16 +80,31 @@
private final Handler mConnectivityServiceHandler;
- // The object responsible for Proxy Auto Configuration (PAC).
- @NonNull
- private final PacProxyInstaller mPacProxyInstaller;
+ private final PacProxyManager mPacProxyManager;
+
+ private class PacProxyInstalledListener implements PacProxyManager.PacProxyInstalledListener {
+ private final int mEvent;
+
+ PacProxyInstalledListener(int event) {
+ mEvent = event;
+ }
+
+ public void onPacProxyInstalled(@Nullable Network network, @NonNull ProxyInfo proxy) {
+ mConnectivityServiceHandler
+ .sendMessage(mConnectivityServiceHandler
+ .obtainMessage(mEvent, new Pair<>(network, proxy)));
+ }
+ }
public ProxyTracker(@NonNull final Context context,
@NonNull final Handler connectivityServiceInternalHandler, final int pacChangedEvent) {
mContext = context;
mConnectivityServiceHandler = connectivityServiceInternalHandler;
- mPacProxyInstaller = new PacProxyInstaller(
- context, connectivityServiceInternalHandler, pacChangedEvent);
+ mPacProxyManager = context.getSystemService(PacProxyManager.class);
+
+ PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent);
+ mPacProxyManager.addPacProxyInstalledListener(
+ mConnectivityServiceHandler::post, listener);
}
// Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
@@ -182,7 +200,7 @@
if (!TextUtils.isEmpty(pacFileUrl)) {
mConnectivityServiceHandler.post(
- () -> mPacProxyInstaller.setCurrentProxyScriptUrl(proxyProperties));
+ () -> mPacProxyManager.setCurrentProxyScriptUrl(proxyProperties));
}
}
}
@@ -226,9 +244,9 @@
final ProxyInfo defaultProxy = getDefaultProxy();
final ProxyInfo proxyInfo = null != defaultProxy ?
defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
+ mPacProxyManager.setCurrentProxyScriptUrl(proxyInfo);
- if (mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo)
- == PacProxyInstaller.DONT_SEND_BROADCAST) {
+ if (!shouldSendBroadcast(proxyInfo)) {
return;
}
if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
@@ -244,6 +262,10 @@
}
}
+ private boolean shouldSendBroadcast(ProxyInfo proxy) {
+ return Uri.EMPTY.equals(proxy.getPacFileUrl()) || proxy.getPort() > 0;
+ }
+
/**
* Sets the global proxy in memory. Also writes the values to the global settings of the device.
*
@@ -308,10 +330,10 @@
return;
}
- // This call could be coming from the PacProxyInstaller, containing the port of the
+ // This call could be coming from the PacProxyService, containing the port of the
// local proxy. If this new proxy matches the global proxy then copy this proxy to the
// global (to get the correct local port), and send a broadcast.
- // TODO: Switch PacProxyInstaller to have its own message to send back rather than
+ // TODO: Switch PacProxyService to have its own message to send back rather than
// reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
if ((mGlobalProxy != null) && (proxyInfo != null)
&& (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
index 0f5400d..534dbe7 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -27,6 +27,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import java.util.Objects;
@@ -146,13 +147,23 @@
mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
}
- void sendEventQosSessionAvailable(final QosSession session,
+ void sendEventEpsQosSessionAvailable(final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
try {
- if (DBG) log("sendEventQosSessionAvailable: sending...");
+ if (DBG) log("sendEventEpsQosSessionAvailable: sending...");
mCallback.onQosEpsBearerSessionAvailable(session, attributes);
} catch (final RemoteException e) {
- loge("sendEventQosSessionAvailable: remote exception", e);
+ loge("sendEventEpsQosSessionAvailable: remote exception", e);
+ }
+ }
+
+ void sendEventNrQosSessionAvailable(final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ try {
+ if (DBG) log("sendEventNrQosSessionAvailable: sending...");
+ mCallback.onNrQosSessionAvailable(session, attributes);
+ } catch (final RemoteException e) {
+ loge("sendEventNrQosSessionAvailable: remote exception", e);
}
}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 8bda532..b6ab47b 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -27,6 +27,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import com.android.net.module.util.CollectionUtils;
@@ -179,17 +180,31 @@
}
/**
- * Called when the NetworkAgent sends the qos session available event
+ * Called when the NetworkAgent sends the qos session available event for EPS
*
* @param qosCallbackId the callback id that the qos session is now available to
* @param session the qos session that is now available
* @param attributes the qos attributes that are now available on the qos session
*/
- public void sendEventQosSessionAvailable(final int qosCallbackId,
+ public void sendEventEpsQosSessionAvailable(final int qosCallbackId,
final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
- runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ",
- ac -> ac.sendEventQosSessionAvailable(session, attributes));
+ runOnAgentConnection(qosCallbackId, "sendEventEpsQosSessionAvailable: ",
+ ac -> ac.sendEventEpsQosSessionAvailable(session, attributes));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session available event for NR
+ *
+ * @param qosCallbackId the callback id that the qos session is now available to
+ * @param session the qos session that is now available
+ * @param attributes the qos attributes that are now available on the qos session
+ */
+ public void sendEventNrQosSessionAvailable(final int qosCallbackId,
+ final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ runOnAgentConnection(qosCallbackId, "sendEventNrQosSessionAvailable: ",
+ ac -> ac.sendEventNrQosSessionAvailable(session, attributes));
}
/**
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 8122495..e1a424f 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -70,7 +70,7 @@
"mockito-target-minus-junit4",
"net-tests-utils",
"platform-test-annotations",
- "service-connectivity",
+ "service-connectivity-pre-jarjar",
"services.core",
"services.net",
],
@@ -79,6 +79,7 @@
"android.test.runner",
"android.test.base",
"android.test.mock",
+ "ServiceConnectivityResources",
],
jni_libs: [
"libservice-connectivity",
diff --git a/tests/net/common/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java
index 9c0fc7c..50ecb42 100644
--- a/tests/net/common/java/android/net/IpPrefixTest.java
+++ b/tests/net/common/java/android/net/IpPrefixTest.java
@@ -113,6 +113,15 @@
p = new IpPrefix("f00:::/32");
fail("Expected IllegalArgumentException: invalid IPv6 address");
} catch (IllegalArgumentException expected) { }
+
+ p = new IpPrefix("/64");
+ assertEquals("::/64", p.toString());
+
+ p = new IpPrefix("/128");
+ assertEquals("::1/128", p.toString());
+
+ p = new IpPrefix("[2001:db8::123]/64");
+ assertEquals("2001:db8::/64", p.toString());
}
@Test
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index 1eaf30c..2cf3cf9 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -53,6 +53,7 @@
import org.junit.runner.RunWith;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
@@ -117,6 +118,20 @@
assertEquals(456, address.getScope());
assertTrue(address.isIpv4());
+ address = new LinkAddress("/64", 1 /* flags */, 2 /* scope */);
+ assertEquals(Inet6Address.LOOPBACK, address.getAddress());
+ assertEquals(64, address.getPrefixLength());
+ assertEquals(1, address.getFlags());
+ assertEquals(2, address.getScope());
+ assertTrue(address.isIpv6());
+
+ address = new LinkAddress("[2001:db8::123]/64", 3 /* flags */, 4 /* scope */);
+ assertEquals(InetAddresses.parseNumericAddress("2001:db8::123"), address.getAddress());
+ assertEquals(64, address.getPrefixLength());
+ assertEquals(3, address.getFlags());
+ assertEquals(4, address.getScope());
+ assertTrue(address.isIpv6());
+
// InterfaceAddress doesn't have a constructor. Fetch some from an interface.
List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 0dfec75..1f50e31 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -35,6 +35,9 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
+import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -51,7 +54,6 @@
import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -62,13 +64,13 @@
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
-import android.net.wifi.WifiInfo;
import android.net.wifi.aware.DiscoverySession;
import android.net.wifi.aware.PeerHandle;
import android.net.wifi.aware.WifiAwareNetworkSpecifier;
import android.os.Build;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
+import android.util.Range;
import androidx.test.runner.AndroidJUnit4;
@@ -240,73 +242,95 @@
@Test
public void testSetUids() {
final NetworkCapabilities netCap = new NetworkCapabilities();
- final Set<UidRange> uids = new ArraySet<>();
- uids.add(new UidRange(50, 100));
- uids.add(new UidRange(3000, 4000));
- netCap.setUids(uids);
- assertTrue(netCap.appliesToUid(50));
- assertTrue(netCap.appliesToUid(80));
- assertTrue(netCap.appliesToUid(100));
+ // Null uids match all UIDs
+ netCap.setUids(null);
+ assertTrue(netCap.appliesToUid(10));
+ assertTrue(netCap.appliesToUid(200));
assertTrue(netCap.appliesToUid(3000));
- assertTrue(netCap.appliesToUid(3001));
- assertFalse(netCap.appliesToUid(10));
- assertFalse(netCap.appliesToUid(25));
- assertFalse(netCap.appliesToUid(49));
- assertFalse(netCap.appliesToUid(101));
- assertFalse(netCap.appliesToUid(2000));
- assertFalse(netCap.appliesToUid(100000));
-
+ assertTrue(netCap.appliesToUid(10010));
assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
- assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
- assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
- assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
- assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
- assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
-
- NetworkCapabilities netCap2 = new NetworkCapabilities();
- // A new netcap object has null UIDs, so anything will satisfy it.
- assertTrue(netCap2.satisfiedByUids(netCap));
- // Still not equal though.
- assertFalse(netCap2.equalsUids(netCap));
- netCap2.setUids(uids);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.equalsUids(netCap2));
- assertTrue(netCap2.equalsUids(netCap));
-
- uids.add(new UidRange(600, 700));
- netCap2.setUids(uids);
- assertFalse(netCap2.satisfiedByUids(netCap));
- assertFalse(netCap.appliesToUid(650));
- assertTrue(netCap2.appliesToUid(650));
- netCap.combineCapabilities(netCap2);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.appliesToUid(650));
- assertFalse(netCap.appliesToUid(500));
-
- assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
- netCap.combineCapabilities(new NetworkCapabilities());
- assertTrue(netCap.appliesToUid(500));
assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
- assertFalse(netCap2.appliesToUid(500));
- assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
- assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+
+ if (isAtLeastS()) {
+ final Set<Range<Integer>> uids = new ArraySet<>();
+ uids.add(uidRange(50, 100));
+ uids.add(uidRange(3000, 4000));
+ netCap.setUids(uids);
+ assertTrue(netCap.appliesToUid(50));
+ assertTrue(netCap.appliesToUid(80));
+ assertTrue(netCap.appliesToUid(100));
+ assertTrue(netCap.appliesToUid(3000));
+ assertTrue(netCap.appliesToUid(3001));
+ assertFalse(netCap.appliesToUid(10));
+ assertFalse(netCap.appliesToUid(25));
+ assertFalse(netCap.appliesToUid(49));
+ assertFalse(netCap.appliesToUid(101));
+ assertFalse(netCap.appliesToUid(2000));
+ assertFalse(netCap.appliesToUid(100000));
+
+ assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
+ assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
+ assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
+
+ NetworkCapabilities netCap2 = new NetworkCapabilities();
+ // A new netcap object has null UIDs, so anything will satisfy it.
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ // Still not equal though.
+ assertFalse(netCap2.equalsUids(netCap));
+ netCap2.setUids(uids);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.equalsUids(netCap2));
+ assertTrue(netCap2.equalsUids(netCap));
+
+ uids.add(uidRange(600, 700));
+ netCap2.setUids(uids);
+ assertFalse(netCap2.satisfiedByUids(netCap));
+ assertFalse(netCap.appliesToUid(650));
+ assertTrue(netCap2.appliesToUid(650));
+ netCap.combineCapabilities(netCap2);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.appliesToUid(650));
+ assertFalse(netCap.appliesToUid(500));
+
+ assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+ netCap.combineCapabilities(new NetworkCapabilities());
+ assertTrue(netCap.appliesToUid(500));
+ assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
+ assertFalse(netCap2.appliesToUid(500));
+ assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
+ assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+
+ // Null uids satisfies everything.
+ netCap.setUids(null);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.satisfiedByUids(netCap2));
+ netCap2.setUids(null);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.satisfiedByUids(netCap2));
+ }
}
@Test
public void testParcelNetworkCapabilities() {
- final Set<UidRange> uids = new ArraySet<>();
- uids.add(new UidRange(50, 100));
- uids.add(new UidRange(3000, 4000));
+ final Set<Range<Integer>> uids = new ArraySet<>();
+ uids.add(uidRange(50, 100));
+ uids.add(uidRange(3000, 4000));
final NetworkCapabilities netCap = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
- .setUids(uids)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
if (isAtLeastS()) {
netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
- } else if (isAtLeastR()) {
+ netCap.setUids(uids);
+ }
+ if (isAtLeastR()) {
netCap.setOwnerUid(123);
netCap.setAdministratorUids(new int[] {5, 11});
}
@@ -330,55 +354,6 @@
testParcelSane(netCap);
}
- private NetworkCapabilities createNetworkCapabilitiesWithWifiInfo() {
- // uses a real WifiInfo to test parceling of sensitive data.
- final WifiInfo wifiInfo = new WifiInfo.Builder()
- .setSsid("sssid1234".getBytes())
- .setBssid("00:11:22:33:44:55")
- .build();
- return new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .setSSID(TEST_SSID)
- .setTransportInfo(wifiInfo)
- .setRequestorPackageName("com.android.test")
- .setRequestorUid(9304);
- }
-
- @Test
- public void testParcelNetworkCapabilitiesWithLocationSensitiveFields() {
- assumeTrue(isAtLeastS());
-
- final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
- final NetworkCapabilities netCapWithLocationSensitiveFields =
- new NetworkCapabilities(netCap, true);
-
- assertParcelingIsLossless(netCapWithLocationSensitiveFields);
- testParcelSane(netCapWithLocationSensitiveFields);
-
- assertEquals(netCapWithLocationSensitiveFields,
- parcelingRoundTrip(netCapWithLocationSensitiveFields));
- }
-
- @Test
- public void testParcelNetworkCapabilitiesWithoutLocationSensitiveFields() {
- assumeTrue(isAtLeastS());
-
- final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
- final NetworkCapabilities netCapWithoutLocationSensitiveFields =
- new NetworkCapabilities(netCap, false);
-
- final NetworkCapabilities sanitizedNetCap =
- new NetworkCapabilities(netCapWithoutLocationSensitiveFields);
- final WifiInfo sanitizedWifiInfo = new WifiInfo.Builder()
- .setSsid(new byte[0])
- .setBssid(WifiInfo.DEFAULT_MAC_ADDRESS)
- .build();
- sanitizedNetCap.setTransportInfo(sanitizedWifiInfo);
- assertEquals(sanitizedNetCap, parcelingRoundTrip(netCapWithoutLocationSensitiveFields));
- }
-
private void testParcelSane(NetworkCapabilities cap) {
if (isAtLeastS()) {
assertParcelSane(cap, 17);
@@ -389,6 +364,45 @@
}
}
+ private static NetworkCapabilities createNetworkCapabilitiesWithTransportInfo() {
+ return new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_EIMS)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .setSSID(TEST_SSID)
+ .setTransportInfo(new TestTransportInfo())
+ .setRequestorPackageName("com.android.test")
+ .setRequestorUid(9304);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesCopyWithNoRedactions() {
+ assumeTrue(isAtLeastS());
+
+ final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo();
+ final NetworkCapabilities netCapWithNoRedactions =
+ new NetworkCapabilities(netCap, NetworkCapabilities.REDACT_NONE);
+ TestTransportInfo testTransportInfo =
+ (TestTransportInfo) netCapWithNoRedactions.getTransportInfo();
+ assertFalse(testTransportInfo.locationRedacted);
+ assertFalse(testTransportInfo.localMacAddressRedacted);
+ assertFalse(testTransportInfo.settingsRedacted);
+ }
+
+ @Test
+ public void testNetworkCapabilitiesCopyWithoutLocationSensitiveFields() {
+ assumeTrue(isAtLeastS());
+
+ final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo();
+ final NetworkCapabilities netCapWithNoRedactions =
+ new NetworkCapabilities(netCap, REDACT_FOR_ACCESS_FINE_LOCATION);
+ TestTransportInfo testTransportInfo =
+ (TestTransportInfo) netCapWithNoRedactions.getTransportInfo();
+ assertTrue(testTransportInfo.locationRedacted);
+ assertFalse(testTransportInfo.localMacAddressRedacted);
+ assertFalse(testTransportInfo.settingsRedacted);
+ }
+
@Test
public void testOemPaid() {
NetworkCapabilities nc = new NetworkCapabilities();
@@ -518,11 +532,22 @@
assertFalse(nc1.equalsNetCapabilities(nc2));
nc2.addUnwantedCapability(NET_CAPABILITY_INTERNET);
assertTrue(nc1.equalsNetCapabilities(nc2));
+ if (isAtLeastS()) {
+ // Remove a required capability doesn't affect unwanted capabilities.
+ // This is a behaviour change from S.
+ nc1.removeCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
- nc1.removeCapability(NET_CAPABILITY_INTERNET);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.removeCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc1.equalsNetCapabilities(nc2));
+ nc1.removeUnwantedCapability(NET_CAPABILITY_INTERNET);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ nc2.removeUnwantedCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ } else {
+ nc1.removeCapability(NET_CAPABILITY_INTERNET);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ nc2.removeCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ }
}
@Test
@@ -540,12 +565,16 @@
assertFalse(nc1.satisfiedByNetworkCapabilities(nc2));
}
- private ArraySet<UidRange> uidRange(int from, int to) {
- final ArraySet<UidRange> range = new ArraySet<>(1);
- range.add(new UidRange(from, to));
+ private ArraySet<Range<Integer>> uidRanges(int from, int to) {
+ final ArraySet<Range<Integer>> range = new ArraySet<>(1);
+ range.add(uidRange(from, to));
return range;
}
+ private Range<Integer> uidRange(int from, int to) {
+ return new Range<Integer>(from, to);
+ }
+
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testSetAdministratorUids() {
NetworkCapabilities nc =
@@ -579,11 +608,21 @@
// This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
- nc2.combineCapabilities(nc1);
- // We will get this capability in both requested and unwanted lists thus this request
- // will never be satisfied.
- assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+ if (isAtLeastS()) {
+ // From S, it is not allowed to have the same capability in both wanted and
+ // unwanted list.
+ assertThrows(IllegalArgumentException.class, () -> nc2.combineCapabilities(nc1));
+ // Remove unwanted capability to continue other tests.
+ nc1.removeUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
+ } else {
+ nc2.combineCapabilities(nc1);
+ // We will get this capability in both requested and unwanted lists thus this request
+ // will never be satisfied.
+ assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+ // For R or below, remove unwanted capability via removeCapability.
+ nc1.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
nc1.setSSID(TEST_SSID);
nc2.combineCapabilities(nc1);
@@ -601,23 +640,23 @@
} catch (IllegalStateException expected) {}
nc1.setSSID(TEST_SSID);
- nc1.setUids(uidRange(10, 13));
- assertNotEquals(nc1, nc2);
- nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything.
- assertNotEquals(nc1, nc2);
- nc1.combineCapabilities(nc2); // 10~13 + everything is everything.
- assertEquals(nc1, nc2);
- nc1.setUids(uidRange(10, 13));
- nc2.setUids(uidRange(20, 23));
- assertNotEquals(nc1, nc2);
- nc1.combineCapabilities(nc2);
- assertTrue(nc1.appliesToUid(12));
- assertFalse(nc2.appliesToUid(12));
- assertTrue(nc1.appliesToUid(22));
- assertTrue(nc2.appliesToUid(22));
-
- // Verify the subscription id list can be combined only when they are equal.
if (isAtLeastS()) {
+ nc1.setUids(uidRanges(10, 13));
+ assertNotEquals(nc1, nc2);
+ nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything.
+ assertNotEquals(nc1, nc2);
+ nc1.combineCapabilities(nc2); // 10~13 + everything is everything.
+ assertEquals(nc1, nc2);
+ nc1.setUids(uidRanges(10, 13));
+ nc2.setUids(uidRanges(20, 23));
+ assertNotEquals(nc1, nc2);
+ nc1.combineCapabilities(nc2);
+ assertTrue(nc1.appliesToUid(12));
+ assertFalse(nc2.appliesToUid(12));
+ assertTrue(nc1.appliesToUid(22));
+ assertTrue(nc2.appliesToUid(22));
+
+ // Verify the subscription id list can be combined only when they are equal.
nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
nc2.setSubIds(Set.of(TEST_SUBID2));
assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
@@ -773,8 +812,11 @@
if (isAtLeastR()) {
assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
}
-
- nc1.setUids(uidRange(10, 13));
+ if (isAtLeastS()) {
+ nc1.setUids(uidRanges(10, 13));
+ } else {
+ nc1.setUids(null);
+ }
nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
assertEquals(nc1, nc2);
@@ -1033,18 +1075,42 @@
} catch (IllegalArgumentException e) { }
}
- private class TestTransportInfo implements TransportInfo {
+ /**
+ * Test TransportInfo to verify redaction mechanism.
+ */
+ private static class TestTransportInfo implements TransportInfo {
+ public final boolean locationRedacted;
+ public final boolean localMacAddressRedacted;
+ public final boolean settingsRedacted;
+
TestTransportInfo() {
+ locationRedacted = false;
+ localMacAddressRedacted = false;
+ settingsRedacted = false;
+ }
+
+ TestTransportInfo(boolean locationRedacted,
+ boolean localMacAddressRedacted,
+ boolean settingsRedacted) {
+ this.locationRedacted = locationRedacted;
+ this.localMacAddressRedacted =
+ localMacAddressRedacted;
+ this.settingsRedacted = settingsRedacted;
}
@Override
- public TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
- return this;
+ public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
+ return new TestTransportInfo(
+ (redactions & NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
+ (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
+ (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
+ );
}
@Override
- public boolean hasLocationSensitiveFields() {
- return false;
+ public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
+ return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
+ | REDACT_FOR_NETWORK_SETTINGS;
}
}
@@ -1055,7 +1121,7 @@
final int requestUid = 10100;
final int[] administratorUids = {ownerUid, 10001};
final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1);
- final TestTransportInfo transportInfo = new TestTransportInfo();
+ final TransportInfo transportInfo = new TransportInfo() {};
final String ssid = "TEST_SSID";
final String packageName = "com.google.test.networkcapabilities";
final NetworkCapabilities nc = new NetworkCapabilities.Builder()
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 2a2dc56..b6e4274 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -44,12 +44,10 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.ConnectivityService
-import com.android.server.LocalServices
import com.android.server.NetworkAgentWrapper
import com.android.server.TestNetIdManager
import com.android.server.connectivity.MockableSystemProperties
import com.android.server.connectivity.ProxyTracker
-import com.android.server.net.NetworkPolicyManagerInternal
import com.android.testutils.TestableNetworkCallback
import org.junit.After
import org.junit.Before
@@ -75,7 +73,7 @@
import kotlin.test.fail
const val SERVICE_BIND_TIMEOUT_MS = 5_000L
-const val TEST_TIMEOUT_MS = 1_000L
+const val TEST_TIMEOUT_MS = 10_000L
/**
* Test that exercises an instrumented version of ConnectivityService against an instrumented
@@ -162,10 +160,6 @@
networkStackClient.init()
networkStackClient.start()
- LocalServices.removeServiceForTest(NetworkPolicyManagerInternal::class.java)
- LocalServices.addService(NetworkPolicyManagerInternal::class.java,
- mock(NetworkPolicyManagerInternal::class.java))
-
service = TestConnectivityService(makeDependencies())
cm = ConnectivityManager(context, service)
context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 01d8186..e2d43cb 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -44,11 +44,11 @@
import android.net.NetworkSpecifier;
import android.net.QosFilter;
import android.net.SocketKeepalive;
-import android.net.UidRange;
import android.os.ConditionVariable;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
+import android.util.Range;
import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.connectivity.ConnectivityConstants;
@@ -222,7 +222,7 @@
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
- public void setUids(Set<UidRange> uids) {
+ public void setUids(Set<Range<Integer>> uids) {
mNetworkCapabilities.setUids(uids);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 6fc605e..6cbdd25 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -41,10 +41,10 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -64,6 +64,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.os.Process;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -219,8 +220,8 @@
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- anyInt(), any(), nullable(String.class))).thenReturn(request);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request);
manager.requestNetwork(request, callback, handler);
// callback triggers
@@ -247,8 +248,8 @@
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- anyInt(), any(), nullable(String.class))).thenReturn(req1);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1);
manager.requestNetwork(req1, callback, handler);
// callback triggers
@@ -265,8 +266,8 @@
verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
// callback can be registered again
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- anyInt(), any(), nullable(String.class))).thenReturn(req2);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2);
manager.requestNetwork(req2, callback, handler);
// callback triggers
@@ -289,8 +290,8 @@
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(),
- any(), nullable(String.class))).thenReturn(request);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(),
+ anyInt(), any(), nullable(String.class))).thenReturn(request);
Handler handler = new Handler(Looper.getMainLooper());
manager.requestNetwork(request, callback, handler);
@@ -357,34 +358,40 @@
final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
manager.requestNetwork(request, callback);
- verify(mService).requestNetwork(eq(request.networkCapabilities),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
// Verify that register network callback does not calls requestNetwork at all.
manager.registerNetworkCallback(request, callback);
- verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(),
- anyInt(), any(), any());
+ verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(),
+ anyInt(), anyInt(), any(), any());
verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
+ Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+
manager.registerDefaultNetworkCallback(callback);
- verify(mService).requestNetwork(eq(null),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
- Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ manager.registerDefaultNetworkCallbackAsUid(42, callback, handler);
+ verify(mService).requestNetwork(eq(42), eq(null),
+ eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
+ eq(testPkgName), eq(testAttributionTag));
+
manager.requestBackgroundNetwork(request, handler, callback);
- verify(mService).requestNetwork(eq(request.networkCapabilities),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerSystemDefaultNetworkCallback(callback, handler);
- verify(mService).requestNetwork(eq(null),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index d04c87b..b7a42ec 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -42,7 +42,13 @@
VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+ VpnTransportInfo v4 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY);
+ VpnTransportInfo v5 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM);
+
assertNotEquals(v1, v2);
+ assertNotEquals(v3, v4);
+ assertNotEquals(v4, v5);
+
assertEquals(v1, v3);
assertEquals(v1.hashCode(), v3.hashCode());
}
diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
index 8ea226d..b62bdbc 100644
--- a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
+++ b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.content.res.Resources
+import android.net.ConnectivityResources
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.MAX_TRANSPORT
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
@@ -26,13 +27,15 @@
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import androidx.test.filters.SmallTest
import com.android.internal.R
+import org.junit.After
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.any
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
@@ -47,21 +50,33 @@
class KeepaliveUtilsTest {
// Prepare mocked context with given resource strings.
- private fun getMockedContextWithStringArrayRes(id: Int, res: Array<out String?>?): Context {
+ private fun getMockedContextWithStringArrayRes(
+ id: Int,
+ name: String,
+ res: Array<out String?>?
+ ): Context {
val mockRes = mock(Resources::class.java)
- doReturn(res).`when`(mockRes).getStringArray(ArgumentMatchers.eq(id))
+ doReturn(res).`when`(mockRes).getStringArray(eq(id))
+ doReturn(id).`when`(mockRes).getIdentifier(eq(name), any(), any())
return mock(Context::class.java).apply {
doReturn(mockRes).`when`(this).getResources()
+ ConnectivityResources.setResourcesContextForTest(this)
}
}
+ @After
+ fun tearDown() {
+ ConnectivityResources.setResourcesContextForTest(null)
+ }
+
@Test
fun testGetSupportedKeepalives() {
fun assertRunWithException(res: Array<out String?>?) {
try {
val mockContext = getMockedContextWithStringArrayRes(
- R.array.config_networkSupportedKeepaliveCount, res)
+ R.array.config_networkSupportedKeepaliveCount,
+ "config_networkSupportedKeepaliveCount", res)
KeepaliveUtils.getSupportedKeepalives(mockContext)
fail("Expected KeepaliveDeviceConfigurationException")
} catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
@@ -89,7 +104,8 @@
val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0)
val mockContext = getMockedContextWithStringArrayRes(
- R.array.config_networkSupportedKeepaliveCount, validRes)
+ R.array.config_networkSupportedKeepaliveCount,
+ "config_networkSupportedKeepaliveCount", validRes)
val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
assertArrayEquals(expectedValidRes, actual)
}
diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
index c1315f6..25aa626 100644
--- a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
+++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt
@@ -21,18 +21,20 @@
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
+import android.net.ConnectivityResources
+import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
+import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE
import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener
import android.provider.Settings
-import android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI
-import android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.test.mock.MockContentResolver
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
-import com.android.internal.R
+import com.android.connectivity.resources.R
import com.android.internal.util.test.FakeSettingsProvider
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -41,6 +43,7 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.argThat
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.any
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
@@ -57,6 +60,8 @@
@SmallTest
class MultinetworkPolicyTrackerTest {
private val resources = mock(Resources::class.java).also {
+ doReturn(R.integer.config_networkAvoidBadWifi).`when`(it).getIdentifier(
+ eq("config_networkAvoidBadWifi"), eq("integer"), any())
doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
}
private val telephonyManager = mock(TelephonyManager::class.java)
@@ -75,6 +80,7 @@
doReturn(resources).`when`(it).resources
doReturn(it).`when`(it).createConfigurationContext(any())
Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
+ ConnectivityResources.setResourcesContextForTest(it)
}
private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
@@ -85,6 +91,11 @@
assertEquals(preference, tracker.meteredMultipathPreference)
}
+ @After
+ fun tearDown() {
+ ConnectivityResources.setResourcesContextForTest(null)
+ }
+
@Test
fun testUpdateMeteredMultipathPreference() {
assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2c8c8a6..10b2f1e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,23 +23,31 @@
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.FEATURE_WIFI;
+import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
-import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
+import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
@@ -77,15 +85,15 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
+import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
+import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
+import static android.net.NetworkCapabilities.REDACT_NONE;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
@@ -174,6 +182,8 @@
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.ConnectivityManager.TooManyRequestsException;
+import android.net.ConnectivityResources;
+import android.net.ConnectivitySettingsManager;
import android.net.ConnectivityThread;
import android.net.DataStallReportParcelable;
import android.net.EthernetManager;
@@ -182,8 +192,7 @@
import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkPolicyListener;
-import android.net.IOnSetOemNetworkPreferenceListener;
+import android.net.IOnCompleteListener;
import android.net.IQosCallback;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
@@ -201,7 +210,9 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicyManager;
+import android.net.NetworkPolicyManager.NetworkPolicyCallback;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStackClient;
@@ -229,7 +240,6 @@
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
-import android.net.wifi.WifiInfo;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Build;
@@ -255,17 +265,20 @@
import android.system.Os;
import android.telephony.TelephonyManager;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
+import android.util.Range;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.connectivity.resources.R;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.ArrayUtils;
@@ -284,7 +297,6 @@
import com.android.server.connectivity.Vpn;
import com.android.server.connectivity.VpnProfileStore;
import com.android.server.net.NetworkPinner;
-import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.testutils.ExceptionUtils;
import com.android.testutils.HandlerUtils;
import com.android.testutils.RecorderCallback.CallbackEntry;
@@ -376,6 +388,11 @@
// Set a non-zero value to verify the flow to set tcp init rwnd value.
private static final int TEST_TCP_INIT_RWND = 60;
+ // Used for testing the per-work-profile default network.
+ private static final int TEST_APP_ID = 103;
+ private static final int TEST_WORK_PROFILE_USER_ID = 2;
+ private static final int TEST_WORK_PROFILE_APP_UID =
+ UserHandle.getUid(TEST_WORK_PROFILE_USER_ID, TEST_APP_ID);
private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
@@ -410,7 +427,7 @@
private TestNetworkAgentWrapper mEthernetNetworkAgent;
private MockVpn mMockVpn;
private Context mContext;
- private INetworkPolicyListener mPolicyListener;
+ private NetworkPolicyCallback mPolicyCallback;
private WrappedMultinetworkPolicyTracker mPolicyTracker;
private HandlerThread mAlarmManagerThread;
private TestNetIdManager mNetIdManager;
@@ -419,10 +436,10 @@
private VpnManagerService mVpnManagerService;
private TestNetworkCallback mDefaultNetworkCallback;
private TestNetworkCallback mSystemDefaultNetworkCallback;
+ private TestNetworkCallback mProfileDefaultNetworkCallback;
// State variables required to emulate NetworkPolicyManagerService behaviour.
- private int mUidRules = RULE_NONE;
- private boolean mRestrictBackground = false;
+ private int mBlockedReasons = BLOCKED_REASON_NONE;
@Mock DeviceIdleInternal mDeviceIdleInternal;
@Mock INetworkManagementService mNetworkManagementService;
@@ -444,6 +461,7 @@
@Mock NetworkPolicyManager mNetworkPolicyManager;
@Mock VpnProfileStore mVpnProfileStore;
@Mock SystemConfigManager mSystemConfigManager;
+ @Mock Resources mResources;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -471,7 +489,7 @@
private class MockContext extends BroadcastInterceptingContext {
private final MockContentResolver mContentResolver;
- @Spy private Resources mResources;
+ @Spy private Resources mInternalResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
// Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
@@ -480,21 +498,15 @@
MockContext(Context base, ContentProvider settingsProvider) {
super(base);
- mResources = spy(base.getResources());
- when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)).
- thenReturn(new String[] {
+ mInternalResources = spy(base.getResources());
+ when(mInternalResources.getStringArray(com.android.internal.R.array.networkAttributes))
+ .thenReturn(new String[] {
"wifi,1,1,1,-1,true",
"mobile,0,0,0,-1,true",
"mobile_mms,2,0,2,60000,true",
"mobile_supl,3,0,2,60000,true",
});
- when(mResources.getStringArray(
- com.android.internal.R.array.config_wakeonlan_supported_interfaces))
- .thenReturn(new String[]{
- WIFI_WOL_IFNAME,
- });
-
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@@ -545,13 +557,26 @@
return super.getSystemService(name);
}
+ final HashMap<UserHandle, UserManager> mUserManagers = new HashMap<>();
@Override
public Context createContextAsUser(UserHandle user, int flags) {
final Context asUser = mock(Context.class, AdditionalAnswers.delegatesTo(this));
doReturn(user).when(asUser).getUser();
+ doAnswer((inv) -> {
+ final UserManager um = mUserManagers.computeIfAbsent(user,
+ u -> mock(UserManager.class, AdditionalAnswers.delegatesTo(mUserManager)));
+ return um;
+ }).when(asUser).getSystemService(Context.USER_SERVICE);
return asUser;
}
+ public void setWorkProfile(@NonNull final UserHandle userHandle, boolean value) {
+ // This relies on all contexts for a given user returning the same UM mock
+ final UserManager umMock = createContextAsUser(userHandle, 0 /* flags */)
+ .getSystemService(UserManager.class);
+ doReturn(value).when(umMock).isManagedProfile();
+ }
+
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
@@ -559,7 +584,7 @@
@Override
public Resources getResources() {
- return mResources;
+ return mInternalResources;
}
@Override
@@ -1082,6 +1107,10 @@
public void triggerUnfulfillable(NetworkRequest r) {
super.releaseRequestAsUnfulfillableByAnyFactory(r);
}
+
+ public void assertNoRequestChanged() {
+ assertNull(mRequestHistory.poll(0, r -> true));
+ }
}
private Set<UidRange> uidRangesForUids(int... uids) {
@@ -1133,7 +1162,7 @@
}
public void setUids(Set<UidRange> uids) {
- mNetworkCapabilities.setUids(uids);
+ mNetworkCapabilities.setUids(UidRange.toIntRanges(uids));
if (mAgentRegistered) {
mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
}
@@ -1149,11 +1178,6 @@
}
@Override
- public int getNetId() {
- return (mMockNetworkAgent == null) ? NETID_UNSET : mMockNetworkAgent.getNetwork().netId;
- }
-
- @Override
public int getActiveVpnType() {
return mVpnType;
}
@@ -1177,10 +1201,10 @@
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
- verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+ verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(uids)));
verify(mMockNetd, never())
- .networkRemoveUidRanges(eq(mMockVpn.getNetId()), any());
+ .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any());
mAgentRegistered = true;
updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
@@ -1349,28 +1373,13 @@
}
private void mockUidNetworkingBlocked() {
- doAnswer(i -> mContext.getSystemService(NetworkPolicyManager.class)
- .checkUidNetworkingBlocked(i.getArgument(0) /* uid */, mUidRules,
- i.getArgument(1) /* metered */, mRestrictBackground)
+ doAnswer(i -> NetworkPolicyManager.isUidBlocked(mBlockedReasons, i.getArgument(1))
).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
-
- doAnswer(inv -> mContext.getSystemService(NetworkPolicyManager.class)
- .checkUidNetworkingBlocked(inv.getArgument(0) /* uid */,
- inv.getArgument(1) /* uidRules */,
- inv.getArgument(2) /* isNetworkMetered */,
- inv.getArgument(3) /* isBackgroundRestricted */)
- ).when(mNetworkPolicyManager).checkUidNetworkingBlocked(
- anyInt(), anyInt(), anyBoolean(), anyBoolean());
}
- private void setUidRulesChanged(int uidRules) throws RemoteException {
- mUidRules = uidRules;
- mPolicyListener.onUidRulesChanged(Process.myUid(), mUidRules);
- }
-
- private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException {
- mRestrictBackground = restrictBackground;
- mPolicyListener.onRestrictBackgroundChanged(mRestrictBackground);
+ private void setBlockedReasonChanged(int blockedReasons) {
+ mBlockedReasons = blockedReasons;
+ mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
}
private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
@@ -1407,18 +1416,56 @@
fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
}
- private void registerNetworkCallbackAsUid(NetworkRequest request, NetworkCallback callback,
- int uid) {
+ private <T> T doAsUid(final int uid, @NonNull final Supplier<T> what) {
when(mDeps.getCallingUid()).thenReturn(uid);
try {
- mCm.registerNetworkCallback(request, callback);
- waitForIdle();
+ return what.get();
} finally {
returnRealCallingUid();
}
}
+ private void doAsUid(final int uid, @NonNull final Runnable what) {
+ doAsUid(uid, () -> {
+ what.run(); return Void.TYPE;
+ });
+ }
+
+ private void registerNetworkCallbackAsUid(NetworkRequest request, NetworkCallback callback,
+ int uid) {
+ doAsUid(uid, () -> {
+ mCm.registerNetworkCallback(request, callback);
+ });
+ }
+
+ private void registerDefaultNetworkCallbackAsUid(@NonNull final NetworkCallback callback,
+ final int uid) {
+ doAsUid(uid, () -> {
+ mCm.registerDefaultNetworkCallback(callback);
+ waitForIdle();
+ });
+ }
+
+ private interface ExceptionalRunnable {
+ void run() throws Exception;
+ }
+
+ private void withPermission(String permission, ExceptionalRunnable r) throws Exception {
+ if (mServiceContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ r.run();
+ return;
+ }
+ try {
+ mServiceContext.setPermission(permission, PERMISSION_GRANTED);
+ r.run();
+ } finally {
+ mServiceContext.setPermission(permission, PERMISSION_DENIED);
+ }
+ }
+
private static final int PRIMARY_USER = 0;
+ private static final UidRange PRIMARY_UIDRANGE =
+ UidRange.createForUser(UserHandle.of(PRIMARY_USER));
private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
@@ -1464,14 +1511,14 @@
Looper.prepare();
}
mockDefaultPackages();
+ mockHasSystemFeature(FEATURE_WIFI, true);
+ mockHasSystemFeature(FEATURE_WIFI_DIRECT, true);
+ doReturn(true).when(mTelephonyManager).isDataCapable();
FakeSettingsProvider.clearSettingsProvider();
mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
new FakeSettingsProvider());
mServiceContext.setUseRegisteredHandlers(true);
- LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
- LocalServices.addService(
- NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
mAlarmManagerThread = new HandlerThread("TestAlarmManager");
mAlarmManagerThread.start();
@@ -1490,10 +1537,11 @@
mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any());
- final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
- ArgumentCaptor.forClass(INetworkPolicyListener.class);
- verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture());
- mPolicyListener = policyListenerCaptor.getValue();
+ final ArgumentCaptor<NetworkPolicyCallback> policyCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkPolicyCallback.class);
+ verify(mNetworkPolicyManager).registerNetworkPolicyCallback(any(),
+ policyCallbackCaptor.capture());
+ mPolicyCallback = policyCallbackCaptor.getValue();
// Create local CM before sending system ready so that we can answer
// getSystemService() correctly.
@@ -1506,7 +1554,7 @@
mQosCallbackTracker = mock(QosCallbackTracker.class);
// Ensure that the default setting for Captive Portals is used for most tests
- setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+ setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
setAlwaysOnNetworks(false);
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
}
@@ -1516,17 +1564,14 @@
}
private ConnectivityService.Dependencies makeDependencies() {
- doReturn(TEST_TCP_INIT_RWND).when(mSystemProperties)
- .getInt("net.tcp.default_init_rwnd", 0);
doReturn(false).when(mSystemProperties).getBoolean("ro.radio.noril", false);
- doNothing().when(mSystemProperties).setTcpInitRwnd(anyInt());
final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
doReturn(mNetIdManager).when(deps).makeNetIdManager();
doReturn(mNetworkStack).when(deps).getNetworkStack();
doReturn(mSystemProperties).when(deps).getSystemProperties();
doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
- doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
+ doReturn(true).when(deps).queryUserAccess(anyInt(), any(), any());
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -1534,6 +1579,33 @@
}).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
doReturn(true).when(deps).getCellular464XlatEnabled();
+ doReturn(60000).when(mResources).getInteger(
+ com.android.connectivity.resources.R.integer.config_networkTransitionTimeout);
+ doReturn("").when(mResources).getString(
+ com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl);
+ doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray(
+ com.android.connectivity.resources.R.array.config_wakeonlan_supported_interfaces);
+ doReturn(new String[] { "0,1", "1,3" }).when(mResources).getStringArray(
+ com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount);
+ doReturn(com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount)
+ .when(mResources).getIdentifier(eq("config_networkSupportedKeepaliveCount"),
+ eq("array"), any());
+ doReturn(com.android.connectivity.resources.R.array.network_switch_type_name)
+ .when(mResources).getIdentifier(eq("network_switch_type_name"),
+ eq("array"), any());
+
+ // We don't test the actual notification value strings, so just return an empty array.
+ // It doesn't matter what the values are as long as it's not null.
+ doReturn(new String[0]).when(mResources).getStringArray(R.array.network_switch_type_name);
+
+ final ConnectivityResources connRes = mock(ConnectivityResources.class);
+ doReturn(mResources).when(connRes).get();
+ doReturn(connRes).when(deps).getResources(any());
+
+ final Context mockResContext = mock(Context.class);
+ doReturn(mResources).when(mockResContext).getResources();
+ ConnectivityResources.setResourcesContextForTest(mockResContext);
+
return deps;
}
@@ -1566,6 +1638,7 @@
@After
public void tearDown() throws Exception {
unregisterDefaultNetworkCallbacks();
+ maybeTearDownEnterpriseNetwork();
setAlwaysOnNetworks(false);
if (mCellNetworkAgent != null) {
mCellNetworkAgent.disconnect();
@@ -1588,6 +1661,7 @@
waitForIdle();
FakeSettingsProvider.clearSettingsProvider();
+ ConnectivityResources.setResourcesContextForTest(null);
mCsHandlerThread.quitSafely();
mAlarmManagerThread.quitSafely();
@@ -1776,7 +1850,8 @@
assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
- assertFalse(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
+ assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
+ assertFalse(mCm.isNetworkSupported(TYPE_PROXY));
// Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
// mocks, this assert exercises the ConnectivityService code path that ensures that
@@ -3349,7 +3424,7 @@
.addCapability(NET_CAPABILITY_VALIDATED).build();
mCm.registerNetworkCallback(validatedRequest, validatedCallback);
- setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
+ setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID);
// Bring up a network with a captive portal.
// Expect it to fail to connect and not result in any callbacks.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -3750,8 +3825,9 @@
NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
- null, 0, null, ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
+ mService.requestNetwork(Process.INVALID_UID, networkCapabilities,
+ NetworkRequest.Type.REQUEST.ordinal(), null, 0, null,
+ ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
mContext.getPackageName(), getAttributionTag());
});
@@ -3980,7 +4056,7 @@
}
@Test
- public void testRegisterSystemDefaultCallbackRequiresNetworkSettings() throws Exception {
+ public void testRegisterPrivilegedDefaultCallbacksRequireNetworkSettings() throws Exception {
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false /* validated */);
@@ -3989,30 +4065,38 @@
assertThrows(SecurityException.class,
() -> mCm.registerSystemDefaultNetworkCallback(callback, handler));
callback.assertNoCallback();
+ assertThrows(SecurityException.class,
+ () -> mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler));
+ callback.assertNoCallback();
mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
PERMISSION_GRANTED);
mCm.registerSystemDefaultNetworkCallback(callback, handler);
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
mCm.unregisterNetworkCallback(callback);
+
+ mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler);
+ callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ mCm.unregisterNetworkCallback(callback);
}
private void setCaptivePortalMode(int mode) {
ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, mode);
}
private void setAlwaysOnNetworks(boolean enable) {
ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON,
+ enable ? 1 : 0);
mService.updateAlwaysOnNetworks();
waitForIdle();
}
private void setPrivateDnsSettings(String mode, String specifier) {
final ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_MODE, mode);
- Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_SPECIFIER, specifier);
+ Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_MODE, mode);
+ Settings.Global.putString(cr, ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER, specifier);
mService.updatePrivateDnsSettings();
waitForIdle();
}
@@ -4250,7 +4334,7 @@
@Test
public void testAvoidBadWifiSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
+ final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
String[] values = new String[] {null, "0", "1"};
@@ -4284,6 +4368,7 @@
assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
}
+ @Ignore("Refactoring in progress b/178071397")
@Test
public void testAvoidBadWifi() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
@@ -4307,7 +4392,7 @@
TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 0);
mPolicyTracker.reevaluate();
// Bring up validated cell.
@@ -4375,7 +4460,7 @@
validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
mPolicyTracker.reevaluate();
// We now switch to cell.
@@ -4388,11 +4473,11 @@
// Simulate the user turning the cellular fallback setting off and then on.
// We switch to wifi and then to cell.
- Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
+ Settings.Global.putString(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null);
mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
- Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
+ Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
mPolicyTracker.reevaluate();
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
@@ -4411,7 +4496,7 @@
@Test
public void testMeteredMultipathPreferenceSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
+ final String settingName = ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
for (int config : Arrays.asList(0, 3, 2)) {
for (String setting: Arrays.asList(null, "0", "2", "1")) {
@@ -6887,7 +6972,7 @@
final int uid = Process.myUid();
NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertNotNull("nc=" + nc, nc.getUids());
- assertEquals(nc.getUids(), uidRangesForUids(uid));
+ assertEquals(nc.getUids(), UidRange.toIntRanges(uidRangesForUids(uid)));
assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
// Set an underlying network and expect to see the VPN transports change.
@@ -6912,10 +6997,13 @@
// Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
// restricted user.
+ final UidRange rRange = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
+ final Range<Integer> restrictUidRange = new Range<Integer>(rRange.start, rRange.stop);
+ final Range<Integer> singleUidRange = new Range<Integer>(uid, uid);
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2
- && caps.getUids().contains(new UidRange(uid, uid))
- && caps.getUids().contains(createUidRange(RESTRICTED_USER))
+ && caps.getUids().contains(singleUidRange)
+ && caps.getUids().contains(restrictUidRange)
&& caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_WIFI));
@@ -6924,8 +7012,8 @@
callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2
- && caps.getUids().contains(new UidRange(uid, uid))
- && caps.getUids().contains(createUidRange(RESTRICTED_USER))
+ && caps.getUids().contains(singleUidRange)
+ && caps.getUids().contains(restrictUidRange)
&& caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI));
@@ -6939,7 +7027,7 @@
// change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 1
- && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.getUids().contains(singleUidRange)
&& caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI));
}
@@ -7189,6 +7277,20 @@
mMockVpn.disconnect();
}
+ private class DetailedBlockedStatusCallback extends TestNetworkCallback {
+ public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) {
+ super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS);
+ }
+ public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) {
+ // This doesn't work:
+ // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork());
+ super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS);
+ }
+ public void onBlockedStatusChanged(Network network, int blockedReasons) {
+ getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
+ }
+ }
+
@Test
public void testNetworkBlockedStatus() throws Exception {
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -7196,36 +7298,49 @@
.addTransportType(TRANSPORT_CELLULAR)
.build();
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+ final DetailedBlockedStatusCallback detailedCallback = new DetailedBlockedStatusCallback();
+ mCm.registerNetworkCallback(cellRequest, detailedCallback);
+
mockUidNetworkingBlocked();
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ detailedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent,
+ BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertExtraInfoFromCmPresent(mCellNetworkAgent);
- setUidRulesChanged(RULE_REJECT_ALL);
+ setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_REASON_BATTERY_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertExtraInfoFromCmBlocked(mCellNetworkAgent);
- // ConnectivityService should cache it not to invoke the callback again.
- setUidRulesChanged(RULE_REJECT_METERED);
- cellNetworkCallback.assertNoCallback();
+ // If blocked state does not change but blocked reason does, the boolean callback is called.
+ // TODO: investigate de-duplicating.
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED);
+ cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_USER_RESTRICTED);
- setUidRulesChanged(RULE_NONE);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertExtraInfoFromCmPresent(mCellNetworkAgent);
- setUidRulesChanged(RULE_REJECT_METERED);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7235,6 +7350,8 @@
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7244,39 +7361,49 @@
cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
mCellNetworkAgent);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
+ mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertExtraInfoFromCmBlocked(mCellNetworkAgent);
- setUidRulesChanged(RULE_ALLOW_METERED);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertExtraInfoFromCmPresent(mCellNetworkAgent);
- setUidRulesChanged(RULE_NONE);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.assertNoCallback();
+ detailedCallback.assertNoCallback();
// Restrict background data. Networking is not blocked because the network is unmetered.
- setRestrictBackgroundChanged(true);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertExtraInfoFromCmBlocked(mCellNetworkAgent);
- setRestrictBackgroundChanged(true);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
cellNetworkCallback.assertNoCallback();
- setUidRulesChanged(RULE_ALLOW_METERED);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertExtraInfoFromCmPresent(mCellNetworkAgent);
- setRestrictBackgroundChanged(false);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.assertNoCallback();
+ detailedCallback.assertNoCallback();
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7292,9 +7419,9 @@
mockUidNetworkingBlocked();
// No Networkcallbacks invoked before any network is active.
- setUidRulesChanged(RULE_REJECT_ALL);
- setUidRulesChanged(RULE_NONE);
- setUidRulesChanged(RULE_REJECT_METERED);
+ setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
defaultCallback.assertNoCallback();
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -7319,8 +7446,8 @@
defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
// Verify there's no Networkcallbacks invoked after data saver on/off.
- setRestrictBackgroundChanged(true);
- setRestrictBackgroundChanged(false);
+ setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
+ setBlockedReasonChanged(BLOCKED_REASON_NONE);
defaultCallback.assertNoCallback();
mCellNetworkAgent.disconnect();
@@ -7419,6 +7546,13 @@
final NetworkRequest vpnUidRequest = new NetworkRequest.Builder().build();
registerNetworkCallbackAsUid(vpnUidRequest, vpnUidCallback, VPN_UID);
+ final TestNetworkCallback vpnUidDefaultCallback = new TestNetworkCallback();
+ registerDefaultNetworkCallbackAsUid(vpnUidDefaultCallback, VPN_UID);
+
+ final TestNetworkCallback vpnDefaultCallbackAsUid = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallbackAsUid(VPN_UID, vpnDefaultCallbackAsUid,
+ new Handler(ConnectivityThread.getInstanceLooper()));
+
final int uid = Process.myUid();
final int userId = UserHandle.getUserId(uid);
final ArrayList<String> allowList = new ArrayList<>();
@@ -7437,6 +7571,8 @@
callback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ vpnUidDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ vpnDefaultCallbackAsUid.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7449,6 +7585,8 @@
callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -7463,6 +7601,8 @@
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
// The following requires that the UID of this test package is greater than VPN_UID. This
// is always true in practice because a plain AOSP build with no apps installed has almost
@@ -7483,6 +7623,8 @@
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
defaultCallback.assertNoCallback();
vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7503,6 +7645,8 @@
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7514,6 +7658,8 @@
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7528,6 +7674,8 @@
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7539,6 +7687,8 @@
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7551,6 +7701,8 @@
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7561,6 +7713,8 @@
assertUidRangesUpdatedForMyUid(true);
defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
vpnUidCallback.assertNoCallback(); // vpnUidCallback has NOT_VPN capability.
+ vpnUidDefaultCallback.assertNoCallback(); // VPN does not apply to VPN_UID
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7571,11 +7725,16 @@
mMockVpn.disconnect();
defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+ vpnUidCallback.assertNoCallback();
+ vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertNull(mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(defaultCallback);
mCm.unregisterNetworkCallback(vpnUidCallback);
+ mCm.unregisterNetworkCallback(vpnUidDefaultCallback);
+ mCm.unregisterNetworkCallback(vpnDefaultCallbackAsUid);
}
private void setupLegacyLockdownVpn() {
@@ -7597,7 +7756,7 @@
assertNotNull(underlying);
mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
// The legacy lockdown VPN only supports userId 0.
- final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> ranges = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.registerAgent(ranges);
mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
mMockVpn.connect(true);
@@ -7985,7 +8144,6 @@
// Switching default network updates TCP buffer sizes.
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
- verify(mSystemProperties, times(1)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Add an IPv4 address. Expect prefix discovery to be stopped. Netd doesn't tell us that
// the NAT64 prefix was removed because one was never discovered.
cellLp.addLinkAddress(myIpv4);
@@ -8471,14 +8629,12 @@
mCellNetworkAgent.connect(false);
networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
- verify(mSystemProperties, times(1)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Change link Properties should have updated tcp buffer size.
LinkProperties lp = new LinkProperties();
lp.setTcpBufferSizes(testTcpBufferSizes);
mCellNetworkAgent.sendLinkProperties(lp);
networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verifyTcpBufferSizeChange(testTcpBufferSizes);
- verify(mSystemProperties, times(2)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Clean up.
mCellNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -8562,7 +8718,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -8590,7 +8746,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -8606,7 +8762,7 @@
lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -8621,7 +8777,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -8673,7 +8829,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
- final UidRange vpnRange = createUidRange(PRIMARY_USER);
+ final UidRange vpnRange = PRIMARY_UIDRANGE;
final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -8778,29 +8934,34 @@
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, includeLocationSensitiveInfo, callerUid,
+ netCap, includeLocationSensitiveInfo, Process.myUid(), callerUid,
mContext.getPackageName(), getAttributionTag())
.getOwnerUid();
}
- private void verifyWifiInfoCopyNetCapsPermission(
+ private void verifyTransportInfoCopyNetCapsPermission(
int callerUid, boolean includeLocationSensitiveInfo,
boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
- final WifiInfo wifiInfo = mock(WifiInfo.class);
- when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
- final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions()).thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, includeLocationSensitiveInfo, callerUid,
+ netCap, includeLocationSensitiveInfo, Process.myPid(), callerUid,
mContext.getPackageName(), getAttributionTag());
- verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
+ if (shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
+ verify(transportInfo).makeCopy(REDACT_NONE);
+ } else {
+ verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
+ }
}
- private void verifyOwnerUidAndWifiInfoNetCapsPermission(
+ private void verifyOwnerUidAndTransportInfoNetCapsPermission(
boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
- boolean shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag,
- boolean shouldInclLocationSensitiveWifiInfoWithIncludeFlag) {
+ boolean shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag,
+ boolean shouldInclLocationSensitiveTransportInfoWithIncludeFlag) {
final int myUid = Process.myUid();
final int expectedOwnerUidWithoutIncludeFlag =
@@ -8814,13 +8975,13 @@
assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
myUid, myUid, true /* includeLocationSensitiveInfo */));
- verifyWifiInfoCopyNetCapsPermission(myUid,
+ verifyTransportInfoCopyNetCapsPermission(myUid,
false, /* includeLocationSensitiveInfo */
- shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag);
+ shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag);
- verifyWifiInfoCopyNetCapsPermission(myUid,
+ verifyTransportInfoCopyNetCapsPermission(myUid,
true, /* includeLocationSensitiveInfo */
- shouldInclLocationSensitiveWifiInfoWithIncludeFlag);
+ shouldInclLocationSensitiveTransportInfoWithIncludeFlag);
}
@@ -8830,15 +8991,15 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndWifiInfoNetCapsPermission(
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we include owner uid even if the request asks to remove it since the
// app has necessary permissions and targetSdk < S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
- true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8848,15 +9009,15 @@
setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndWifiInfoNetCapsPermission(
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we include owner uid even if the request asks to remove it since the
// app has necessary permissions and targetSdk < S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
- true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8867,15 +9028,15 @@
setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndWifiInfoNetCapsPermission(
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we owner UID if the request asks us to remove it even if the app
// has necessary permissions since targetSdk >= S.
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
- true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8885,15 +9046,15 @@
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- verifyOwnerUidAndWifiInfoNetCapsPermission(
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we owner UID if the request asks us to remove it even if the app
// has necessary permissions since targetSdk >= S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
- true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8903,11 +9064,11 @@
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndWifiInfoNetCapsPermission(
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8930,11 +9091,11 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- verifyOwnerUidAndWifiInfoNetCapsPermission(
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8944,17 +9105,196 @@
// Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
- verifyOwnerUidAndWifiInfoNetCapsPermission(
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
+ @Test
+ public void testCreateForCallerWithLocalMacAddressSanitizedWithLocalMacAddressPermission()
+ throws Exception {
+ mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_GRANTED);
+
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions())
+ .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
+ Process.myPid(), Process.myUid(),
+ mContext.getPackageName(), getAttributionTag());
+ // don't redact MAC_ADDRESS fields, only location sensitive fields.
+ verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
+ }
+
+ @Test
+ public void testCreateForCallerWithLocalMacAddressSanitizedWithoutLocalMacAddressPermission()
+ throws Exception {
+ mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
+
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions())
+ .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
+ Process.myPid(), Process.myUid(),
+ mContext.getPackageName(), getAttributionTag());
+ // redact both MAC_ADDRESS & location sensitive fields.
+ verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION
+ | REDACT_FOR_LOCAL_MAC_ADDRESS);
+ }
+
+ @Test
+ public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
+ throws Exception {
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions())
+ .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
+ Process.myPid(), Process.myUid(),
+ mContext.getPackageName(), getAttributionTag());
+ // don't redact NETWORK_SETTINGS fields, only location sensitive fields.
+ verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
+ }
+
+ @Test
+ public void testCreateForCallerWithLocalMacAddressSanitizedWithoutSettingsPermission()
+ throws Exception {
+ mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
+
+ final TransportInfo transportInfo = mock(TransportInfo.class);
+ when(transportInfo.getApplicableRedactions())
+ .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities().setTransportInfo(transportInfo);
+
+ mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
+ Process.myPid(), Process.myUid(),
+ mContext.getPackageName(), getAttributionTag());
+ // redact both NETWORK_SETTINGS & location sensitive fields.
+ verify(transportInfo).makeCopy(
+ REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
+ }
+
+ /**
+ * Test TransportInfo to verify redaction mechanism.
+ */
+ private static class TestTransportInfo implements TransportInfo {
+ public final boolean locationRedacted;
+ public final boolean localMacAddressRedacted;
+ public final boolean settingsRedacted;
+
+ TestTransportInfo() {
+ locationRedacted = false;
+ localMacAddressRedacted = false;
+ settingsRedacted = false;
+ }
+
+ TestTransportInfo(boolean locationRedacted, boolean localMacAddressRedacted,
+ boolean settingsRedacted) {
+ this.locationRedacted = locationRedacted;
+ this.localMacAddressRedacted =
+ localMacAddressRedacted;
+ this.settingsRedacted = settingsRedacted;
+ }
+
+ @Override
+ public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
+ return new TestTransportInfo(
+ (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
+ (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
+ (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
+ );
+ }
+
+ @Override
+ public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
+ return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
+ | REDACT_FOR_NETWORK_SETTINGS;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof TestTransportInfo)) return false;
+ TestTransportInfo that = (TestTransportInfo) other;
+ return that.locationRedacted == this.locationRedacted
+ && that.localMacAddressRedacted == this.localMacAddressRedacted
+ && that.settingsRedacted == this.settingsRedacted;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted);
+ }
+ }
+
+ private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
+ @NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid,
+ @NonNull TransportInfo actualTransportInfo, int expectedOwnerUid,
+ @NonNull TransportInfo expectedTransportInfo) throws Exception {
+ when(mPackageManager.getTargetSdkVersion(anyString())).thenReturn(Build.VERSION_CODES.S);
+ final NetworkCapabilities ncTemplate =
+ new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .setOwnerUid(actualOwnerUid);
+
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
+ ncTemplate);
+ mWiFiNetworkAgent.connect(false);
+
+ wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+ // Send network capabilities update with TransportInfo to trigger capabilities changed
+ // callback.
+ mWiFiNetworkAgent.setNetworkCapabilities(
+ ncTemplate.setTransportInfo(actualTransportInfo), true);
+
+ wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent,
+ nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid())
+ && Objects.equals(expectedTransportInfo, nc.getTransportInfo()));
+
+ }
+
+ @Test
+ public void testVerifyLocationDataIsNotIncludedWhenInclFlagNotSet() throws Exception {
+ final TestNetworkCallback wifiNetworkCallack = new TestNetworkCallback();
+ final int ownerUid = Process.myUid();
+ final TransportInfo transportInfo = new TestTransportInfo();
+ // Even though the test uid holds privileged permissions, mask location fields since
+ // the callback did not explicitly opt-in to get location data.
+ final TransportInfo sanitizedTransportInfo = new TestTransportInfo(
+ true, /* locationRedacted */
+ true, /* localMacAddressRedacted */
+ true /* settingsRedacted */
+ );
+ // Should not expect location data since the callback does not set the flag for including
+ // location data.
+ verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
+ wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo);
+ }
+
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
throws Exception {
- final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER));
+ final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.setVpnType(vpnType);
mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
@@ -9153,7 +9493,8 @@
ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
- nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
+ nc, new NetworkScore.Builder().setLegacyInt(0).build(),
+ mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
INVALID_UID, mQosCallbackTracker, new ConnectivityService.Dependencies());
}
@@ -9495,10 +9836,12 @@
assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
if (add) {
- inOrder.verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+ inOrder.verify(mMockNetd, times(1))
+ .networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(vpnRanges)));
} else {
- inOrder.verify(mMockNetd, times(1)).networkRemoveUidRanges(eq(mMockVpn.getNetId()),
+ inOrder.verify(mMockNetd, times(1))
+ .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(vpnRanges)));
}
@@ -9513,7 +9856,7 @@
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- final UidRange vpnRange = createUidRange(PRIMARY_USER);
+ final UidRange vpnRange = PRIMARY_UIDRANGE;
Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -9539,8 +9882,8 @@
for (int reqTypeInt : invalidReqTypeInts) {
assertThrows("Expect throws for invalid request type " + reqTypeInt,
IllegalArgumentException.class,
- () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
- ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
+ () -> mService.requestNetwork(Process.INVALID_UID, nc, reqTypeInt, null, 0,
+ null, ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
mContext.getPackageName(), getAttributionTag())
);
}
@@ -9659,7 +10002,7 @@
&& session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionLost(qosCallbackId, sessionId);
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_EPS_BEARER);
waitForIdle();
verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
session.getSessionId() == sessionId
@@ -9667,6 +10010,36 @@
}
@Test
+ public void testNrQosCallbackAvailableAndLost() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+
+ final NrQosSessionAttributes attributes = new NrQosSessionAttributes(
+ 1, 2, 3, 4, 5, 6, 7, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ waitForIdle();
+
+ verify(mQosCallbackMockHelper.mCallback).onNrQosSessionAvailable(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_NR_BEARER), eq(attributes));
+
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_NR_BEARER);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_NR_BEARER));
+ }
+
+ @Test
public void testQosCallbackTooManyRequests() throws Exception {
mQosCallbackMockHelper = new QosCallbackMockHelper();
@@ -9711,7 +10084,7 @@
.thenReturn(hasFeature);
}
- private UidRange getNriFirstUidRange(
+ private Range<Integer> getNriFirstUidRange(
@NonNull final ConnectivityService.NetworkRequestInfo nri) {
return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next();
}
@@ -9894,11 +10267,11 @@
pref));
// Sort by uid to access nris by index
- nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).start));
- assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).start);
- assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).stop);
- assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).start);
- assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).stop);
+ nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).getLower()));
+ assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getLower());
+ assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getUpper());
+ assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getLower());
+ assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getUpper());
}
@Test
@@ -9928,17 +10301,17 @@
// UIDs for all users and all managed packages should be present.
// Two users each with two packages.
final int expectedUidSize = 2;
- final List<UidRange> uids =
+ final List<Range<Integer>> uids =
new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
assertEquals(expectedUidSize, uids.size());
// Sort by uid to access nris by index
- uids.sort(Comparator.comparingInt(uid -> uid.start));
+ uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- assertEquals(TEST_PACKAGE_UID, uids.get(0).start);
- assertEquals(TEST_PACKAGE_UID, uids.get(0).stop);
- assertEquals(secondUserTestPackageUid, uids.get(1).start);
- assertEquals(secondUserTestPackageUid, uids.get(1).stop);
+ assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower());
+ assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper());
+ assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower());
+ assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
}
@Test
@@ -10105,9 +10478,13 @@
Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
mSystemDefaultNetworkCallback = new TestNetworkCallback();
mDefaultNetworkCallback = new TestNetworkCallback();
+ mProfileDefaultNetworkCallback = new TestNetworkCallback();
mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
new Handler(ConnectivityThread.getInstanceLooper()));
mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
+ registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
+ TEST_WORK_PROFILE_APP_UID);
+ // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
mServiceContext.setPermission(
Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
}
@@ -10119,12 +10496,15 @@
if (null != mSystemDefaultNetworkCallback) {
mCm.unregisterNetworkCallback(mSystemDefaultNetworkCallback);
}
+ if (null != mProfileDefaultNetworkCallback) {
+ mCm.unregisterNetworkCallback(mProfileDefaultNetworkCallback);
+ }
}
private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
@OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
throws Exception {
- final int testPackageNameUid = 123;
+ final int testPackageNameUid = TEST_PACKAGE_UID;
final String testPackageName = "per.app.defaults.package";
setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
networkPrefToSetup, testPackageNameUid, testPackageName);
@@ -10174,7 +10554,7 @@
oemPrefListener.expectOnComplete();
}
- private static class TestOemListenerCallback implements IOnSetOemNetworkPreferenceListener {
+ private static class TestOemListenerCallback implements IOnCompleteListener {
final CompletableFuture<Object> mDone = new CompletableFuture<>();
@Override
@@ -10260,6 +10640,11 @@
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Setup the test process to use networkPref for their default network.
setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
@@ -10270,19 +10655,22 @@
null,
mEthernetNetworkAgent.getNetwork());
- // At this point with a restricted network used, the available callback should trigger
+ // At this point with a restricted network used, the available callback should trigger.
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mEthernetNetworkAgent.getNetwork());
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the default network which should trigger a LOST callback.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
// At this point, with no network is available, the lost callback should trigger
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
@Test
@@ -10300,6 +10688,11 @@
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
// The active nai for the default is null at this point as this is a restricted network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
@@ -10311,15 +10704,19 @@
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mEthernetNetworkAgent.getNetwork());
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the default network which should trigger a LOST callback.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+ otherUidDefaultCallback.assertNoCallback();
// At this point, with no network is available, the lost callback should trigger
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
@Test
@@ -10333,6 +10730,11 @@
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(Manifest.permission.NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Setup a process different than the test process to use the default network. This means
// that the defaultNetworkCallback won't be tracked by the per-app policy.
setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
@@ -10348,6 +10750,9 @@
defaultNetworkCallback.assertNoCallback();
assertDefaultNetworkCapabilities(userId /* no networks */);
+ // The other UID does have access, and gets a callback.
+ otherUidDefaultCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
+
// Bring up unrestricted cellular. This should now satisfy the default network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
@@ -10355,25 +10760,31 @@
mEthernetNetworkAgent.getNetwork());
// At this point with an unrestricted network used, the available callback should trigger
+ // The other UID is unaffected and remains on the paid network.
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mCellNetworkAgent.getNetwork());
assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the per-app network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- // Since the callback didn't use the per-app network, no callback should fire.
+ // Since the callback didn't use the per-app network, only the other UID gets a callback.
+ // Because the preference specifies no fallback, it does not switch to cellular.
defaultNetworkCallback.assertNoCallback();
+ otherUidDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
// Now bring down the default network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
// As this callback was tracking the default, this should now trigger.
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
/**
@@ -11112,11 +11523,494 @@
mCm.unregisterNetworkCallback(cellCb);
}
+ // Cannot be part of MockNetworkFactory since it requires method of the test.
+ private void expectNoRequestChanged(@NonNull MockNetworkFactory factory) {
+ waitForIdle();
+ factory.assertNoRequestChanged();
+ }
+
@Test
- public void testRegisterBestMatchingNetworkCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- assertThrows(UnsupportedOperationException.class,
- () -> mCm.registerBestMatchingNetworkCallback(request, new NetworkCallback(),
- mCsHandlerThread.getThreadHandler()));
+ public void testRegisterBestMatchingNetworkCallback_noIssueToFactory() throws Exception {
+ // Prepare mock mms factory.
+ final HandlerThread handlerThread = new HandlerThread("MockCellularFactory");
+ handlerThread.start();
+ NetworkCapabilities filter = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_MMS);
+ final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "testFactory", filter, mCsHandlerThread);
+ testFactory.setScoreFilter(40);
+
+ try {
+ // Register the factory and expect it will see default request, because all requests
+ // are sent to all factories.
+ testFactory.register();
+ testFactory.expectRequestAdd();
+ testFactory.assertRequestCountEquals(1);
+ // The factory won't try to start the network since the default request doesn't
+ // match the filter (no INTERNET capability).
+ assertFalse(testFactory.getMyStartRequested());
+
+ // Register callback for listening best matching network. Verify that the request won't
+ // be sent to factory.
+ final TestNetworkCallback bestMatchingCb = new TestNetworkCallback();
+ mCm.registerBestMatchingNetworkCallback(
+ new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(),
+ bestMatchingCb, mCsHandlerThread.getThreadHandler());
+ bestMatchingCb.assertNoCallback();
+ expectNoRequestChanged(testFactory);
+ testFactory.assertRequestCountEquals(1);
+ assertFalse(testFactory.getMyStartRequested());
+
+ // Fire a normal mms request, verify the factory will only see the request.
+ final TestNetworkCallback mmsNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest mmsRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_MMS).build();
+ mCm.requestNetwork(mmsRequest, mmsNetworkCallback);
+ testFactory.expectRequestAdd();
+ testFactory.assertRequestCountEquals(2);
+ assertTrue(testFactory.getMyStartRequested());
+
+ // Unregister best matching callback, verify factory see no change.
+ mCm.unregisterNetworkCallback(bestMatchingCb);
+ expectNoRequestChanged(testFactory);
+ testFactory.assertRequestCountEquals(2);
+ assertTrue(testFactory.getMyStartRequested());
+ } finally {
+ testFactory.terminate();
+ }
+ }
+
+ @Test
+ public void testRegisterBestMatchingNetworkCallback_trackBestNetwork() throws Exception {
+ final TestNetworkCallback bestMatchingCb = new TestNetworkCallback();
+ mCm.registerBestMatchingNetworkCallback(
+ new NetworkRequest.Builder().addCapability(NET_CAPABILITY_TRUSTED).build(),
+ bestMatchingCb, mCsHandlerThread.getThreadHandler());
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ bestMatchingCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+
+ // Change something on cellular to trigger capabilities changed, since the callback
+ // only cares about the best network, verify it received nothing from cellular.
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ bestMatchingCb.assertNoCallback();
+
+ // Make cellular the best network again, verify the callback now tracks cellular.
+ mWiFiNetworkAgent.adjustScore(-50);
+ bestMatchingCb.expectAvailableCallbacksValidated(mCellNetworkAgent);
+
+ // Make cellular temporary non-trusted, which will not satisfying the request.
+ // Verify the callback switch from/to the other network accordingly.
+ mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
+ bestMatchingCb.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_TRUSTED);
+ bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mCellNetworkAgent);
+
+ // Verify the callback doesn't care about wifi disconnect.
+ mWiFiNetworkAgent.disconnect();
+ bestMatchingCb.assertNoCallback();
+ mCellNetworkAgent.disconnect();
+ bestMatchingCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ }
+
+ private UidRangeParcel[] uidRangeFor(final UserHandle handle) {
+ UidRange range = UidRange.createForUser(handle);
+ return new UidRangeParcel[] { new UidRangeParcel(range.start, range.stop) };
+ }
+
+ private static class TestOnCompleteListener implements Runnable {
+ final class OnComplete {}
+ final ArrayTrackRecord<OnComplete>.ReadHead mHistory =
+ new ArrayTrackRecord<OnComplete>().newReadHead();
+
+ @Override
+ public void run() {
+ mHistory.add(new OnComplete());
+ }
+
+ public void expectOnComplete() {
+ assertNotNull(mHistory.poll(TIMEOUT_MS, it -> true));
+ }
+ }
+
+ private TestNetworkAgentWrapper makeEnterpriseNetworkAgent() throws Exception {
+ final NetworkCapabilities workNc = new NetworkCapabilities();
+ workNc.addCapability(NET_CAPABILITY_ENTERPRISE);
+ workNc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ return new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), workNc);
+ }
+
+ private TestNetworkCallback mEnterpriseCallback;
+ private UserHandle setupEnterpriseNetwork() {
+ final UserHandle userHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(userHandle, true);
+
+ // File a request to avoid the enterprise network being disconnected as soon as the default
+ // request goes away – it would make impossible to test that networkRemoveUidRanges
+ // is called, as the network would disconnect first for lack of a request.
+ mEnterpriseCallback = new TestNetworkCallback();
+ final NetworkRequest keepUpRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_ENTERPRISE)
+ .build();
+ mCm.requestNetwork(keepUpRequest, mEnterpriseCallback);
+ return userHandle;
+ }
+
+ private void maybeTearDownEnterpriseNetwork() {
+ if (null != mEnterpriseCallback) {
+ mCm.unregisterNetworkCallback(mEnterpriseCallback);
+ }
+ }
+
+ /**
+ * Make sure per-profile networking preference behaves as expected when the enterprise network
+ * goes up and down while the preference is active. Make sure they behave as expected whether
+ * there is a general default network or not.
+ */
+ @Test
+ public void testPreferenceForUserNetworkUpDown() throws Exception {
+ final InOrder inOrder = inOrder(mMockNetd);
+ final UserHandle testHandle = setupEnterpriseNetwork();
+ registerDefaultNetworkCallbacks();
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+
+ // Setting a network preference for this user will create a new set of routing rules for
+ // the UID range that corresponds to this user, so as to define the default network
+ // for these apps separately. This is true because the multi-layer request relevant to
+ // this UID range contains a TRACK_DEFAULT, so the range will be moved through UID-specific
+ // rules to the correct network – in this case the system default network. The case where
+ // the default network for the profile happens to be the same as the system default
+ // is not handled specially, the rules are always active as long as a preference is set.
+ inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ // The enterprise network is not ready yet.
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ mProfileDefaultNetworkCallback);
+
+ final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+ workAgent.connect(false);
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
+ mSystemDefaultNetworkCallback.assertNoCallback();
+ mDefaultNetworkCallback.assertNoCallback();
+ inOrder.verify(mMockNetd).networkCreatePhysical(workAgent.getNetwork().netId,
+ INetd.PERMISSION_SYSTEM);
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ // Make sure changes to the work agent send callbacks to the app in the work profile, but
+ // not to the other apps.
+ workAgent.setNetworkValid(true /* isStrictMode */);
+ workAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+ mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent,
+ nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED)
+ && nc.hasCapability(NET_CAPABILITY_ENTERPRISE));
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+
+ workAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent, nc ->
+ nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+
+ // Conversely, change a capability on the system-wide default network and make sure
+ // that only the apps outside of the work profile receive the callbacks.
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
+ mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
+ nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
+ nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ mProfileDefaultNetworkCallback.assertNoCallback();
+
+ // Disconnect and reconnect the system-wide default network and make sure that the
+ // apps on this network see the appropriate callbacks, and the app on the work profile
+ // doesn't because it continues to use the enterprise network.
+ mCellNetworkAgent.disconnect();
+ mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.assertNoCallback();
+ inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.assertNoCallback();
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+
+ // When the agent disconnects, test that the app on the work profile falls back to the
+ // default network.
+ workAgent.disconnect();
+ mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent);
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+ inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
+
+ mCellNetworkAgent.disconnect();
+ mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+
+ // Waiting for the handler to be idle before checking for networkDestroy is necessary
+ // here because ConnectivityService calls onLost before the network is fully torn down.
+ waitForIdle();
+ inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
+
+ // If the control comes here, callbacks seem to behave correctly in the presence of
+ // a default network when the enterprise network goes up and down. Now, make sure they
+ // also behave correctly in the absence of a system-wide default network.
+ final TestNetworkAgentWrapper workAgent2 = makeEnterpriseNetworkAgent();
+ workAgent2.connect(false);
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent2);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd).networkCreatePhysical(workAgent2.getNetwork().netId,
+ INetd.PERMISSION_SYSTEM);
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent2.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ workAgent2.setNetworkValid(true /* isStrictMode */);
+ workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid());
+ mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent2,
+ nc -> nc.hasCapability(NET_CAPABILITY_ENTERPRISE)
+ && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
+
+ // When the agent disconnects, test that the app on the work profile falls back to the
+ // default network.
+ workAgent2.disconnect();
+ mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent2);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd).networkDestroy(workAgent2.getNetwork().netId);
+
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ mProfileDefaultNetworkCallback);
+
+ // Callbacks will be unregistered by tearDown()
+ }
+
+ /**
+ * Test that, in a given networking context, calling setPreferenceForUser to set per-profile
+ * defaults on then off works as expected.
+ */
+ @Test
+ public void testSetPreferenceForUserOnOff() throws Exception {
+ final InOrder inOrder = inOrder(mMockNetd);
+ final UserHandle testHandle = setupEnterpriseNetwork();
+
+ // Connect both a regular cell agent and an enterprise network first.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+ workAgent.connect(true);
+
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ registerDefaultNetworkCallbacks();
+
+ mSystemDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
+
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_DEFAULT,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
+ inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ workAgent.disconnect();
+ mCellNetworkAgent.disconnect();
+
+ // Callbacks will be unregistered by tearDown()
+ }
+
+ /**
+ * Test per-profile default networks for two different profiles concurrently.
+ */
+ @Test
+ public void testSetPreferenceForTwoProfiles() throws Exception {
+ final InOrder inOrder = inOrder(mMockNetd);
+ final UserHandle testHandle2 = setupEnterpriseNetwork();
+ final UserHandle testHandle4 = UserHandle.of(TEST_WORK_PROFILE_USER_ID + 2);
+ mServiceContext.setWorkProfile(testHandle4, true);
+ registerDefaultNetworkCallbacks();
+
+ final TestNetworkCallback app4Cb = new TestNetworkCallback();
+ final int testWorkProfileAppUid4 =
+ UserHandle.getUid(testHandle4.getIdentifier(), TEST_APP_ID);
+ registerDefaultNetworkCallbackAsUid(app4Cb, testWorkProfileAppUid4);
+
+ // Connect both a regular cell agent and an enterprise network first.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
+ workAgent.connect(true);
+
+ mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ app4Cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+ inOrder.verify(mMockNetd).networkCreatePhysical(workAgent.getNetwork().netId,
+ INetd.PERMISSION_SYSTEM);
+
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle2));
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ app4Cb);
+
+ mCm.setProfileNetworkPreference(testHandle4, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle4));
+
+ app4Cb.expectAvailableCallbacksValidated(workAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ mProfileDefaultNetworkCallback);
+
+ mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_DEFAULT,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
+ uidRangeFor(testHandle2));
+
+ mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
+ app4Cb);
+
+ workAgent.disconnect();
+ mCellNetworkAgent.disconnect();
+
+ mCm.unregisterNetworkCallback(app4Cb);
+ // Other callbacks will be unregistered by tearDown()
+ }
+
+ @Test
+ public void testProfilePreferenceRemovedUponUserRemoved() throws Exception {
+ final InOrder inOrder = inOrder(mMockNetd);
+ final UserHandle testHandle = setupEnterpriseNetwork();
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ inOrder.verify(mMockNetd).networkCreatePhysical(mCellNetworkAgent.getNetwork().netId,
+ INetd.PERMISSION_NONE);
+ inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+
+ final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+ removedIntent.putExtra(Intent.EXTRA_USER, testHandle);
+ processBroadcast(removedIntent);
+
+ inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
+ uidRangeFor(testHandle));
+ }
+
+ /**
+ * Make sure that OEM preference and per-profile preference can't be used at the same
+ * time and throw ISE if tried
+ */
+ @Test
+ public void testOemPreferenceAndProfilePreferenceExclusive() throws Exception {
+ final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(testHandle, true);
+ final TestOnCompleteListener listener = new TestOnCompleteListener();
+
+ setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
+ OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY);
+ assertThrows("Should not be able to set per-profile pref while OEM prefs present",
+ IllegalStateException.class, () ->
+ mCm.setProfileNetworkPreference(testHandle,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener));
+
+ // Empty the OEM prefs
+ final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
+ final OemNetworkPreferences emptyOemPref = new OemNetworkPreferences.Builder().build();
+ mService.setOemNetworkPreference(emptyOemPref, oemPrefListener);
+ oemPrefListener.expectOnComplete();
+
+ mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
+ r -> r.run(), listener);
+ listener.expectOnComplete();
+ assertThrows("Should not be able to set OEM prefs while per-profile pref is on",
+ IllegalStateException.class , () ->
+ mService.setOemNetworkPreference(emptyOemPref, oemPrefListener));
+ }
+
+ /**
+ * Make sure wrong preferences for per-profile default networking are rejected.
+ */
+ @Test
+ public void testProfileNetworkPrefWrongPreference() throws Exception {
+ final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(testHandle, true);
+ assertThrows("Should not be able to set an illegal preference",
+ IllegalArgumentException.class,
+ () -> mCm.setProfileNetworkPreference(testHandle,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE + 1, null, null));
+ }
+
+ /**
+ * Make sure requests for per-profile default networking for a non-work profile are
+ * rejected
+ */
+ @Test
+ public void testProfileNetworkPrefWrongProfile() throws Exception {
+ final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
+ mServiceContext.setWorkProfile(testHandle, false);
+ assertThrows("Should not be able to set a user pref for a non-work profile",
+ IllegalArgumentException.class , () ->
+ mCm.setProfileNetworkPreference(testHandle,
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
}
}
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
index a10a3c8..5ec1119 100644
--- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
+++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -21,13 +21,29 @@
package com.android.server
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.FEATURE_WIFI
+import android.content.pm.PackageManager.FEATURE_WIFI_DIRECT
import android.net.ConnectivityManager.TYPE_ETHERNET
import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_MOBILE_CBS
+import android.net.ConnectivityManager.TYPE_MOBILE_DUN
+import android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY
+import android.net.ConnectivityManager.TYPE_MOBILE_FOTA
+import android.net.ConnectivityManager.TYPE_MOBILE_HIPRI
+import android.net.ConnectivityManager.TYPE_MOBILE_IA
+import android.net.ConnectivityManager.TYPE_MOBILE_IMS
+import android.net.ConnectivityManager.TYPE_MOBILE_MMS
import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
+import android.net.ConnectivityManager.TYPE_VPN
import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.ConnectivityManager.TYPE_WIFI_P2P
import android.net.ConnectivityManager.TYPE_WIMAX
+import android.net.EthernetManager
import android.net.NetworkInfo.DetailedState.CONNECTED
import android.net.NetworkInfo.DetailedState.DISCONNECTED
+import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.server.ConnectivityService.LegacyTypeTracker
@@ -36,7 +52,6 @@
import org.junit.Assert.assertNull
import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
@@ -52,88 +67,130 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
class LegacyTypeTrackerTest {
- private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL)
+ private val supportedTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_MOBILE,
+ TYPE_MOBILE_SUPL, TYPE_MOBILE_MMS, TYPE_MOBILE_SUPL, TYPE_MOBILE_DUN, TYPE_MOBILE_HIPRI,
+ TYPE_MOBILE_FOTA, TYPE_MOBILE_IMS, TYPE_MOBILE_CBS, TYPE_MOBILE_IA,
+ TYPE_MOBILE_EMERGENCY, TYPE_VPN)
private val mMockService = mock(ConnectivityService::class.java).apply {
doReturn(false).`when`(this).isDefaultNetwork(any())
}
- private val mTracker = LegacyTypeTracker(mMockService).apply {
- supportedTypes.forEach {
- addSupportedType(it)
- }
+ private val mPm = mock(PackageManager::class.java)
+ private val mContext = mock(Context::class.java).apply {
+ doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI)
+ doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
+ doReturn(mPm).`when`(this).packageManager
+ doReturn(mock(EthernetManager::class.java)).`when`(this).getSystemService(
+ Context.ETHERNET_SERVICE)
+ }
+ private val mTm = mock(TelephonyManager::class.java).apply {
+ doReturn(true).`when`(this).isDataCapable
+ }
+
+ private fun makeTracker() = LegacyTypeTracker(mMockService).apply {
+ loadSupportedTypes(mContext, mTm)
}
@Test
fun testSupportedTypes() {
- try {
- mTracker.addSupportedType(supportedTypes[0])
- fail("Expected IllegalStateException")
- } catch (expected: IllegalStateException) {}
+ val tracker = makeTracker()
supportedTypes.forEach {
- assertTrue(mTracker.isTypeSupported(it))
+ assertTrue(tracker.isTypeSupported(it))
}
- assertFalse(mTracker.isTypeSupported(UNSUPPORTED_TYPE))
+ assertFalse(tracker.isTypeSupported(UNSUPPORTED_TYPE))
+ }
+
+ @Test
+ fun testSupportedTypes_NoEthernet() {
+ doReturn(null).`when`(mContext).getSystemService(Context.ETHERNET_SERVICE)
+ assertFalse(makeTracker().isTypeSupported(TYPE_ETHERNET))
+ }
+
+ @Test
+ fun testSupportedTypes_NoTelephony() {
+ doReturn(false).`when`(mTm).isDataCapable
+ val tracker = makeTracker()
+ val nonMobileTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_VPN)
+ nonMobileTypes.forEach {
+ assertTrue(tracker.isTypeSupported(it))
+ }
+ supportedTypes.toSet().minus(nonMobileTypes).forEach {
+ assertFalse(tracker.isTypeSupported(it))
+ }
+ }
+
+ @Test
+ fun testSupportedTypes_NoWifiDirect() {
+ doReturn(false).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
+ val tracker = makeTracker()
+ assertFalse(tracker.isTypeSupported(TYPE_WIFI_P2P))
+ supportedTypes.toSet().minus(TYPE_WIFI_P2P).forEach {
+ assertTrue(tracker.isTypeSupported(it))
+ }
}
@Test
fun testSupl() {
+ val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, mobileNai)
+ tracker.add(TYPE_MOBILE, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
reset(mMockService)
- mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
+ tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
- mTracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
+ tracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
- mTracker.add(TYPE_MOBILE_SUPL, mobileNai)
+ tracker.add(TYPE_MOBILE_SUPL, mobileNai)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
reset(mMockService)
- mTracker.remove(mobileNai, false)
+ tracker.remove(mobileNai, false)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
}
@Test
fun testAddNetwork() {
+ val tracker = makeTracker()
val mobileNai = mock(NetworkAgentInfo::class.java)
val wifiNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, mobileNai)
- mTracker.add(TYPE_WIFI, wifiNai)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ tracker.add(TYPE_MOBILE, mobileNai)
+ tracker.add(TYPE_WIFI, wifiNai)
+ assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a second NAI does not change the results.
val secondMobileNai = mock(NetworkAgentInfo::class.java)
- mTracker.add(TYPE_MOBILE, secondMobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ tracker.add(TYPE_MOBILE, secondMobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure removing a network that wasn't added for this type is a no-op.
- mTracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ tracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
+ assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Remove the top network for mobile and make sure the second one becomes the network
// of record for this type.
- mTracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
- assertSame(mTracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
- assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai)
+ tracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
+ assertSame(tracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
+ assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
// Make sure adding a network for an unsupported type does not register it.
- mTracker.add(UNSUPPORTED_TYPE, mobileNai)
- assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE))
+ tracker.add(UNSUPPORTED_TYPE, mobileNai)
+ assertNull(tracker.getNetworkForType(UNSUPPORTED_TYPE))
}
@Test
fun testBroadcastOnDisconnect() {
+ val tracker = makeTracker()
val mobileNai1 = mock(NetworkAgentInfo::class.java)
val mobileNai2 = mock(NetworkAgentInfo::class.java)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
- mTracker.add(TYPE_MOBILE, mobileNai1)
+ tracker.add(TYPE_MOBILE, mobileNai1)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
reset(mMockService)
doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
- mTracker.add(TYPE_MOBILE, mobileNai2)
+ tracker.add(TYPE_MOBILE, mobileNai2)
verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
- mTracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
+ tracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
}
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 5760211..692c50f 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -18,15 +18,15 @@
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
+import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
import static android.net.NetworkCapabilities.MAX_TRANSPORT;
import static android.net.NetworkCapabilities.MIN_TRANSPORT;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
-import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static com.android.testutils.MiscAsserts.assertContainsExactly;
import static com.android.testutils.MiscAsserts.assertContainsStringsExactly;
@@ -312,14 +312,14 @@
@Test
public void testOverrideDefaultMode() throws Exception {
// Hard-coded default is opportunistic mode.
- final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mContentResolver);
+ final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mCtx);
assertTrue(cfgAuto.useTls);
assertEquals("", cfgAuto.hostname);
assertEquals(new InetAddress[0], cfgAuto.ips);
// Pretend a gservices push sets the default to "off".
Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off");
- final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mContentResolver);
+ final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mCtx);
assertFalse(cfgOff.useTls);
assertEquals("", cfgOff.hostname);
assertEquals(new InetAddress[0], cfgOff.ips);
@@ -328,7 +328,7 @@
Settings.Global.putString(
mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
- final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mContentResolver);
+ final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mCtx);
assertTrue(cfgStrict.useTls);
assertEquals("strictmode.com", cfgStrict.hostname);
assertEquals(new InetAddress[0], cfgStrict.ips);
diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
new file mode 100644
index 0000000..eb3b4df
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity
+
+import android.net.NetworkAgentConfig
+import android.net.NetworkCapabilities
+import android.text.TextUtils
+import android.util.ArraySet
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.connectivity.FullScore.MAX_CS_MANAGED_POLICY
+import com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED
+import com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED
+import com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED
+import com.android.server.connectivity.FullScore.POLICY_IS_VPN
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.collections.minOfOrNull
+import kotlin.collections.maxOfOrNull
+import kotlin.reflect.full.staticProperties
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class FullScoreTest {
+ // Convenience methods
+ fun FullScore.withPolicies(
+ validated: Boolean = false,
+ vpn: Boolean = false,
+ onceChosen: Boolean = false,
+ acceptUnvalidated: Boolean = false
+ ): FullScore {
+ val nac = NetworkAgentConfig.Builder().apply {
+ setUnvalidatedConnectivityAcceptable(acceptUnvalidated)
+ setExplicitlySelected(onceChosen)
+ }.build()
+ val nc = NetworkCapabilities.Builder().apply {
+ if (vpn) addTransportType(NetworkCapabilities.TRANSPORT_VPN)
+ if (validated) addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+ }.build()
+ return mixInScore(nc, nac)
+ }
+
+ @Test
+ fun testGetLegacyInt() {
+ val ns = FullScore(50, 0L /* policy */)
+ assertEquals(10, ns.legacyInt) // -40 penalty for not being validated
+ assertEquals(50, ns.legacyIntAsValidated)
+
+ val vpnNs = FullScore(101, 0L /* policy */).withPolicies(vpn = true)
+ assertEquals(101, vpnNs.legacyInt) // VPNs are not subject to unvalidation penalty
+ assertEquals(101, vpnNs.legacyIntAsValidated)
+ assertEquals(101, vpnNs.withPolicies(validated = true).legacyInt)
+ assertEquals(101, vpnNs.withPolicies(validated = true).legacyIntAsValidated)
+
+ val validatedNs = ns.withPolicies(validated = true)
+ assertEquals(50, validatedNs.legacyInt) // No penalty, this is validated
+ assertEquals(50, validatedNs.legacyIntAsValidated)
+
+ val chosenNs = ns.withPolicies(onceChosen = true)
+ assertEquals(10, chosenNs.legacyInt)
+ assertEquals(100, chosenNs.legacyIntAsValidated)
+ assertEquals(10, chosenNs.withPolicies(acceptUnvalidated = true).legacyInt)
+ assertEquals(50, chosenNs.withPolicies(acceptUnvalidated = true).legacyIntAsValidated)
+ }
+
+ @Test
+ fun testToString() {
+ val string = FullScore(10, 0L /* policy */)
+ .withPolicies(vpn = true, acceptUnvalidated = true).toString()
+ assertTrue(string.contains("Score(10"), string)
+ assertTrue(string.contains("ACCEPT_UNVALIDATED"), string)
+ assertTrue(string.contains("IS_VPN"), string)
+ assertFalse(string.contains("IS_VALIDATED"), string)
+ val foundNames = ArraySet<String>()
+ getAllPolicies().forEach {
+ val name = FullScore.policyNameOf(it.get() as Int)
+ assertFalse(TextUtils.isEmpty(name))
+ assertFalse(foundNames.contains(name))
+ foundNames.add(name)
+ }
+ assertFailsWith<IllegalArgumentException> {
+ FullScore.policyNameOf(MAX_CS_MANAGED_POLICY + 1)
+ }
+ }
+
+ fun getAllPolicies() = Regex("POLICY_.*").let { nameRegex ->
+ FullScore::class.staticProperties.filter { it.name.matches(nameRegex) }
+ }
+
+ @Test
+ fun testHasPolicy() {
+ val ns = FullScore(50, 0L /* policy */)
+ assertFalse(ns.hasPolicy(POLICY_IS_VALIDATED))
+ assertFalse(ns.hasPolicy(POLICY_IS_VPN))
+ assertFalse(ns.hasPolicy(POLICY_EVER_USER_SELECTED))
+ assertFalse(ns.hasPolicy(POLICY_ACCEPT_UNVALIDATED))
+ assertTrue(ns.withPolicies(validated = true).hasPolicy(POLICY_IS_VALIDATED))
+ assertTrue(ns.withPolicies(vpn = true).hasPolicy(POLICY_IS_VPN))
+ assertTrue(ns.withPolicies(onceChosen = true).hasPolicy(POLICY_EVER_USER_SELECTED))
+ assertTrue(ns.withPolicies(acceptUnvalidated = true).hasPolicy(POLICY_ACCEPT_UNVALIDATED))
+ }
+
+ @Test
+ fun testMinMaxPolicyConstants() {
+ val policies = getAllPolicies()
+
+ policies.forEach { policy ->
+ assertTrue(policy.get() as Int >= FullScore.MIN_CS_MANAGED_POLICY)
+ assertTrue(policy.get() as Int <= FullScore.MAX_CS_MANAGED_POLICY)
+ }
+ assertEquals(FullScore.MIN_CS_MANAGED_POLICY,
+ policies.minOfOrNull { it.get() as Int })
+ assertEquals(FullScore.MAX_CS_MANAGED_POLICY,
+ policies.maxOfOrNull { it.get() as Int })
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 1c0ba4f..9ab60a4 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -40,6 +40,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
+import android.net.NetworkScore;
import android.os.Binder;
import android.text.format.DateUtils;
@@ -355,8 +356,9 @@
caps.addCapability(0);
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
- new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */,
- mConnService, mNetd, mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
+ new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(),
+ mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd,
+ mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(),
mQosCallbackTracker, new ConnectivityService.Dependencies());
nai.everValidated = true;
return nai;
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index ff8c632..3adf08c 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -35,6 +36,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.net.ConnectivityResources;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.UserHandle;
@@ -43,9 +45,10 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.R;
+import com.android.connectivity.resources.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -119,11 +122,25 @@
when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO);
+ ConnectivityResources.setResourcesContextForTest(mCtx);
when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
+ // Come up with some credible-looking transport names. The actual values do not matter.
+ String[] transportNames = new String[NetworkCapabilities.MAX_TRANSPORT + 1];
+ for (int transport = 0; transport <= NetworkCapabilities.MAX_TRANSPORT; transport++) {
+ transportNames[transport] = NetworkCapabilities.transportNameOf(transport);
+ }
+ when(mResources.getStringArray(R.array.network_switch_type_name))
+ .thenReturn(transportNames);
+
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
}
+ @After
+ public void tearDown() {
+ ConnectivityResources.setResourcesContextForTest(null);
+ }
+
private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
final String tag = NetworkNotificationManager.tagFor(id);
mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
@@ -142,15 +159,15 @@
public void testTitleOfPrivateDnsBroken() {
// Test the title of mobile data.
verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
// Test the title of wifi.
verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
// Test the title of other networks.
verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index b8f7fbc..6ad4900 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -23,6 +23,7 @@
import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.INetd.IF_STATE_DOWN;
import static android.net.INetd.IF_STATE_UP;
+import static android.os.UserHandle.PER_USER_RANGE;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -74,7 +75,6 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.RouteInfo;
-import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.VpnManager;
import android.net.VpnService;
@@ -181,8 +181,7 @@
mPackages.put(PKGS[i], PKG_UIDS[i]);
}
}
- private static final UidRange PRI_USER_RANGE =
- UidRange.createForUser(UserHandle.of(primaryUser.id));
+ private static final Range<Integer> PRI_USER_RANGE = uidRangeForUser(primaryUser.id);
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
@Mock private UserManager mUserManager;
@@ -260,6 +259,21 @@
.thenReturn(tunnelResp);
}
+ private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
+ final Set<Range<Integer>> range = new ArraySet<>();
+ for (Range<Integer> r : ranges) range.add(r);
+
+ return range;
+ }
+
+ private static Range<Integer> uidRangeForUser(int userId) {
+ return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
+ }
+
+ private Range<Integer> uidRange(int start, int stop) {
+ return new Range<Integer>(start, stop);
+ }
+
@Test
public void testRestrictedProfilesAreAddedToVpn() {
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
@@ -268,12 +282,10 @@
// Assume the user can have restricted profiles.
doReturn(true).when(mUserManager).canHaveRestrictedProfile();
- final Set<UidRange> ranges =
+ final Set<Range<Integer>> ranges =
vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id))
- })), ranges);
+ assertEquals(rangeSet(PRI_USER_RANGE, uidRangeForUser(restrictedProfileA.id)), ranges);
}
@Test
@@ -281,10 +293,10 @@
setMockedUsers(primaryUser, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id);
- final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+ final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
+ assertEquals(rangeSet(PRI_USER_RANGE), ranges);
}
@Test
@@ -292,35 +304,38 @@
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id);
- final Set<UidRange> ranges = new ArraySet<>();
+ final Set<Range<Integer>> ranges = new ArraySet<>();
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
+ assertEquals(rangeSet(PRI_USER_RANGE), ranges);
}
@Test
public void testUidAllowAndDenylist() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = PRI_USER_RANGE;
+ final Range<Integer> user = PRI_USER_RANGE;
+ final int userStart = user.getLower();
+ final int userStop = user.getUpper();
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
// Allowed list
- final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- Arrays.asList(packages), null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]),
- new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2])
- })), allow);
+ final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+ Arrays.asList(packages), null /* disallowedApplications */);
+ assertEquals(rangeSet(
+ uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]),
+ uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2])),
+ allow);
// Denied list
- final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- null, Arrays.asList(packages));
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
- })), disallow);
+ final Set<Range<Integer>> disallow =
+ vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
+ null /* allowedApplications */, Arrays.asList(packages));
+ assertEquals(rangeSet(
+ uidRange(userStart, userStart + PKG_UIDS[0] - 1),
+ uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+ /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
+ uidRange(userStart + PKG_UIDS[2] + 1, userStop)),
+ disallow);
}
@Test
@@ -350,84 +365,86 @@
@Test
public void testLockdownChangingPackage() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = PRI_USER_RANGE;
-
+ final Range<Integer> user = PRI_USER_RANGE;
+ final int userStart = user.getLower();
+ final int userStop = user.getUpper();
// Set always-on without lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
// Set always-on with lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
}));
// Switch to another app.
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
}));
}
@Test
public void testLockdownAllowlist() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = PRI_USER_RANGE;
-
+ final Range<Integer> user = PRI_USER_RANGE;
+ final int userStart = user.getLower();
+ final int userStop = user.getUpper();
// Set always-on with lockdown and allow app PKGS[2] from lockdown.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[1], true, Collections.singletonList(PKGS[2])));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
+ verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
}));
// Change allowed app list to PKGS[3].
assertTrue(vpn.setAlwaysOnPackage(
PKGS[1], true, Collections.singletonList(PKGS[3])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
}));
// Change the VPN app.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Collections.singletonList(PKGS[3])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
+ new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1)
}));
// Remove the list of allowed packages.
assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop),
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop),
}));
// Add the list of allowed packages.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Collections.singletonList(PKGS[1])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
}));
// Try allowing a package with a comma, should be rejected.
@@ -439,12 +456,12 @@
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
}));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
- new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
+ new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1),
+ new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
}));
}
@@ -452,7 +469,7 @@
public void testLockdownRuleRepeatability() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
- new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)};
+ new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())};
// Given legacy lockdown is already enabled,
vpn.setLockdown(true);
verify(mConnectivityManager, times(1)).setRequireVpnForUids(true,
@@ -484,7 +501,7 @@
public void testLockdownRuleReversibility() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] entireUser = {
- new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)
+ new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())
};
final UidRangeParcel[] exceptPkg0 = {
new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
@@ -1026,7 +1043,11 @@
.thenReturn(new Network[] { new Network(101) });
when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
- anyInt(), any(), anyInt())).thenReturn(new Network(102));
+ any(), any(), anyInt())).thenAnswer(invocation -> {
+ // The runner has registered an agent and is now ready.
+ legacyRunnerReady.open();
+ return new Network(102);
+ });
final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
final TestDeps deps = (TestDeps) vpn.mDeps;
try {
@@ -1048,7 +1069,7 @@
ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
- lpCaptor.capture(), ncCaptor.capture(), anyInt(), any(), anyInt());
+ lpCaptor.capture(), ncCaptor.capture(), any(), any(), anyInt());
// In this test the expected address is always v4 so /32.
// Note that the interface needs to be specified because RouteInfo objects stored in