diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java index 67dacb88f7..ba7df7ff9b 100644 --- a/framework/src/android/net/ConnectivitySettingsManager.java +++ b/framework/src/android/net/ConnectivitySettingsManager.java @@ -176,7 +176,9 @@ public class ConnectivitySettingsManager { /** * When detecting a captive portal, immediately disconnect from the - * network and do not reconnect to that network in the future. + * network and do not reconnect to that network in the future; except + * on Wear platform companion proxy networks (transport BLUETOOTH) + * will stay behind captive portal. */ public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 3ae3e2d5c3..6fc63df9b2 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -4405,7 +4405,7 @@ public class ConnectivityService extends IConnectivityManager.Stub updateCapabilitiesForNetwork(nai); } else if (portalChanged) { if (portal && ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID - == getCaptivePortalMode()) { + == getCaptivePortalMode(nai)) { if (DBG) log("Avoiding captive portal network: " + nai.toShortString()); nai.onPreventAutomaticReconnect(); teardownUnneededNetwork(nai); @@ -4441,7 +4441,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private int getCaptivePortalMode() { + private int getCaptivePortalMode(@NonNull NetworkAgentInfo nai) { + if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) && + mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH)) { + // Do not avoid captive portal when network is wear proxy. + return ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT; + } + return Settings.Global.getInt(mContext.getContentResolver(), ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT); diff --git a/tests/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/integration/util/com/android/server/NetworkAgentWrapper.java index edd201d11c..ec09f9ea4e 100644 --- a/tests/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/integration/util/com/android/server/NetworkAgentWrapper.java @@ -19,6 +19,7 @@ package com.android.server; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.NetworkCapabilities.TRANSPORT_TEST; @@ -123,6 +124,10 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); mNetworkCapabilities.addTransportType(transport); switch (transport) { + case TRANSPORT_BLUETOOTH: + // Score for Wear companion proxy network; not BLUETOOTH tethering. + mScore = new NetworkScore.Builder().setLegacyInt(100).build(); + break; case TRANSPORT_ETHERNET: mScore = new NetworkScore.Builder().setLegacyInt(70).build(); break; diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index c8cbce1ef7..83e5c6700b 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -128,6 +128,7 @@ 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_BLUETOOTH; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.NetworkCapabilities.TRANSPORT_TEST; @@ -4870,6 +4871,34 @@ public class ConnectivityServiceTest { assertNoCallbacks(captivePortalCallback, validatedCallback); } + @Test + public void testNoAvoidCaptivePortalOnWearProxy() throws Exception { + // Bring up a BLUETOOTH network which is companion proxy on wear + // then set captive portal. + mockHasSystemFeature(PackageManager.FEATURE_WATCH, true); + setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID); + TestNetworkAgentWrapper btAgent = new TestNetworkAgentWrapper(TRANSPORT_BLUETOOTH); + final String firstRedirectUrl = "http://example.com/firstPath"; + + btAgent.connectWithCaptivePortal(firstRedirectUrl, false /* privateDnsProbeSent */); + btAgent.assertNotDisconnected(TIMEOUT_MS); + } + + @Test + public void testAvoidCaptivePortalOnBluetooth() throws Exception { + // When not on Wear, BLUETOOTH is just regular network, + // then set captive portal. + mockHasSystemFeature(PackageManager.FEATURE_WATCH, false); + setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID); + TestNetworkAgentWrapper btAgent = new TestNetworkAgentWrapper(TRANSPORT_BLUETOOTH); + final String firstRedirectUrl = "http://example.com/firstPath"; + + btAgent.connectWithCaptivePortal(firstRedirectUrl, false /* privateDnsProbeSent */); + + btAgent.expectDisconnected(); + btAgent.expectPreventReconnectReceived(); + } + @Test public void testCaptivePortalApi() throws Exception { mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);