Merge "Check if network has partial connectivity"
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -3197,13 +3197,18 @@
|
||||
<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">Wi-Fi has no internet access</string>
|
||||
<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 after the user logs in to a captive portal network, to indicate that the network should now have internet connectivity. This is the message of notification. [CHAR LIMIT=50] -->
|
||||
<string name="captive_portal_logged_in_detailed">Connected</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 is shown when the user's softap config has been changed due to underlying
|
||||
hardware restrictions. This is the notifications's title.
|
||||
|
||||
@@ -1211,6 +1211,8 @@
|
||||
<java-symbol type="string" name="mediasize_japanese_kahu" />
|
||||
<java-symbol type="string" name="mediasize_japanese_kaku2" />
|
||||
<java-symbol type="string" name="mediasize_japanese_you4" />
|
||||
<java-symbol type="string" name="network_partial_connectivity" />
|
||||
<java-symbol type="string" name="network_partial_connectivity_detailed" />
|
||||
<java-symbol type="string" name="reason_service_unavailable" />
|
||||
<java-symbol type="string" name="reason_unknown" />
|
||||
<java-symbol type="string" name="restr_pin_enter_admin_pin" />
|
||||
|
||||
@@ -252,6 +252,12 @@ public class NetworkStackService extends Service {
|
||||
mNm.notifyCaptivePortalAppFinished(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyAcceptPartialConnectivity() {
|
||||
checkNetworkStackCallingPermission();
|
||||
mNm.notifyAcceptPartialConnectivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceReevaluation(int uid) {
|
||||
checkNetworkStackCallingPermission();
|
||||
|
||||
@@ -24,6 +24,7 @@ import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL;
|
||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||
@@ -227,6 +228,12 @@ public class NetworkMonitor extends StateMachine {
|
||||
*/
|
||||
public static final int EVENT_DNS_NOTIFICATION = 17;
|
||||
|
||||
/**
|
||||
* ConnectivityService notifies NetworkMonitor that the user accepts partial connectivity and
|
||||
* NetworkMonitor should ignore the https probe.
|
||||
*/
|
||||
public static final int EVENT_ACCEPT_PARTIAL_CONNECTIVITY = 18;
|
||||
|
||||
// Start mReevaluateDelayMs at this value and double.
|
||||
private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
|
||||
private static final int MAX_REEVALUATE_DELAY_MS = 10 * 60 * 1000;
|
||||
@@ -378,6 +385,14 @@ public class NetworkMonitor extends StateMachine {
|
||||
mNetworkCapabilities = new NetworkCapabilities(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* ConnectivityService notifies NetworkMonitor that the user accepts partial connectivity and
|
||||
* NetworkMonitor should ignore the https probe.
|
||||
*/
|
||||
public void notifyAcceptPartialConnectivity() {
|
||||
sendMessage(EVENT_ACCEPT_PARTIAL_CONNECTIVITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the NetworkMonitor to reevaluate the network.
|
||||
*/
|
||||
@@ -636,6 +651,10 @@ public class NetworkMonitor extends StateMachine {
|
||||
case EVENT_DNS_NOTIFICATION:
|
||||
mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
|
||||
break;
|
||||
case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
|
||||
mUseHttps = false;
|
||||
transitionTo(mEvaluatingPrivateDnsState);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1058,6 +1077,11 @@ public class NetworkMonitor extends StateMachine {
|
||||
notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, probeResult.redirectUrl);
|
||||
mLastPortalProbeResult = probeResult;
|
||||
transitionTo(mCaptivePortalState);
|
||||
} else if (probeResult.isPartialConnectivity()) {
|
||||
logNetworkEvent(NetworkEvent.NETWORK_PARTIAL_CONNECTIVITY);
|
||||
notifyNetworkTested(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY,
|
||||
probeResult.redirectUrl);
|
||||
transitionTo(mWaitingForNextProbeState);
|
||||
} else {
|
||||
logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
|
||||
notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, probeResult.redirectUrl);
|
||||
@@ -1065,7 +1089,8 @@ public class NetworkMonitor extends StateMachine {
|
||||
}
|
||||
return HANDLED;
|
||||
case EVENT_DNS_NOTIFICATION:
|
||||
// Leave the event to DefaultState to record correct dns timestamp.
|
||||
case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
|
||||
// Leave the event to DefaultState.
|
||||
return NOT_HANDLED;
|
||||
default:
|
||||
// Wait for probe result and defer events to next state by default.
|
||||
@@ -1504,10 +1529,11 @@ public class NetworkMonitor extends StateMachine {
|
||||
// If we have new-style probe specs, use those. Otherwise, use the fallback URLs.
|
||||
final CaptivePortalProbeSpec probeSpec = nextFallbackSpec();
|
||||
final URL fallbackUrl = (probeSpec != null) ? probeSpec.getUrl() : nextFallbackUrl();
|
||||
CaptivePortalProbeResult fallbackProbeResult = null;
|
||||
if (fallbackUrl != null) {
|
||||
CaptivePortalProbeResult result = sendHttpProbe(fallbackUrl, PROBE_FALLBACK, probeSpec);
|
||||
if (result.isPortal()) {
|
||||
return result;
|
||||
fallbackProbeResult = sendHttpProbe(fallbackUrl, PROBE_FALLBACK, probeSpec);
|
||||
if (fallbackProbeResult.isPortal()) {
|
||||
return fallbackProbeResult;
|
||||
}
|
||||
}
|
||||
// Otherwise wait until http and https probes completes and use their results.
|
||||
@@ -1517,6 +1543,12 @@ public class NetworkMonitor extends StateMachine {
|
||||
return httpProbe.result();
|
||||
}
|
||||
httpsProbe.join();
|
||||
final boolean isHttpSuccessful =
|
||||
(httpProbe.result().isSuccessful()
|
||||
|| (fallbackProbeResult != null && fallbackProbeResult.isSuccessful()));
|
||||
if (httpsProbe.result().isFailed() && isHttpSuccessful) {
|
||||
return CaptivePortalProbeResult.PARTIAL;
|
||||
}
|
||||
return httpsProbe.result();
|
||||
} catch (InterruptedException e) {
|
||||
validationLog("Error: http or https probe wait interrupted!");
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.connectivity;
|
||||
|
||||
import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS;
|
||||
@@ -572,6 +573,34 @@ public class NetworkMonitorTest {
|
||||
stats.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreHttpsProbe() throws Exception {
|
||||
setSslException(mHttpsConnection);
|
||||
setStatus(mHttpConnection, 204);
|
||||
|
||||
final NetworkMonitor nm = makeMonitor();
|
||||
nm.notifyNetworkConnected();
|
||||
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
|
||||
.notifyNetworkTested(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY, null);
|
||||
|
||||
nm.notifyAcceptPartialConnectivity();
|
||||
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
|
||||
.notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsPartialConnectivity() throws IOException {
|
||||
setStatus(mHttpsConnection, 500);
|
||||
setStatus(mHttpConnection, 204);
|
||||
setStatus(mFallbackConnection, 500);
|
||||
assertPartialConnectivity(makeMonitor().isCaptivePortal());
|
||||
|
||||
setStatus(mHttpsConnection, 500);
|
||||
setStatus(mHttpConnection, 500);
|
||||
setStatus(mFallbackConnection, 204);
|
||||
assertPartialConnectivity(makeMonitor().isCaptivePortal());
|
||||
}
|
||||
|
||||
private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
|
||||
@@ -649,6 +678,10 @@ public class NetworkMonitorTest {
|
||||
assertFalse(result.isSuccessful());
|
||||
}
|
||||
|
||||
private void assertPartialConnectivity(CaptivePortalProbeResult result) {
|
||||
assertTrue(result.isPartialConnectivity());
|
||||
}
|
||||
|
||||
private void setSslException(HttpURLConnection connection) throws IOException {
|
||||
doThrow(new SSLHandshakeException("Invalid cert")).when(connection).getResponseCode();
|
||||
}
|
||||
|
||||
@@ -233,6 +233,8 @@ message SystemMessage {
|
||||
NOTE_NETWORK_SWITCH = 743;
|
||||
// Device logged-in captive portal network successfully
|
||||
NOTE_NETWORK_LOGGED_IN = 744;
|
||||
// A partial connectivity network was detected during network validation
|
||||
NOTE_NETWORK_PARTIAL_CONNECTIVITY = 745;
|
||||
|
||||
// Notify the user that their work profile has been deleted
|
||||
// Package: android
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.net.ConnectivityManager.TYPE_NONE;
|
||||
import static android.net.ConnectivityManager.TYPE_VPN;
|
||||
import static android.net.ConnectivityManager.getNetworkTypeName;
|
||||
import static android.net.ConnectivityManager.isNetworkTypeValid;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
|
||||
@@ -34,6 +35,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
|
||||
import static android.net.NetworkPolicyManager.RULE_NONE;
|
||||
@@ -488,6 +490,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
*/
|
||||
public static final int EVENT_TIMEOUT_NOTIFICATION = 44;
|
||||
|
||||
/**
|
||||
* Used to specify whether a network should be used even if connectivity is partial.
|
||||
* arg1 = whether to accept the network if its connectivity is partial (1 for true or 0 for
|
||||
* false)
|
||||
* arg2 = whether to remember this choice in the future (1 for true or 0 for false)
|
||||
* obj = network
|
||||
*/
|
||||
private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 45;
|
||||
|
||||
/**
|
||||
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
|
||||
* should be shown.
|
||||
@@ -2487,9 +2498,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
switch (msg.what) {
|
||||
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
|
||||
final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
|
||||
if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
|
||||
networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) ||
|
||||
networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
|
||||
if (networkCapabilities.hasConnectivityManagedCapability()) {
|
||||
Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
|
||||
}
|
||||
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
|
||||
@@ -2514,6 +2523,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
}
|
||||
nai.networkMisc.explicitlySelected = true;
|
||||
nai.networkMisc.acceptUnvalidated = msg.arg1 == 1;
|
||||
// Mark the network as temporarily accepting partial connectivity so that it
|
||||
// will be validated (and possibly become default) even if it only provides
|
||||
// partial internet access. Note that if user connects to partial connectivity
|
||||
// and choose "don't ask again", then wifi disconnected by some reasons(maybe
|
||||
// out of wifi coverage) and if the same wifi is available again, the device
|
||||
// will auto connect to this wifi even though the wifi has "no internet".
|
||||
// TODO: Evaluate using a separate setting in IpMemoryStore.
|
||||
nai.networkMisc.acceptPartialConnectivity = msg.arg1 == 1;
|
||||
break;
|
||||
}
|
||||
case NetworkAgent.EVENT_SOCKET_KEEPALIVE: {
|
||||
@@ -2531,6 +2548,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
|
||||
if (nai == null) break;
|
||||
|
||||
final boolean partialConnectivity =
|
||||
(msg.arg1 == NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY)
|
||||
// If user accepts partial connectivity network, NetworkMonitor
|
||||
// will skip https probing. It will make partial connectivity
|
||||
// network becomes valid. But user still need to know this
|
||||
// network is limited. So, it's needed to refer to
|
||||
// acceptPartialConnectivity to add
|
||||
// NET_CAPABILITY_PARTIAL_CONNECTIVITY into NetworkCapabilities
|
||||
// of this network. So that user can see "Limited connection"
|
||||
// in the settings.
|
||||
|| (nai.networkMisc.acceptPartialConnectivity
|
||||
&& nai.partialConnectivity);
|
||||
// Once a network is determined to have partial connectivity, it cannot
|
||||
// go back to full connectivity without a disconnect.
|
||||
final boolean partialConnectivityChange =
|
||||
(partialConnectivity && !nai.partialConnectivity);
|
||||
|
||||
final boolean valid = (msg.arg1 == NETWORK_TEST_RESULT_VALID);
|
||||
final boolean wasValidated = nai.lastValidated;
|
||||
final boolean wasDefault = isDefaultNetwork(nai);
|
||||
@@ -2539,6 +2573,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
nai.captivePortalLoginNotified = true;
|
||||
showNetworkNotification(nai, NotificationType.LOGGED_IN);
|
||||
}
|
||||
// If this network has just connected and partial connectivity has just been
|
||||
// detected, tell NetworkMonitor if the user accepted partial connectivity on a
|
||||
// previous connect.
|
||||
if ((msg.arg1 == NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY)
|
||||
&& nai.networkMisc.acceptPartialConnectivity) {
|
||||
try {
|
||||
nai.networkMonitor().notifyAcceptPartialConnectivity();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
|
||||
|
||||
@@ -2568,6 +2613,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
mNotifier.clearNotification(nai.network.netId,
|
||||
NotificationType.LOST_INTERNET);
|
||||
}
|
||||
} else if (partialConnectivityChange) {
|
||||
nai.partialConnectivity = partialConnectivity;
|
||||
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
|
||||
}
|
||||
updateInetCondition(nai);
|
||||
// Let the NetworkAgent know the state of its network
|
||||
@@ -2606,7 +2654,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
}
|
||||
if (!visible) {
|
||||
// Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other
|
||||
// notifications belong to the same network may be cleared unexpected.
|
||||
// notifications belong to the same network may be cleared unexpectedly.
|
||||
mNotifier.clearNotification(netId, NotificationType.SIGN_IN);
|
||||
mNotifier.clearNotification(netId, NotificationType.NETWORK_SWITCH);
|
||||
} else {
|
||||
@@ -3192,14 +3240,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
|
||||
@Override
|
||||
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
|
||||
enforceConnectivityInternalPermission();
|
||||
enforceNetworkStackSettingsOrSetup();
|
||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_ACCEPT_UNVALIDATED,
|
||||
encodeBool(accept), encodeBool(always), network));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) {
|
||||
enforceNetworkStackSettingsOrSetup();
|
||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY,
|
||||
encodeBool(accept), encodeBool(always), network));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAvoidUnvalidated(Network network) {
|
||||
enforceConnectivityInternalPermission();
|
||||
enforceNetworkStackSettingsOrSetup();
|
||||
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_AVOID_UNVALIDATED, network));
|
||||
}
|
||||
|
||||
@@ -3225,6 +3280,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
if (accept != nai.networkMisc.acceptUnvalidated) {
|
||||
int oldScore = nai.getCurrentScore();
|
||||
nai.networkMisc.acceptUnvalidated = accept;
|
||||
// If network becomes partial connectivity and user already accepted to use this
|
||||
// network, we should respect the user's option and don't need to popup the
|
||||
// PARTIAL_CONNECTIVITY notification to user again.
|
||||
nai.networkMisc.acceptPartialConnectivity = accept;
|
||||
rematchAllNetworksAndRequests(nai, oldScore);
|
||||
sendUpdatedScoreToFactories(nai);
|
||||
}
|
||||
@@ -3243,6 +3302,48 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
|
||||
}
|
||||
|
||||
private void handleSetAcceptPartialConnectivity(Network network, boolean accept,
|
||||
boolean always) {
|
||||
if (DBG) {
|
||||
log("handleSetAcceptPartialConnectivity network=" + network + " accept=" + accept
|
||||
+ " always=" + always);
|
||||
}
|
||||
|
||||
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
|
||||
if (nai == null) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (nai.lastValidated) {
|
||||
// The network validated while the dialog box was up. Take no action.
|
||||
return;
|
||||
}
|
||||
|
||||
if (accept != nai.networkMisc.acceptPartialConnectivity) {
|
||||
nai.networkMisc.acceptPartialConnectivity = accept;
|
||||
}
|
||||
|
||||
// TODO: Use the current design or save the user choice into IpMemoryStore.
|
||||
if (always) {
|
||||
nai.asyncChannel.sendMessage(
|
||||
NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept));
|
||||
}
|
||||
|
||||
if (!accept) {
|
||||
// Tell the NetworkAgent to not automatically reconnect to the network.
|
||||
nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
|
||||
// Tear down the network.
|
||||
teardownUnneededNetwork(nai);
|
||||
} else {
|
||||
try {
|
||||
nai.networkMonitor().notifyAcceptPartialConnectivity();
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSetAvoidUnvalidated(Network network) {
|
||||
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
|
||||
if (nai == null || nai.lastValidated) {
|
||||
@@ -3413,6 +3514,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
case LOST_INTERNET:
|
||||
action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION;
|
||||
break;
|
||||
case PARTIAL_CONNECTIVITY:
|
||||
action = ConnectivityManager.ACTION_PROMPT_PARTIAL_CONNECTIVITY;
|
||||
break;
|
||||
default:
|
||||
Slog.wtf(TAG, "Unknown notification type " + type);
|
||||
return;
|
||||
@@ -3435,22 +3539,36 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
if (VDBG || DDBG) log("handlePromptUnvalidated " + network);
|
||||
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
|
||||
|
||||
// Only prompt if the network is unvalidated and was explicitly selected by the user, and if
|
||||
// we haven't already been told to switch to it regardless of whether it validated or not.
|
||||
// Also don't prompt on captive portals because we're already prompting the user to sign in.
|
||||
if (nai == null || nai.everValidated || nai.everCaptivePortalDetected ||
|
||||
!nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
|
||||
// Only prompt if the network is unvalidated or network has partial internet connectivity
|
||||
// and was explicitly selected by the user, and if we haven't already been told to switch
|
||||
// to it regardless of whether it validated or not. Also don't prompt on captive portals
|
||||
// because we're already prompting the user to sign in.
|
||||
if (nai == null || nai.everValidated || nai.everCaptivePortalDetected
|
||||
|| !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated
|
||||
|| nai.networkMisc.acceptPartialConnectivity) {
|
||||
return;
|
||||
}
|
||||
showNetworkNotification(nai, NotificationType.NO_INTERNET);
|
||||
// TODO: Evaluate if it's needed to wait 8 seconds for triggering notification when
|
||||
// NetworkMonitor detects the network is partial connectivity. Need to change the design to
|
||||
// popup the notification immediately when the network is partial connectivity.
|
||||
if (nai.partialConnectivity) {
|
||||
// Treat PARTIAL_CONNECTIVITY as NO_INTERNET temporary until Settings has been updated.
|
||||
// TODO: Need to change back to PARTIAL_CONNECTIVITY when Settings part is merged.
|
||||
showNetworkNotification(nai, NotificationType.NO_INTERNET);
|
||||
} else {
|
||||
showNetworkNotification(nai, NotificationType.NO_INTERNET);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
|
||||
NetworkCapabilities nc = nai.networkCapabilities;
|
||||
if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
|
||||
|
||||
if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
|
||||
mMultinetworkPolicyTracker.shouldNotifyWifiUnvalidated()) {
|
||||
if (!nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mMultinetworkPolicyTracker.shouldNotifyWifiUnvalidated()) {
|
||||
showNetworkNotification(nai, NotificationType.LOST_INTERNET);
|
||||
}
|
||||
}
|
||||
@@ -3541,6 +3659,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
handleSetAcceptUnvalidated(network, toBool(msg.arg1), toBool(msg.arg2));
|
||||
break;
|
||||
}
|
||||
case EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY: {
|
||||
Network network = (Network) msg.obj;
|
||||
handleSetAcceptPartialConnectivity(network, toBool(msg.arg1),
|
||||
toBool(msg.arg2));
|
||||
break;
|
||||
}
|
||||
case EVENT_SET_AVOID_UNVALIDATED: {
|
||||
handleSetAvoidUnvalidated((Network) msg.obj);
|
||||
break;
|
||||
@@ -5465,6 +5589,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
} else {
|
||||
newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
|
||||
}
|
||||
if (nai.partialConnectivity) {
|
||||
newNc.addCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
|
||||
} else {
|
||||
newNc.removeCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
|
||||
}
|
||||
|
||||
return newNc;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
||||
// last detected.
|
||||
public boolean captivePortalLoginNotified;
|
||||
|
||||
// Set to true when partial connectivity was detected.
|
||||
public boolean partialConnectivity;
|
||||
|
||||
// Networks are lingered when they become unneeded as a result of their NetworkRequests being
|
||||
// satisfied by a higher-scoring network. so as to allow communication to wrap up before the
|
||||
// network is taken down. This usually only happens to the default network. Lingering ends with
|
||||
@@ -592,6 +595,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
||||
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
|
||||
}
|
||||
|
||||
// TODO: Print shorter members first and only print the boolean variable which value is true
|
||||
// to improve readability.
|
||||
public String toString() {
|
||||
return "NetworkAgentInfo{ ni{" + networkInfo + "} "
|
||||
+ "network{" + network + "} nethandle{" + network.getNetworkHandle() + "} "
|
||||
@@ -604,6 +609,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
||||
+ "everCaptivePortalDetected{" + everCaptivePortalDetected + "} "
|
||||
+ "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} "
|
||||
+ "captivePortalLoginNotified{" + captivePortalLoginNotified + "} "
|
||||
+ "partialConnectivity{" + partialConnectivity + "} "
|
||||
+ "acceptPartialConnectivity{" + networkMisc.acceptPartialConnectivity + "} "
|
||||
+ "clat{" + clatd + "} "
|
||||
+ "}";
|
||||
}
|
||||
|
||||
@@ -47,8 +47,9 @@ public class NetworkNotificationManager {
|
||||
LOST_INTERNET(SystemMessage.NOTE_NETWORK_LOST_INTERNET),
|
||||
NETWORK_SWITCH(SystemMessage.NOTE_NETWORK_SWITCH),
|
||||
NO_INTERNET(SystemMessage.NOTE_NETWORK_NO_INTERNET),
|
||||
SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN),
|
||||
LOGGED_IN(SystemMessage.NOTE_NETWORK_LOGGED_IN);
|
||||
LOGGED_IN(SystemMessage.NOTE_NETWORK_LOGGED_IN),
|
||||
PARTIAL_CONNECTIVITY(SystemMessage.NOTE_NETWORK_PARTIAL_CONNECTIVITY),
|
||||
SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN);
|
||||
|
||||
public final int eventId;
|
||||
|
||||
@@ -169,11 +170,18 @@ public class NetworkNotificationManager {
|
||||
CharSequence details;
|
||||
int icon = getIcon(transportType);
|
||||
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
|
||||
title = r.getString(R.string.wifi_no_internet, 0);
|
||||
title = r.getString(R.string.wifi_no_internet,
|
||||
WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
|
||||
details = r.getString(R.string.wifi_no_internet_detailed);
|
||||
} else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
|
||||
&& transportType == TRANSPORT_WIFI) {
|
||||
title = r.getString(R.string.network_partial_connectivity,
|
||||
WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
|
||||
details = r.getString(R.string.network_partial_connectivity_detailed);
|
||||
} else if (notifyType == NotificationType.LOST_INTERNET &&
|
||||
transportType == TRANSPORT_WIFI) {
|
||||
title = r.getString(R.string.wifi_no_internet, 0);
|
||||
title = r.getString(R.string.wifi_no_internet,
|
||||
WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
|
||||
details = r.getString(R.string.wifi_no_internet_detailed);
|
||||
} else if (notifyType == NotificationType.SIGN_IN) {
|
||||
switch (transportType) {
|
||||
@@ -316,6 +324,8 @@ public class NetworkNotificationManager {
|
||||
}
|
||||
switch (t) {
|
||||
case SIGN_IN:
|
||||
return 5;
|
||||
case PARTIAL_CONNECTIVITY:
|
||||
return 4;
|
||||
case NO_INTERNET:
|
||||
return 3;
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||
@@ -27,6 +28,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
|
||||
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.RESTRICTED_CAPABILITIES;
|
||||
@@ -334,6 +336,24 @@ public class NetworkCapabilitiesTest {
|
||||
assertTrue(request.satisfiedByNetworkCapabilities(network));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectivityManagedCapabilities() {
|
||||
NetworkCapabilities nc = new NetworkCapabilities();
|
||||
assertFalse(nc.hasConnectivityManagedCapability());
|
||||
// Check every single system managed capability.
|
||||
nc.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
|
||||
assertTrue(nc.hasConnectivityManagedCapability());
|
||||
nc.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
|
||||
nc.addCapability(NET_CAPABILITY_FOREGROUND);
|
||||
assertTrue(nc.hasConnectivityManagedCapability());
|
||||
nc.removeCapability(NET_CAPABILITY_FOREGROUND);
|
||||
nc.addCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
|
||||
assertTrue(nc.hasConnectivityManagedCapability());
|
||||
nc.removeCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
|
||||
nc.addCapability(NET_CAPABILITY_VALIDATED);
|
||||
assertTrue(nc.hasConnectivityManagedCapability());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualsNetCapabilities() {
|
||||
NetworkCapabilities nc1 = new NetworkCapabilities();
|
||||
|
||||
@@ -28,6 +28,7 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
|
||||
import static android.net.ConnectivityManager.TYPE_NONE;
|
||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
|
||||
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
|
||||
@@ -43,6 +44,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
|
||||
@@ -442,6 +444,11 @@ public class ConnectivityServiceTest {
|
||||
mNmValidationRedirectUrl = redirectUrl;
|
||||
}
|
||||
|
||||
void setNetworkPartial() {
|
||||
mNmValidationResult = NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
|
||||
mNmValidationRedirectUrl = null;
|
||||
}
|
||||
|
||||
MockNetworkAgent(int transport) {
|
||||
this(transport, new LinkProperties());
|
||||
}
|
||||
@@ -484,6 +491,7 @@ public class ConnectivityServiceTest {
|
||||
try {
|
||||
doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected();
|
||||
doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
|
||||
doAnswer(validateAnswer).when(mNetworkMonitor).notifyAcceptPartialConnectivity();
|
||||
} catch (RemoteException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
@@ -669,6 +677,11 @@ public class ConnectivityServiceTest {
|
||||
connect(false);
|
||||
}
|
||||
|
||||
public void connectWithPartialConnectivity() {
|
||||
setNetworkPartial();
|
||||
connect(false);
|
||||
}
|
||||
|
||||
public void suspend() {
|
||||
mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
|
||||
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
|
||||
@@ -2497,6 +2510,106 @@ public class ConnectivityServiceTest {
|
||||
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartialConnectivity() {
|
||||
// Register network callback.
|
||||
NetworkRequest request = new NetworkRequest.Builder()
|
||||
.clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
|
||||
.build();
|
||||
TestNetworkCallback callback = new TestNetworkCallback();
|
||||
mCm.registerNetworkCallback(request, callback);
|
||||
|
||||
// Bring up validated mobile data.
|
||||
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||
mCellNetworkAgent.connect(true);
|
||||
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
|
||||
|
||||
// Bring up wifi with partial connectivity.
|
||||
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||
mWiFiNetworkAgent.connectWithPartialConnectivity();
|
||||
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
|
||||
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
|
||||
|
||||
// Mobile data should be the default network.
|
||||
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
callback.assertNoCallback();
|
||||
|
||||
// If the user chooses yes to use this partial connectivity wifi, switch the default
|
||||
// network to wifi and check if wifi becomes valid or not.
|
||||
mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
|
||||
false /* always */);
|
||||
// With https probe disabled, NetworkMonitor should pass the network validation with http
|
||||
// probe.
|
||||
mWiFiNetworkAgent.setNetworkValid();
|
||||
waitForIdle();
|
||||
try {
|
||||
verify(mWiFiNetworkAgent.mNetworkMonitor,
|
||||
timeout(TIMEOUT_MS).times(1)).notifyAcceptPartialConnectivity();
|
||||
} catch (RemoteException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
|
||||
NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED,
|
||||
mWiFiNetworkAgent);
|
||||
assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
|
||||
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
|
||||
// Disconnect and reconnect wifi with partial connectivity again.
|
||||
mWiFiNetworkAgent.disconnect();
|
||||
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
|
||||
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||
mWiFiNetworkAgent.connectWithPartialConnectivity();
|
||||
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
|
||||
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
|
||||
|
||||
// Mobile data should be the default network.
|
||||
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
|
||||
// If the user chooses no, disconnect wifi immediately.
|
||||
mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), false/* accept */,
|
||||
false /* always */);
|
||||
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
|
||||
|
||||
// If user accepted partial connectivity before, and device reconnects to that network
|
||||
// again, but now the network has full connectivity. The network shouldn't contain
|
||||
// NET_CAPABILITY_PARTIAL_CONNECTIVITY.
|
||||
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||
// acceptUnvalidated is also used as setting for accepting partial networks.
|
||||
mWiFiNetworkAgent.explicitlySelected(true /* acceptUnvalidated */);
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
|
||||
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
|
||||
nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
|
||||
assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
|
||||
// Wifi should be the default network.
|
||||
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
mWiFiNetworkAgent.disconnect();
|
||||
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
|
||||
|
||||
// If user accepted partial connectivity before, and now the device reconnects to the
|
||||
// partial connectivity network. The network should be valid and contain
|
||||
// NET_CAPABILITY_PARTIAL_CONNECTIVITY.
|
||||
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||
mWiFiNetworkAgent.explicitlySelected(true /* acceptUnvalidated */);
|
||||
mWiFiNetworkAgent.connectWithPartialConnectivity();
|
||||
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
|
||||
// TODO: If the user accepted partial connectivity, we shouldn't switch to wifi until
|
||||
// NetworkMonitor detects partial connectivity
|
||||
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
mWiFiNetworkAgent.setNetworkValid();
|
||||
waitForIdle();
|
||||
try {
|
||||
verify(mWiFiNetworkAgent.mNetworkMonitor,
|
||||
timeout(TIMEOUT_MS).times(1)).notifyAcceptPartialConnectivity();
|
||||
} catch (RemoteException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
|
||||
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
|
||||
// Wifi should be the default network.
|
||||
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaptivePortal() {
|
||||
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
|
||||
|
||||
Reference in New Issue
Block a user