diff --git a/api/system-current.txt b/api/system-current.txt
index 1d6b595bc9661..b89a1da22ca27 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3193,6 +3193,7 @@ package android.net {
method public int[] getTransportTypes();
method public boolean satisfiedByNetworkCapabilities(android.net.NetworkCapabilities);
field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
+ field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
}
public class NetworkKey implements android.os.Parcelable {
@@ -3341,10 +3342,12 @@ package android.net.captiveportal {
ctor public CaptivePortalProbeResult(int, String, String);
ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
method public boolean isFailed();
+ method public boolean isPartialConnectivity();
method public boolean isPortal();
method public boolean isSuccessful();
field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
field public static final int FAILED_CODE = 599; // 0x257
+ field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL;
field public static final int PORTAL_CODE = 302; // 0x12e
field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
field public static final int SUCCESS_CODE = 204; // 0xcc
@@ -3476,6 +3479,7 @@ package android.net.metrics {
field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
field public static final int NETWORK_LINGER = 5; // 0x5
+ field public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd
field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
field public static final int NETWORK_UNLINGER = 6; // 0x6
diff --git a/api/test-current.txt b/api/test-current.txt
index 055066337da5c..d43b1c4ec275c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -751,10 +751,12 @@ package android.net.captiveportal {
ctor public CaptivePortalProbeResult(int, String, String);
ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
method public boolean isFailed();
+ method public boolean isPartialConnectivity();
method public boolean isPortal();
method public boolean isSuccessful();
field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
field public static final int FAILED_CODE = 599; // 0x257
+ field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL;
field public static final int PORTAL_CODE = 302; // 0x12e
field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
field public static final int SUCCESS_CODE = 204; // 0xcc
@@ -886,6 +888,7 @@ package android.net.metrics {
field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
field public static final int NETWORK_LINGER = 5; // 0x5
+ field public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd
field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
field public static final int NETWORK_UNLINGER = 6; // 0x6
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 249357e3633d7..91fefa2f1cb09 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -426,6 +426,16 @@ public class ConnectivityManager {
public static final String ACTION_PROMPT_LOST_VALIDATION =
"android.net.conn.PROMPT_LOST_VALIDATION";
+ /**
+ * Action used to display a dialog that asks the user whether to stay connected to a network
+ * that has not validated. This intent is used to start the dialog in settings via
+ * startActivity.
+ *
+ * @hide
+ */
+ public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY =
+ "android.net.conn.PROMPT_PARTIAL_CONNECTIVITY";
+
/**
* Invalid tethering type.
* @see #startTethering(int, boolean, OnStartTetheringCallback)
@@ -4018,7 +4028,7 @@ public class ConnectivityManager {
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
try {
mService.setAcceptUnvalidated(network, accept, always);
@@ -4027,6 +4037,29 @@ public class ConnectivityManager {
}
}
+ /**
+ * Informs the system whether it should consider the network as validated even if it only has
+ * partial connectivity. If {@code accept} is true, then the network will be considered as
+ * validated even if connectivity is only partial. If {@code always} is true, then the choice
+ * is remembered, so that the next time the user connects to this network, the system will
+ * switch to it.
+ *
+ * @param network The network to accept.
+ * @param accept Whether to consider the network as validated even if it has partial
+ * connectivity.
+ * @param always Whether to remember this choice in the future.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+ public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) {
+ try {
+ mService.setAcceptPartialConnectivity(network, accept, always);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is
* only meaningful if the system is configured not to penalize such networks, e.g., if the
@@ -4037,7 +4070,7 @@ public class ConnectivityManager {
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void setAvoidUnvalidated(Network network) {
try {
mService.setAvoidUnvalidated(network);
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 9fc56b4e3d36b..2df4e75c49a42 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -176,6 +176,7 @@ interface IConnectivityManager
void releaseNetworkRequest(in NetworkRequest networkRequest);
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
+ void setAcceptPartialConnectivity(in Network network, boolean accept, boolean always);
void setAvoidUnvalidated(in Network network);
void startCaptivePortalApp(in Network network);
void startCaptivePortalAppInternal(in Network network, in Bundle appExtras);
diff --git a/core/java/android/net/INetworkMonitor.aidl b/core/java/android/net/INetworkMonitor.aidl
index c94cdde15aa8c..5d1ab983c5fcd 100644
--- a/core/java/android/net/INetworkMonitor.aidl
+++ b/core/java/android/net/INetworkMonitor.aidl
@@ -32,9 +32,16 @@ oneway interface INetworkMonitor {
// 3. a broken network (e.g. DNS failed, connect failed, HTTP request failed).
const int NETWORK_TEST_RESULT_INVALID = 1;
+ // After a network has been tested, this result can be sent with EVENT_NETWORK_TESTED.
+ // The network may be used as a default internet connection, but it was found to be a partial
+ // connectivity network which can get the pass result for http probe but get the failed result
+ // for https probe.
+ const int NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY = 2;
+
void start();
void launchCaptivePortalApp();
void notifyCaptivePortalAppFinished(int response);
+ void notifyAcceptPartialConnectivity();
void forceReevaluation(int uid);
void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config);
void notifyDnsResponse(int returnCode);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 0a63e75d1a310..e1cfe991de8da 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -143,7 +143,8 @@ public final class NetworkCapabilities implements Parcelable {
NET_CAPABILITY_NOT_CONGESTED,
NET_CAPABILITY_NOT_SUSPENDED,
NET_CAPABILITY_OEM_PAID,
- NET_CAPABILITY_MCX
+ NET_CAPABILITY_MCX,
+ NET_CAPABILITY_PARTIAL_CONNECTIVITY,
})
public @interface NetCapability { }
@@ -304,8 +305,15 @@ public final class NetworkCapabilities implements Parcelable {
*/
public static final int NET_CAPABILITY_MCX = 23;
+ /**
+ * Indicates that this network was tested to only provide partial connectivity.
+ * @hide
+ */
+ @SystemApi
+ public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_MCX;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_PARTIAL_CONNECTIVITY;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -320,7 +328,8 @@ public final class NetworkCapabilities implements Parcelable {
| (1 << NET_CAPABILITY_NOT_ROAMING)
| (1 << NET_CAPABILITY_FOREGROUND)
| (1 << NET_CAPABILITY_NOT_CONGESTED)
- | (1 << NET_CAPABILITY_NOT_SUSPENDED);
+ | (1 << NET_CAPABILITY_NOT_SUSPENDED)
+ | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);
/**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -374,6 +383,15 @@ public final class NetworkCapabilities implements Parcelable {
(1 << NET_CAPABILITY_SUPL) |
(1 << NET_CAPABILITY_WIFI_P2P);
+ /**
+ * Capabilities that are managed by ConnectivityService.
+ */
+ private static final long CONNECTIVITY_MANAGED_CAPABILITIES =
+ (1 << NET_CAPABILITY_VALIDATED)
+ | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
+ | (1 << NET_CAPABILITY_FOREGROUND)
+ | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);
+
/**
* Adds the given capability to this {@code NetworkCapability} instance.
* Multiple capabilities may be applied sequentially. Note that when searching
@@ -507,6 +525,14 @@ public final class NetworkCapabilities implements Parcelable {
&& ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
}
+ /**
+ * Check if this NetworkCapabilities has system managed capabilities or not.
+ * @hide
+ */
+ public boolean hasConnectivityManagedCapability() {
+ return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
+ }
+
/** Note this method may result in having the same capability in wanted and unwanted lists. */
private void combineNetCapabilities(NetworkCapabilities nc) {
this.mNetworkCapabilities |= nc.mNetworkCapabilities;
@@ -1599,31 +1625,32 @@ public final class NetworkCapabilities implements Parcelable {
*/
public static String capabilityNameOf(@NetCapability int capability) {
switch (capability) {
- case NET_CAPABILITY_MMS: return "MMS";
- case NET_CAPABILITY_SUPL: return "SUPL";
- case NET_CAPABILITY_DUN: return "DUN";
- case NET_CAPABILITY_FOTA: return "FOTA";
- case NET_CAPABILITY_IMS: return "IMS";
- case NET_CAPABILITY_CBS: return "CBS";
- case NET_CAPABILITY_WIFI_P2P: return "WIFI_P2P";
- case NET_CAPABILITY_IA: return "IA";
- case NET_CAPABILITY_RCS: return "RCS";
- case NET_CAPABILITY_XCAP: return "XCAP";
- case NET_CAPABILITY_EIMS: return "EIMS";
- case NET_CAPABILITY_NOT_METERED: return "NOT_METERED";
- case NET_CAPABILITY_INTERNET: return "INTERNET";
- case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED";
- case NET_CAPABILITY_TRUSTED: return "TRUSTED";
- case NET_CAPABILITY_NOT_VPN: return "NOT_VPN";
- case NET_CAPABILITY_VALIDATED: return "VALIDATED";
- case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL";
- case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING";
- case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
- case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED";
- case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED";
- case NET_CAPABILITY_OEM_PAID: return "OEM_PAID";
- case NET_CAPABILITY_MCX: return "MCX";
- default: return Integer.toString(capability);
+ case NET_CAPABILITY_MMS: return "MMS";
+ case NET_CAPABILITY_SUPL: return "SUPL";
+ case NET_CAPABILITY_DUN: return "DUN";
+ case NET_CAPABILITY_FOTA: return "FOTA";
+ case NET_CAPABILITY_IMS: return "IMS";
+ case NET_CAPABILITY_CBS: return "CBS";
+ case NET_CAPABILITY_WIFI_P2P: return "WIFI_P2P";
+ case NET_CAPABILITY_IA: return "IA";
+ case NET_CAPABILITY_RCS: return "RCS";
+ case NET_CAPABILITY_XCAP: return "XCAP";
+ case NET_CAPABILITY_EIMS: return "EIMS";
+ case NET_CAPABILITY_NOT_METERED: return "NOT_METERED";
+ case NET_CAPABILITY_INTERNET: return "INTERNET";
+ case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED";
+ case NET_CAPABILITY_TRUSTED: return "TRUSTED";
+ case NET_CAPABILITY_NOT_VPN: return "NOT_VPN";
+ case NET_CAPABILITY_VALIDATED: return "VALIDATED";
+ case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL";
+ case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING";
+ case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
+ case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED";
+ case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED";
+ case NET_CAPABILITY_OEM_PAID: return "OEM_PAID";
+ case NET_CAPABILITY_MCX: return "MCX";
+ case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY";
+ default: return Integer.toString(capability);
}
}
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index c0487b521b466..6fb239015aee4 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -51,6 +51,12 @@ public class NetworkMisc implements Parcelable {
*/
public boolean acceptUnvalidated;
+ /**
+ * Whether the user explicitly set that this network should be validated even if presence of
+ * only partial internet connectivity.
+ */
+ public boolean acceptPartialConnectivity;
+
/**
* Set to avoid surfacing the "Sign in to network" notification.
* if carrier receivers/apps are registered to handle the carrier-specific provisioning
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
index 7432687e136f6..3930344e5d27b 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
@@ -30,10 +30,20 @@ public final class CaptivePortalProbeResult {
public static final int SUCCESS_CODE = 204;
public static final int FAILED_CODE = 599;
public static final int PORTAL_CODE = 302;
+ // Set partial connectivity http response code to -1 to prevent conflict with the other http
+ // response codes. Besides the default http response code of probe result is set as 599 in
+ // NetworkMonitor#sendParallelHttpProbes(), so response code will be set as -1 only when
+ // NetworkMonitor detects partial connectivity.
+ /**
+ * @hide
+ */
+ public static final int PARTIAL_CODE = -1;
public static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(FAILED_CODE);
public static final CaptivePortalProbeResult SUCCESS =
new CaptivePortalProbeResult(SUCCESS_CODE);
+ public static final CaptivePortalProbeResult PARTIAL =
+ new CaptivePortalProbeResult(PARTIAL_CODE);
private final int mHttpResponseCode; // HTTP response code returned from Internet probe.
public final String redirectUrl; // Redirect destination returned from Internet probe.
@@ -69,4 +79,8 @@ public final class CaptivePortalProbeResult {
public boolean isFailed() {
return !isSuccessful() && !isPortal();
}
+
+ public boolean isPartialConnectivity() {
+ return mHttpResponseCode == PARTIAL_CODE;
+ }
}
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index f5b2ff1304949..5128115800217 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -50,6 +50,8 @@ public final class NetworkEvent implements IpConnectivityLog.Event {
public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12;
+ public static final int NETWORK_PARTIAL_CONNECTIVITY = 13;
+
/** @hide */
@IntDef(value = {
NETWORK_CONNECTED,
@@ -64,6 +66,7 @@ public final class NetworkEvent implements IpConnectivityLog.Event {
NETWORK_FIRST_VALIDATION_PORTAL_FOUND,
NETWORK_REVALIDATION_PORTAL_FOUND,
NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND,
+ NETWORK_PARTIAL_CONNECTIVITY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b412f0fdb9b5f..b4e69adc119ce 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3197,13 +3197,18 @@
%1$s
- Wi-Fi has no internet access
+ %1$s has no internet access
Tap for options
Connected
+
+ %1$s has limited connectivity
+
+
+ Tap to connect anyway