From: Lorenzo Colitti Date: Thu, 27 Apr 2017 05:30:21 +0000 (+0900) Subject: Add a method to start the captive portal login app. X-Git-Tag: android-x86-9.0-r1~1029^2^2~8^2~110^2~103^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=2965d33afc7fd68300b99a53a3f65dab10b5e24e;p=android-x86%2Fframeworks-base.git Add a method to start the captive portal login app. Bug: 36203355 Bug: 36656914 Test: ConnectivityServiceTest (including new test) passes Change-Id: Ide82858af67024623560ab79beea27c201b63447 Merged-In: I82a9a9a8da47870ba3f1bbef5941b37e970c844f (cherry picked from commit 4734cdbbc38752765376aedb0d5208463674535e) --- diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 234bef7483aa..54286d1e9c79 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -3468,6 +3469,22 @@ public class ConnectivityManager { } /** + * Requests that the system open the captive portal app on the specified network. + * + * @param network The network to log into. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) + public void startCaptivePortalApp(Network network) { + try { + mService.startCaptivePortalApp(network); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * It is acceptable to briefly use multipath data to provide seamless connectivity for * time-sensitive user-facing operations when the system default network is temporarily * unresponsive. The amount of data should be limited (less than one megabyte), and the diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 63a1f0513e20..27729dcce779 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -161,6 +161,7 @@ interface IConnectivityManager void setAcceptUnvalidated(in Network network, boolean accept, boolean always); void setAvoidUnvalidated(in Network network); + void startCaptivePortalApp(in Network network); int getMultipathPreference(in Network Network); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 47026d6815f4..522a841e1023 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2761,6 +2761,17 @@ public class ConnectivityService extends IConnectivityManager.Stub PROMPT_UNVALIDATED_DELAY_MS); } + @Override + public void startCaptivePortalApp(Network network) { + enforceConnectivityInternalPermission(); + mHandler.post(() -> { + NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai == null) return; + if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return; + nai.networkMonitor.sendMessage(NetworkMonitor.CMD_LAUNCH_CAPTIVE_PORTAL_APP); + }); + } + public boolean avoidBadWifi() { return mMultinetworkPolicyTracker.getAvoidBadWifi(); } diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 4dcf4251abad..09b30a9bdb7d 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -197,11 +197,13 @@ public class NetworkMonitor extends StateMachine { public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 10; /** - * Message to self indicating sign-in app should be launched. + * Message indicating sign-in app should be launched. * Sent by mLaunchCaptivePortalAppBroadcastReceiver when the - * user touches the sign in notification. + * user touches the sign in notification, or sent by + * ConnectivityService when the user touches the "sign into + * network" button in the wifi access point detail page. */ - private static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = BASE + 11; + public static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = BASE + 11; /** * Retest network to see if captive portal is still in place. diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 3c0b8aa7c59d..369b8a04cf7b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -39,6 +39,7 @@ import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; +import android.net.CaptivePortal; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.PacketKeepalive; @@ -78,6 +79,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; import android.test.AndroidTestCase; import android.test.mock.MockContentResolver; @@ -121,7 +123,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { private static final int TIMEOUT_MS = 500; private static final int TEST_LINGER_DELAY_MS = 120; - private BroadcastInterceptingContext mServiceContext; + private MockContext mServiceContext; private WrappedConnectivityService mService; private WrappedConnectivityManager mCm; private MockNetworkAgent mWiFiNetworkAgent; @@ -152,6 +154,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { private final MockContentResolver mContentResolver; @Spy private Resources mResources; + private final LinkedBlockingQueue mStartedActivities = new LinkedBlockingQueue<>(); MockContext(Context base) { super(base); @@ -169,6 +172,27 @@ public class ConnectivityServiceTest extends AndroidTestCase { } @Override + public void startActivityAsUser(Intent intent, UserHandle handle) { + mStartedActivities.offer(intent); + } + + public Intent expectStartActivityIntent(int timeoutMs) { + Intent intent = null; + try { + intent = mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) {} + assertNotNull("Did not receive sign-in intent after " + timeoutMs + "ms", intent); + return intent; + } + + public void expectNoStartActivityIntent(int timeoutMs) { + try { + assertNull("Received unexpected Intent to start activity", + mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) {} + } + + @Override public Object getSystemService(String name) { if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm; if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class); @@ -1827,6 +1851,52 @@ public class ConnectivityServiceTest extends AndroidTestCase { } @SmallTest + public void testCaptivePortalApp() { + final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); + final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build(); + mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback); + + final TestNetworkCallback validatedCallback = new TestNetworkCallback(); + final NetworkRequest validatedRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_VALIDATED).build(); + mCm.registerNetworkCallback(validatedRequest, validatedCallback); + + // Bring up wifi. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + validatedCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent); + Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); + + // Check that calling startCaptivePortalApp does nothing. + final int fastTimeoutMs = 100; + mCm.startCaptivePortalApp(wifiNetwork); + mServiceContext.expectNoStartActivityIntent(fastTimeoutMs); + + // Turn into a captive portal. + mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 302; + mCm.reportNetworkConnectivity(wifiNetwork, false); + captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + + // Check that startCaptivePortalApp sends the expected intent. + mCm.startCaptivePortalApp(wifiNetwork); + Intent intent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS); + assertEquals(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN, intent.getAction()); + assertEquals(wifiNetwork, intent.getExtra(ConnectivityManager.EXTRA_NETWORK)); + + // Have the app report that the captive portal is dismissed, and check that we revalidate. + mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204; + CaptivePortal c = (CaptivePortal) intent.getExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL); + c.reportCaptivePortalDismissed(); + validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent); + captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + + mCm.unregisterNetworkCallback(validatedCallback); + mCm.unregisterNetworkCallback(captivePortalCallback); + } + + @SmallTest public void testAvoidOrIgnoreCaptivePortals() { final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()