Flyview Flyview - 6 months ago 55
Android Question

Get WiFi captive portal info

Is there a way to access Android's broadcast that the WiFi connection is currently a captive portal (requires web login)? Android seems to do have this built in. If not a broadcast receiver, is there a way to check for the result of the captive portal check? I believe it's using this class, which is hidden from the API:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.L_preview/android/net/CaptivePortalTracker.java

Prior to 4.2, it was probably using:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.2_r1/android/net/wifi/WifiWatchdogStateMachine.java

Background:

I had been using my own method to detect whether WiFi likely required a login. I would wait for a WiFi connected state, then ping a site and make sure there was a response. This seemed to work great in most cases. Another strategy is to do a HttpRequest and check for a redirect or the response body you receive back, similar to Android's strategy in the classes listed above.

However, new to Lollipop is that the mobile data connection is used when WiFi does not have connectivity. This means my ping method will still return results, and that a redirect would not happen, as the request would be routed over the mobile data.

Is there a way to get Android's current status of a WiFi captive portal? If not, can we make sure a request goes over WiFi even when there's no connectivity as seen by Android?

Answer

You'd have to use the new ConnectivityManager.setProcessDefaultNetwork API to force your app to communicate over the captive portal. See https://github.com/pawitp/muwifi-autologin/commit/f045fe36f1fd98a106ea652e2d56f7ddfc871760 for an example.

Complete code added:

final ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
for (Network net : cm.getAllNetworks()) {
    if (cm.getNetworkInfo(net).getType() == ConnectivityManager.TYPE_WIFI) {
        Utils.logDebug(TAG, "Seting process network to " + net);  
        /*Since API 23 ConnectivityManager.setProcessDefaultNetwork(net); 
        is deprecated, use: */
        cm.bindProcessToNetwork(net);
    }
}