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 19da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.BroadcastReceiver; 20da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.Context; 21da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.Intent; 22da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.content.IntentFilter; 23108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brennerimport android.database.ContentObserver; 24da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.net.ConnectivityManager; 25da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.net.IConnectivityManager; 261ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.net.wifi.WifiInfo; 271ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.net.wifi.WifiManager; 28108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brennerimport android.os.Handler; 29da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.os.Message; 30da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.os.RemoteException; 311ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.os.SystemClock; 32da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport android.provider.Settings; 331ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellIdentityCdma; 341ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellIdentityGsm; 351ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellIdentityLte; 361ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellIdentityWcdma; 371ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellInfo; 381ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellInfoCdma; 391ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellInfoGsm; 401ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellInfoLte; 411ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport android.telephony.CellInfoWcdma; 42b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriffimport android.telephony.TelephonyManager; 43da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 449538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriffimport com.android.internal.util.State; 459538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriffimport com.android.internal.util.StateMachine; 469538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 47da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.io.IOException; 48da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.HttpURLConnection; 49da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.InetAddress; 50da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.Inet4Address; 51bf34122a96ef3d02e9b7935e07eb4f9b04034828Wink Savilleimport java.net.SocketTimeoutException; 52da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.URL; 53da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriffimport java.net.UnknownHostException; 541ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammeeimport java.util.List; 55da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 56da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff/** 579538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff * This class allows captive portal detection on a network. 58da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff * @hide 59da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff */ 609538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriffpublic class CaptivePortalTracker extends StateMachine { 61bf34122a96ef3d02e9b7935e07eb4f9b04034828Wink Saville private static final boolean DBG = true; 62da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static final String TAG = "CaptivePortalTracker"; 63da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 64da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static final String DEFAULT_SERVER = "clients3.google.com"; 65da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 66da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private static final int SOCKET_TIMEOUT_MS = 10000; 67da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 681ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String ACTION_NETWORK_CONDITIONS_MEASURED = 691ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee "android.net.conn.NETWORK_CONDITIONS_MEASURED"; 701ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; 711ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_NETWORK_TYPE = "extra_network_type"; 721ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received"; 731ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal"; 741ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_CELL_ID = "extra_cellid"; 751ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_SSID = "extra_ssid"; 761ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_BSSID = "extra_bssid"; 771ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee /** real time since boot */ 781ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms"; 791ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms"; 801ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 811ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = 821ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee "android.permission.ACCESS_NETWORK_CONDITIONS"; 831ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 84da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private String mServer; 85da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private String mUrl; 86da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private boolean mIsCaptivePortalCheckEnabled = false; 87da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private IConnectivityManager mConnService; 88b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff private TelephonyManager mTelephonyManager; 891ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee private WifiManager mWifiManager; 90da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private Context mContext; 91da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private NetworkInfo mNetworkInfo; 92da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 939538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final int CMD_DETECT_PORTAL = 0; 949538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final int CMD_CONNECTIVITY_CHANGE = 1; 959538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final int CMD_DELAYED_CAPTIVE_CHECK = 2; 96da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 979538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff /* This delay happens every time before we do a captive check on a network */ 989538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private static final int DELAYED_CHECK_INTERVAL_MS = 10000; 999538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private int mDelayedCheckToken = 0; 1009538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 1019538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private State mDefaultState = new DefaultState(); 1029538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private State mNoActiveNetworkState = new NoActiveNetworkState(); 1039538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private State mActiveNetworkState = new ActiveNetworkState(); 1049538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private State mDelayedCaptiveCheckState = new DelayedCaptiveCheckState(); 1059538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 106108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner private static final String SETUP_WIZARD_PACKAGE = "com.google.android.setupwizard"; 107108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner private boolean mDeviceProvisioned = false; 108108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner private ProvisioningObserver mProvisioningObserver; 109108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner 1109538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private CaptivePortalTracker(Context context, IConnectivityManager cs) { 1119538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff super(TAG); 112da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 113da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mContext = context; 114da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mConnService = cs; 115b8aad91f059527e04abaf8a83ed1ce6b5f09c55dIrfan Sheriff mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 1161ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 117108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner mProvisioningObserver = new ProvisioningObserver(); 118da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 119da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff IntentFilter filter = new IntentFilter(); 120da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 121108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE); 122da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mContext.registerReceiver(mReceiver, filter); 123da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 124625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey mServer = Settings.Global.getString(mContext.getContentResolver(), 125625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey Settings.Global.CAPTIVE_PORTAL_SERVER); 126da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (mServer == null) mServer = DEFAULT_SERVER; 127da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 128625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(), 129625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1; 1309538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 1319538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff addState(mDefaultState); 1329538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff addState(mNoActiveNetworkState, mDefaultState); 1339538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff addState(mActiveNetworkState, mDefaultState); 1349538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff addState(mDelayedCaptiveCheckState, mActiveNetworkState); 1359538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff setInitialState(mNoActiveNetworkState); 136da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 137da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 138108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner private class ProvisioningObserver extends ContentObserver { 139108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner ProvisioningObserver() { 140108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner super(new Handler()); 141108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 142108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner Settings.Global.DEVICE_PROVISIONED), false, this); 143108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner onChange(false); // load initial value 144108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner } 145108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner 146108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner @Override 147108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner public void onChange(boolean selfChange) { 148108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner mDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(), 149108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner Settings.Global.DEVICE_PROVISIONED, 0) != 0; 150108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner } 151108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner } 152108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner 153da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 154da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff @Override 155da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff public void onReceive(Context context, Intent intent) { 156da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff String action = intent.getAction(); 157108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner // Normally, we respond to CONNECTIVITY_ACTION, allowing time for the change in 158108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner // connectivity to stabilize, but if the device is not yet provisioned, respond 159108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner // immediately to speed up transit through the setup wizard. 160108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner if ((mDeviceProvisioned && action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) 161108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner || (!mDeviceProvisioned 162108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner && action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE))) { 163da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff NetworkInfo info = intent.getParcelableExtra( 164da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff ConnectivityManager.EXTRA_NETWORK_INFO); 1659538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff sendMessage(obtainMessage(CMD_CONNECTIVITY_CHANGE, info)); 166da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 167da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 168da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff }; 169da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 1709538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public static CaptivePortalTracker makeCaptivePortalTracker(Context context, 171da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff IConnectivityManager cs) { 1729538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff CaptivePortalTracker captivePortal = new CaptivePortalTracker(context, cs); 1739538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff captivePortal.start(); 174da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return captivePortal; 175da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 176da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 1779538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public void detectCaptivePortal(NetworkInfo info) { 1789538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff sendMessage(obtainMessage(CMD_DETECT_PORTAL, info)); 1799538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 1809538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 1819538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private class DefaultState extends State { 182da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 183da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff @Override 1849538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public boolean processMessage(Message message) { 185948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville if (DBG) log(getName() + message.toString()); 1869538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff switch (message.what) { 1879538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_DETECT_PORTAL: 1889538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff NetworkInfo info = (NetworkInfo) message.obj; 1899538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff // Checking on a secondary connection is not supported 1909538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff // yet 1919538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff notifyPortalCheckComplete(info); 192da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff break; 1939538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_CONNECTIVITY_CHANGE: 1949538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_DELAYED_CAPTIVE_CHECK: 1959538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff break; 1969538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff default: 1979538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff loge("Ignoring " + message); 1989538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff break; 1999538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2009538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return HANDLED; 2019538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2029538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 203da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 2049538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private class NoActiveNetworkState extends State { 2059538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 2069538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public void enter() { 2073ec8e7fb79f2e662c2b06cfec118a0eeaefd9370Wink Saville setNotificationOff(); 2089538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff mNetworkInfo = null; 2099538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 210da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 2119538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 2129538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public boolean processMessage(Message message) { 213948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville if (DBG) log(getName() + message.toString()); 2149538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff InetAddress server; 2159538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff NetworkInfo info; 2169538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff switch (message.what) { 2179538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_CONNECTIVITY_CHANGE: 2189538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff info = (NetworkInfo) message.obj; 219948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville if (info.getType() == ConnectivityManager.TYPE_WIFI) { 220948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville if (info.isConnected() && isActiveNetwork(info)) { 221948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville mNetworkInfo = info; 222948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville transitionTo(mDelayedCaptiveCheckState); 223948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville } 224948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville } else { 225948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville log(getName() + " not a wifi connectivity change, ignore"); 226da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 227da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff break; 228da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff default: 2299538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return NOT_HANDLED; 230da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 2319538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return HANDLED; 2329538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2339538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2349538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 2359538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private class ActiveNetworkState extends State { 2369538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 2379538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public boolean processMessage(Message message) { 2389538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff NetworkInfo info; 2399538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff switch (message.what) { 2409538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_CONNECTIVITY_CHANGE: 2419538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff info = (NetworkInfo) message.obj; 2429538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (!info.isConnected() 2439538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff && info.getType() == mNetworkInfo.getType()) { 2449538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log("Disconnected from active network " + info); 2459538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff transitionTo(mNoActiveNetworkState); 2469538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } else if (info.getType() != mNetworkInfo.getType() && 2479538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff info.isConnected() && 2489538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff isActiveNetwork(info)) { 2499538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log("Active network switched " + info); 2509538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff deferMessage(message); 2519538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff transitionTo(mNoActiveNetworkState); 2529538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2539538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff break; 2549538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff default: 2559538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return NOT_HANDLED; 2569538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2579538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return HANDLED; 258da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 259da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 260da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 2619538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 2629538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 2639538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private class DelayedCaptiveCheckState extends State { 2649538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 2659538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public void enter() { 266108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner Message message = obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0); 267108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner if (mDeviceProvisioned) { 268108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner sendMessageDelayed(message, DELAYED_CHECK_INTERVAL_MS); 269108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner } else { 270108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner sendMessage(message); 271108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner } 2729538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 2739538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff 2749538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff @Override 2759538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff public boolean processMessage(Message message) { 276948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville if (DBG) log(getName() + message.toString()); 2779538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff switch (message.what) { 2789538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff case CMD_DELAYED_CAPTIVE_CHECK: 2793ec8e7fb79f2e662c2b06cfec118a0eeaefd9370Wink Saville setNotificationOff(); 2803ec8e7fb79f2e662c2b06cfec118a0eeaefd9370Wink Saville 2819538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (message.arg1 == mDelayedCheckToken) { 2829538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff InetAddress server = lookupHost(mServer); 283108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner boolean captive = server != null && isCaptivePortal(server); 284108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner if (captive) { 285108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner if (DBG) log("Captive network " + mNetworkInfo); 286108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner } else { 287108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner if (DBG) log("Not captive network " + mNetworkInfo); 288108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner } 289d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville notifyPortalCheckCompleted(mNetworkInfo, captive); 290108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner if (mDeviceProvisioned) { 291108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner if (captive) { 292108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner // Setup Wizard will assist the user in connecting to a captive 293108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner // portal, so make the notification visible unless during setup 294948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville try { 295948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville mConnService.setProvisioningNotificationVisible(true, 296948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville mNetworkInfo.getType(), mNetworkInfo.getExtraInfo(), mUrl); 297948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville } catch(RemoteException e) { 298948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville e.printStackTrace(); 299948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville } 3009538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 301108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner } else { 302108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner Intent intent = new Intent( 303108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner ConnectivityManager.ACTION_CAPTIVE_PORTAL_TEST_COMPLETED); 304108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner intent.putExtra(ConnectivityManager.EXTRA_IS_CAPTIVE_PORTAL, captive); 305108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner intent.setPackage(SETUP_WIZARD_PACKAGE); 306108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner mContext.sendBroadcast(intent); 3079538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 308108da0cfa4a2f59cc953a4ec61314e69b61d6777Russell Brenner 3099538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff transitionTo(mActiveNetworkState); 3109538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 3119538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff break; 3129538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff default: 3139538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return NOT_HANDLED; 3149538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 3159538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return HANDLED; 3169538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 317da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 318da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 3199538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private void notifyPortalCheckComplete(NetworkInfo info) { 3209538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (info == null) { 3219538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff loge("notifyPortalCheckComplete on null"); 3229538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return; 3239538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 324da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff try { 325d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville if (DBG) log("notifyPortalCheckComplete: ni=" + info); 3269538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff mConnService.captivePortalCheckComplete(info); 327da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } catch(RemoteException e) { 328da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff e.printStackTrace(); 329da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 330da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 331da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 332d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville private void notifyPortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { 333d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville if (info == null) { 334d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville loge("notifyPortalCheckComplete on null"); 335d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville return; 336d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville } 337d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville try { 338d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville if (DBG) log("notifyPortalCheckCompleted: captive=" + isCaptivePortal + " ni=" + info); 339d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville mConnService.captivePortalCheckCompleted(info, isCaptivePortal); 340d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville } catch(RemoteException e) { 341d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville e.printStackTrace(); 342d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville } 343d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville } 344d747cbc898ef44e59c3fbf74a8327b6a12aad397Wink Saville 3459538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff private boolean isActiveNetwork(NetworkInfo info) { 346da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff try { 3479538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff NetworkInfo active = mConnService.getActiveNetworkInfo(); 3489538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (active != null && active.getType() == info.getType()) { 3499538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return true; 3509538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff } 351da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } catch (RemoteException e) { 352da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff e.printStackTrace(); 353da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 3549538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff return false; 355da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 356da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 357948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville private void setNotificationOff() { 358948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville try { 3593ec8e7fb79f2e662c2b06cfec118a0eeaefd9370Wink Saville if (mNetworkInfo != null) { 3603ec8e7fb79f2e662c2b06cfec118a0eeaefd9370Wink Saville mConnService.setProvisioningNotificationVisible(false, mNetworkInfo.getType(), 361948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville null, null); 3623ec8e7fb79f2e662c2b06cfec118a0eeaefd9370Wink Saville } 363948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville } catch (RemoteException e) { 364948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville log("setNotificationOff: " + e); 365948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville } 366948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville } 367948282b0e6cf5310f09db97a4ae939db7c1cef72Wink Saville 368da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff /** 3691ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee * Do a URL fetch on a known server to see if we get the data we expect. 3701ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee * Measure the response time and broadcast that. 371da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff */ 372da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private boolean isCaptivePortal(InetAddress server) { 373da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff HttpURLConnection urlConnection = null; 374da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (!mIsCaptivePortalCheckEnabled) return false; 375da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 376da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff mUrl = "http://" + server.getHostAddress() + "/generate_204"; 3779538bdd3c77968c7673719c580ae653ede4654d6Irfan Sheriff if (DBG) log("Checking " + mUrl); 3781ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee long requestTimestamp = -1; 379da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff try { 380da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff URL url = new URL(mUrl); 381da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection = (HttpURLConnection) url.openConnection(); 382da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.setInstanceFollowRedirects(false); 383da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); 384da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); 385da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.setUseCaches(false); 3861ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 3871ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee // Time how long it takes to get a response to our request 3881ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee requestTimestamp = SystemClock.elapsedRealtime(); 3891ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 390da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.getInputStream(); 3911ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 3921ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee // Time how long it takes to get a response to our request 3931ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee long responseTimestamp = SystemClock.elapsedRealtime(); 3941ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 395da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff // we got a valid response, but not from the real google 3969d4204d6257bf69885cf0718aa3adaa17457c318Wink Saville int rspCode = urlConnection.getResponseCode(); 3979d4204d6257bf69885cf0718aa3adaa17457c318Wink Saville boolean isCaptivePortal = rspCode != 204; 3981ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 3991ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee sendNetworkConditionsBroadcast(true /* response received */, isCaptivePortal, 4001ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee requestTimestamp, responseTimestamp); 4019d4204d6257bf69885cf0718aa3adaa17457c318Wink Saville 4029d4204d6257bf69885cf0718aa3adaa17457c318Wink Saville if (DBG) log("isCaptivePortal: ret=" + isCaptivePortal + " rspCode=" + rspCode); 4031ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee return isCaptivePortal; 404da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } catch (IOException e) { 405da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (DBG) log("Probably not a portal: exception " + e); 4061ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (requestTimestamp != -1) { 4071ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee sendFailedCaptivePortalCheckBroadcast(requestTimestamp); 4081ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } // else something went wrong with setting up the urlConnection 409da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return false; 410da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } finally { 411da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (urlConnection != null) { 412da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff urlConnection.disconnect(); 413da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 414da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 415da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 416da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 417da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff private InetAddress lookupHost(String hostname) { 418da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff InetAddress inetAddress[]; 419da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff try { 420da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff inetAddress = InetAddress.getAllByName(hostname); 421da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } catch (UnknownHostException e) { 4221ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime()); 423da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return null; 424da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 425da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 426da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff for (InetAddress a : inetAddress) { 427da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff if (a instanceof Inet4Address) return a; 428da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 4291ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 4301ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime()); 431da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff return null; 432da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff } 433da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff 4341ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee private void sendFailedCaptivePortalCheckBroadcast(long requestTimestampMs) { 4351ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee sendNetworkConditionsBroadcast(false /* response received */, false /* ignored */, 4361ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee requestTimestampMs, 0 /* ignored */); 4371ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 4381ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 4391ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee /** 4401ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee * @param responseReceived - whether or not we received a valid HTTP response to our request. 4411ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee * If false, isCaptivePortal and responseTimestampMs are ignored 4421ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee */ 4431ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal, 4441ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee long requestTimestampMs, long responseTimestampMs) { 4451ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (Settings.Global.getInt(mContext.getContentResolver(), 4461ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) { 4471ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (DBG) log("Don't send network conditions - lacking user consent."); 4481ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee return; 4491ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 4501ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 4511ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED); 4521ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee switch (mNetworkInfo.getType()) { 4531ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee case ConnectivityManager.TYPE_WIFI: 4541ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo(); 4551ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (currentWifiInfo != null) { 4561ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID()); 4571ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID()); 4581ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } else { 4591ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found"); 4601ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee return; 4611ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 4621ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee break; 4631ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee case ConnectivityManager.TYPE_MOBILE: 4641ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType()); 4651ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee List<CellInfo> info = mTelephonyManager.getAllCellInfo(); 4661ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (info == null) return; 4671ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee StringBuffer uniqueCellId = new StringBuffer(); 4681ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee int numRegisteredCellInfo = 0; 4691ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee for (CellInfo cellInfo : info) { 4701ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (cellInfo.isRegistered()) { 4711ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee numRegisteredCellInfo++; 4721ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (numRegisteredCellInfo > 1) { 4731ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (DBG) log("more than one registered CellInfo. Can't " + 4741ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee "tell which is active. Bailing."); 4751ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee return; 4761ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 4771ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (cellInfo instanceof CellInfoCdma) { 4781ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity(); 4791ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 4801ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } else if (cellInfo instanceof CellInfoGsm) { 4811ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity(); 4821ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 4831ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } else if (cellInfo instanceof CellInfoLte) { 4841ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity(); 4851ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 4861ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } else if (cellInfo instanceof CellInfoWcdma) { 4871ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity(); 4881ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 4891ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } else { 4901ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (DBG) logw("Registered cellinfo is unrecognized"); 4911ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee return; 4921ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 4931ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 4941ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 4951ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee break; 4961ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee default: 4971ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee return; 4981ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 4991ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkInfo.getType()); 5001ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived); 5011ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs); 5021ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee 5031ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee if (responseReceived) { 5041ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal); 5051ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs); 5061ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 5071ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee mContext.sendBroadcast(latencyBroadcast, PERMISSION_ACCESS_NETWORK_CONDITIONS); 5081ed51627d94b140e8893b8e1dcde9bf37e2adca7Brian Williammee } 509da6da0907b28d4704aabbdb1bbeb4300954670d1Irfan Sheriff} 510