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 500dbae1b5)
This commit is contained in:
Lorenzo Colitti
2017-04-27 14:30:21 +09:00
committed by Hugo Benichi
parent d44389ec64
commit de1e515306
4 changed files with 100 additions and 1 deletions

View File

@@ -17,6 +17,7 @@ package android.net;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant; import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi; import android.annotation.SystemApi;
@@ -3467,6 +3468,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 * 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 * time-sensitive user-facing operations when the system default network is temporarily

View File

@@ -161,6 +161,7 @@ interface IConnectivityManager
void setAcceptUnvalidated(in Network network, boolean accept, boolean always); void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
void setAvoidUnvalidated(in Network network); void setAvoidUnvalidated(in Network network);
void startCaptivePortalApp(in Network network);
int getMultipathPreference(in Network Network); int getMultipathPreference(in Network Network);

View File

@@ -2761,6 +2761,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
PROMPT_UNVALIDATED_DELAY_MS); 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() { public boolean avoidBadWifi() {
return mMultinetworkPolicyTracker.getAvoidBadWifi(); return mMultinetworkPolicyTracker.getAvoidBadWifi();
} }

View File

@@ -39,6 +39,7 @@ import android.content.ContextWrapper;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.net.CaptivePortal;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepalive;
@@ -78,6 +79,7 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.Process; import android.os.Process;
import android.os.SystemClock; import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import android.test.mock.MockContentResolver; 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 TIMEOUT_MS = 500;
private static final int TEST_LINGER_DELAY_MS = 120; private static final int TEST_LINGER_DELAY_MS = 120;
private BroadcastInterceptingContext mServiceContext; private MockContext mServiceContext;
private WrappedConnectivityService mService; private WrappedConnectivityService mService;
private WrappedConnectivityManager mCm; private WrappedConnectivityManager mCm;
private MockNetworkAgent mWiFiNetworkAgent; private MockNetworkAgent mWiFiNetworkAgent;
@@ -152,6 +154,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
private final MockContentResolver mContentResolver; private final MockContentResolver mContentResolver;
@Spy private Resources mResources; @Spy private Resources mResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
MockContext(Context base) { MockContext(Context base) {
super(base); super(base);
@@ -168,6 +171,27 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
} }
@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 @Override
public Object getSystemService(String name) { public Object getSystemService(String name) {
if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm; if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
@@ -1826,6 +1850,52 @@ public class ConnectivityServiceTest extends AndroidTestCase {
validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
} }
@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 @SmallTest
public void testAvoidOrIgnoreCaptivePortals() { public void testAvoidOrIgnoreCaptivePortals() {
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();