CaptivePortalTracker.java revision b8aad91f059527e04abaf8a83ed1ce6b5f09c55d
1da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff/* 2da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * Copyright (C) 2012 The Android Open Source Project 3da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * 4da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License"); 5da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * you may not use this file except in compliance with the License. 6da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * You may obtain a copy of the License at 7da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * 8da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * http://www.apache.org/licenses/LICENSE-2.0 9da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * 10da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * Unless required by applicable law or agreed to in writing, software 11da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS, 12da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * See the License for the specific language governing permissions and 14da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * limitations under the License. 15da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff */ 16da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 17da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffpackage android.net; 18da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 199538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriffimport android.app.Activity; 20da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.app.Notification; 21da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.app.NotificationManager; 22da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.app.PendingIntent; 23da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.BroadcastReceiver; 24da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.Context; 25da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.Intent; 26da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.IntentFilter; 27da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.res.Resources; 28da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.net.ConnectivityManager; 29da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.net.IConnectivityManager; 309538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriffimport android.os.UserHandle; 31da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.os.Message; 32da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.os.RemoteException; 33da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.provider.Settings; 34b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriffimport android.telephony.TelephonyManager; 35da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.util.Log; 36da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 379538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriffimport com.android.internal.util.State; 389538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriffimport com.android.internal.util.StateMachine; 399538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 40da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.io.IOException; 41da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.HttpURLConnection; 42da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.InetAddress; 43da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.Inet4Address; 44da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.URL; 45da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.UnknownHostException; 46da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 47da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport com.android.internal.R; 48da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 49da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff/** 509538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff * This class allows captive portal detection on a network. 51da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * @hide 52da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff */ 539538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriffpublic class CaptivePortalTracker extends StateMachine { 549538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final boolean DBG = false; 55da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static final String TAG = "CaptivePortalTracker"; 56da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 57da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static final String DEFAULT_SERVER = "clients3.google.com"; 58da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; 59da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 60da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static final int SOCKET_TIMEOUT_MS = 10000; 61da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 62da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private String mServer; 63da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private String mUrl; 64da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private boolean mNotificationShown = false; 65da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private boolean mIsCaptivePortalCheckEnabled = false; 66da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private IConnectivityManager mConnService; 67b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff private TelephonyManager mTelephonyManager; 68da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private Context mContext; 69da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private NetworkInfo mNetworkInfo; 70da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 719538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final int CMD_DETECT_PORTAL = 0; 729538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final int CMD_CONNECTIVITY_CHANGE = 1; 739538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final int CMD_DELAYED_CAPTIVE_CHECK = 2; 74da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 759538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff /* This delay happens every time before we do a captive check on a network */ 769538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final int DELAYED_CHECK_INTERVAL_MS = 10000; 779538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private int mDelayedCheckToken = 0; 789538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 799538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private State mDefaultState = new DefaultState(); 809538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private State mNoActiveNetworkState = new NoActiveNetworkState(); 819538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private State mActiveNetworkState = new ActiveNetworkState(); 829538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private State mDelayedCaptiveCheckState = new DelayedCaptiveCheckState(); 839538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 849538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private CaptivePortalTracker(Context context, IConnectivityManager cs) { 859538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff super(TAG); 86da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 87da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mContext = context; 88da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mConnService = cs; 89b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 90da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 91da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff IntentFilter filter = new IntentFilter(); 92da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 93da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mContext.registerReceiver(mReceiver, filter); 94da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 95625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey mServer = Settings.Global.getString(mContext.getContentResolver(), 96625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey Settings.Global.CAPTIVE_PORTAL_SERVER); 97da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (mServer == null) mServer = DEFAULT_SERVER; 98da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 99625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(), 100625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1; 1019538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 1029538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff addState(mDefaultState); 1039538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff addState(mNoActiveNetworkState, mDefaultState); 1049538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff addState(mActiveNetworkState, mDefaultState); 1059538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff addState(mDelayedCaptiveCheckState, mActiveNetworkState); 1069538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff setInitialState(mNoActiveNetworkState); 107da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 108da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 109da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 110da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff @Override 111da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff public void onReceive(Context context, Intent intent) { 112da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff String action = intent.getAction(); 1139538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 114da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff NetworkInfo info = intent.getParcelableExtra( 115da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff ConnectivityManager.EXTRA_NETWORK_INFO); 1169538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff sendMessage(obtainMessage(CMD_CONNECTIVITY_CHANGE, info)); 117da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 118da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 119da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff }; 120da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 1219538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public static CaptivePortalTracker makeCaptivePortalTracker(Context context, 122da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff IConnectivityManager cs) { 1239538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff CaptivePortalTracker captivePortal = new CaptivePortalTracker(context, cs); 1249538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff captivePortal.start(); 125da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return captivePortal; 126da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 127da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 1289538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public void detectCaptivePortal(NetworkInfo info) { 1299538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff sendMessage(obtainMessage(CMD_DETECT_PORTAL, info)); 1309538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 1319538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 1329538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private class DefaultState extends State { 1339538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 1349538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public void enter() { 1359538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log(getName() + "\n"); 136da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 137da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 138da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff @Override 1399538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public boolean processMessage(Message message) { 1409538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log(getName() + message.toString() + "\n"); 1419538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff switch (message.what) { 1429538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_DETECT_PORTAL: 1439538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff NetworkInfo info = (NetworkInfo) message.obj; 1449538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff // Checking on a secondary connection is not supported 1459538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff // yet 1469538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff notifyPortalCheckComplete(info); 147da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff break; 1489538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_CONNECTIVITY_CHANGE: 1499538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_DELAYED_CAPTIVE_CHECK: 1509538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff break; 1519538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff default: 1529538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff loge("Ignoring " + message); 1539538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff break; 1549538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 1559538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return HANDLED; 1569538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 1579538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 158da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 1599538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private class NoActiveNetworkState extends State { 1609538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 1619538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public void enter() { 1629538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log(getName() + "\n"); 1639538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff mNetworkInfo = null; 1649538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff /* Clear any previous notification */ 1659538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff setNotificationVisible(false); 1669538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 167da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 1689538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 1699538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public boolean processMessage(Message message) { 1709538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log(getName() + message.toString() + "\n"); 1719538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff InetAddress server; 1729538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff NetworkInfo info; 1739538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff switch (message.what) { 1749538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_CONNECTIVITY_CHANGE: 1759538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff info = (NetworkInfo) message.obj; 1769538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (info.isConnected() && isActiveNetwork(info)) { 1779538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff mNetworkInfo = info; 1789538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff transitionTo(mDelayedCaptiveCheckState); 179da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 180da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff break; 181da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff default: 1829538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return NOT_HANDLED; 183da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 1849538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return HANDLED; 1859538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 1869538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 1879538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 1889538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private class ActiveNetworkState extends State { 1899538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 1909538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public void enter() { 1919538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log(getName() + "\n"); 192da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 193da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 1949538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 1959538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public boolean processMessage(Message message) { 1969538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff NetworkInfo info; 1979538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff switch (message.what) { 1989538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_CONNECTIVITY_CHANGE: 1999538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff info = (NetworkInfo) message.obj; 2009538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (!info.isConnected() 2019538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff && info.getType() == mNetworkInfo.getType()) { 2029538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log("Disconnected from active network " + info); 2039538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff transitionTo(mNoActiveNetworkState); 2049538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } else if (info.getType() != mNetworkInfo.getType() && 2059538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff info.isConnected() && 2069538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff isActiveNetwork(info)) { 2079538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log("Active network switched " + info); 2089538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff deferMessage(message); 2099538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff transitionTo(mNoActiveNetworkState); 2109538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2119538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff break; 2129538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff default: 2139538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return NOT_HANDLED; 2149538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2159538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return HANDLED; 216da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 217da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 218da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 2199538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 2209538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 2219538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private class DelayedCaptiveCheckState extends State { 2229538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 2239538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public void enter() { 2249538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log(getName() + "\n"); 2259538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff sendMessageDelayed(obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, 2269538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff ++mDelayedCheckToken, 0), DELAYED_CHECK_INTERVAL_MS); 2279538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2289538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 2299538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 2309538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public boolean processMessage(Message message) { 2319538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log(getName() + message.toString() + "\n"); 2329538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff switch (message.what) { 2339538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_DELAYED_CAPTIVE_CHECK: 2349538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (message.arg1 == mDelayedCheckToken) { 2359538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff InetAddress server = lookupHost(mServer); 2369538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (server != null) { 2379538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (isCaptivePortal(server)) { 2389538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log("Captive network " + mNetworkInfo); 2399538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff setNotificationVisible(true); 2409538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2419538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2429538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log("Not captive network " + mNetworkInfo); 2439538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff transitionTo(mActiveNetworkState); 2449538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2459538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff break; 2469538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff default: 2479538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return NOT_HANDLED; 2489538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2499538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return HANDLED; 2509538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 251da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 252da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 2539538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private void notifyPortalCheckComplete(NetworkInfo info) { 2549538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (info == null) { 2559538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff loge("notifyPortalCheckComplete on null"); 2569538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return; 2579538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 258da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff try { 2599538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff mConnService.captivePortalCheckComplete(info); 260da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } catch(RemoteException e) { 261da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff e.printStackTrace(); 262da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 263da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 264da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 2659538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private boolean isActiveNetwork(NetworkInfo info) { 266da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff try { 2679538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff NetworkInfo active = mConnService.getActiveNetworkInfo(); 2689538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (active != null && active.getType() == info.getType()) { 2699538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return true; 2709538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 271da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } catch (RemoteException e) { 272da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff e.printStackTrace(); 273da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 2749538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return false; 275da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 276da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 277da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff /** 278da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * Do a URL fetch on a known server to see if we get the data we expect 279da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff */ 280da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private boolean isCaptivePortal(InetAddress server) { 281da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff HttpURLConnection urlConnection = null; 282da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (!mIsCaptivePortalCheckEnabled) return false; 283da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 284da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mUrl = "http://" + server.getHostAddress() + "/generate_204"; 2859538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log("Checking " + mUrl); 286da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff try { 287da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff URL url = new URL(mUrl); 288da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection = (HttpURLConnection) url.openConnection(); 289da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.setInstanceFollowRedirects(false); 290da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); 291da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); 292da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.setUseCaches(false); 293da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.getInputStream(); 294da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff // we got a valid response, but not from the real google 295da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return urlConnection.getResponseCode() != 204; 296da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } catch (IOException e) { 297da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (DBG) log("Probably not a portal: exception " + e); 298da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return false; 299da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } finally { 300da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (urlConnection != null) { 301da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.disconnect(); 302da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 303da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 304da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 305da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 306da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private InetAddress lookupHost(String hostname) { 307da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff InetAddress inetAddress[]; 308da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff try { 309da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff inetAddress = InetAddress.getAllByName(hostname); 310da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } catch (UnknownHostException e) { 311da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return null; 312da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 313da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 314da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff for (InetAddress a : inetAddress) { 315da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (a instanceof Inet4Address) return a; 316da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 317da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return null; 318da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 319da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 320da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private void setNotificationVisible(boolean visible) { 321da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff // if it should be hidden and it is already hidden, then noop 322da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (!visible && !mNotificationShown) { 323da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return; 324da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 325da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 326da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff Resources r = Resources.getSystem(); 327da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff NotificationManager notificationManager = (NotificationManager) mContext 328da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff .getSystemService(Context.NOTIFICATION_SERVICE); 329da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 330da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (visible) { 3319538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff CharSequence title; 332b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff CharSequence details; 333b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff switch (mNetworkInfo.getType()) { 334b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff case ConnectivityManager.TYPE_WIFI: 335b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff title = r.getString(R.string.wifi_available_sign_in, 0); 336b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff details = r.getString(R.string.network_available_sign_in_detailed, 337b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff mNetworkInfo.getExtraInfo()); 338b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff break; 339b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff case ConnectivityManager.TYPE_MOBILE: 340b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff title = r.getString(R.string.network_available_sign_in, 0); 341b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff // TODO: Change this to pull from NetworkInfo once a printable 342b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff // name has been added to it 343b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff details = mTelephonyManager.getNetworkOperatorName(); 344b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff break; 345b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff default: 346b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff title = r.getString(R.string.network_available_sign_in, 0); 347b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff details = r.getString(R.string.network_available_sign_in_detailed, 348b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff mNetworkInfo.getExtraInfo()); 349b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff break; 3509538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 351da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 352da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff Notification notification = new Notification(); 353da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff notification.when = 0; 354da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff notification.icon = com.android.internal.R.drawable.stat_notify_wifi_in_range; 355da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff notification.flags = Notification.FLAG_AUTO_CANCEL; 3569538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl)); 3579538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | 3589538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff Intent.FLAG_ACTIVITY_NEW_TASK); 3599538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); 360da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff notification.tickerText = title; 361da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); 362da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 363da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff notificationManager.notify(NOTIFICATION_ID, 1, notification); 364da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } else { 365da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff notificationManager.cancel(NOTIFICATION_ID, 1); 366da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 367da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mNotificationShown = visible; 368da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 369da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 370da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static void log(String s) { 371da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff Log.d(TAG, s); 372da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 373da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 374da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static void loge(String s) { 375da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff Log.e(TAG, s); 376da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 377da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 378da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff} 379