NetworkMonitor.java revision a68d21350266a6abc16aeb3fec84eafd85b77cc8
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2014 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * you may not use this file except in compliance with the License. 669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * You may obtain a copy of the License at 769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 1269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * See the License for the specific language governing permissions and 1469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server.connectivity; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.PendingIntent; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 210795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopianimport android.content.ComponentName; 220795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopianimport android.content.Context; 230795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopianimport android.content.Intent; 24f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kastenimport android.content.IntentFilter; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.ConnectivityManager; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Network; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.NetworkCapabilities; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.NetworkInfo; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.wifi.WifiInfo; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.wifi.WifiManager; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.UserHandle; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.CellIdentityCdma; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.CellIdentityGsm; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.CellIdentityLte; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.CellIdentityWcdma; 416af763bec7c3f4d50fee8dd0046409bb8a7fe8f6Glenn Kastenimport android.telephony.CellInfo; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.CellInfoCdma; 43957e58670baad8c5995f1368e3b5280f0dbd891fSan Mehatimport android.telephony.CellInfoGsm; 44160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport android.telephony.CellInfoLte; 45a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehatimport android.telephony.CellInfoWcdma; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.telephony.TelephonyManager; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 48160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport com.android.internal.util.Protocol; 49160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport com.android.internal.util.State; 50160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport com.android.internal.util.StateMachine; 51160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport com.android.server.ConnectivityService; 52160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tateimport com.android.server.connectivity.NetworkAgentInfo; 53f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten 54f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kastenimport java.io.IOException; 556793ac943afeb16642f477c43ddfd27e498db37bGlenn Kastenimport java.net.HttpURLConnection; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.net.URL; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide} 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class NetworkMonitor extends StateMachine { 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final boolean DBG = true; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "NetworkMonitor"; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String DEFAULT_SERVER = "clients3.google.com"; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int SOCKET_TIMEOUT_MS = 10000; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String ACTION_NETWORK_CONDITIONS_MEASURED = 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "android.net.conn.NETWORK_CONDITIONS_MEASURED"; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String EXTRA_NETWORK_TYPE = "extra_network_type"; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received"; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal"; 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String EXTRA_CELL_ID = "extra_cellid"; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String EXTRA_SSID = "extra_ssid"; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final String EXTRA_BSSID = "extra_bssid"; 766793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten /** real time since boot */ 77e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms"; 78e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms"; 79e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat 80e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = 81e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat "android.permission.ACCESS_NETWORK_CONDITIONS"; 82e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat 83e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat // Intent broadcast when user selects sign-in notification. 84e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat private static final String ACTION_SIGN_IN_REQUESTED = 85e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat "android.net.netmon.sign_in_requested"; 86e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat 87e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat // Keep these in sync with CaptivePortalLoginActivity.java. 88e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat // Intent broadcast from CaptivePortalLogin indicating sign-in is complete. 89e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat // Extras: 90e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat // EXTRA_TEXT = netId 91e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat // LOGGED_IN_RESULT = "1" if we should use network, "0" if not. 92e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat private static final String ACTION_CAPTIVE_PORTAL_LOGGED_IN = 93e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat "android.net.netmon.captive_portal_logged_in"; 94e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat private static final String LOGGED_IN_RESULT = "result"; 95e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat 96e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat private static final int BASE = Protocol.BASE_NETWORK_MONITOR; 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Inform NetworkMonitor that their network is connected. 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Initiates Network Validation. 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10280b12fcaaec458377d966803c3a61504f0897ea1Romain Guy public static final int CMD_NETWORK_CONNECTED = BASE + 1; 10380b12fcaaec458377d966803c3a61504f0897ea1Romain Guy 10480b12fcaaec458377d966803c3a61504f0897ea1Romain Guy /** 10580b12fcaaec458377d966803c3a61504f0897ea1Romain Guy * Inform ConnectivityService that the network is validated. 10680b12fcaaec458377d966803c3a61504f0897ea1Romain Guy * obj = NetworkAgentInfo 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int EVENT_NETWORK_VALIDATED = BASE + 2; 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Inform NetworkMonitor to linger a network. The Monitor should 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * start a timer and/or start watching for zero live connections while 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * moving towards LINGER_COMPLETE. After the Linger period expires 114887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn * (or other events mark the end of the linger state) the LINGER_COMPLETE 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * event should be sent and the network will be shut down. If a 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * CMD_NETWORK_CONNECTED happens before the LINGER completes 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it indicates further desire to keep the network alive and so 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the LINGER is aborted. 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes public static final int CMD_NETWORK_LINGER = BASE + 3; 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * Message to self indicating linger delay has expired. 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg1 = Token to ignore old messages. 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CMD_LINGER_EXPIRED = BASE + 4; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Inform ConnectivityService that the network LINGER period has 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * expired. 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * obj = NetworkAgentInfo 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int EVENT_NETWORK_LINGER_COMPLETE = BASE + 5; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Message to self indicating it's time to evaluate a network's connectivity. 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg1 = Token to ignore old messages. 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CMD_REEVALUATE = BASE + 6; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Message to self indicating network evaluation is complete. 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg1 = Token to ignore old messages. 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg2 = HTTP response code of network evaluation. 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int EVENT_REEVALUATION_COMPLETE = BASE + 7; 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Inform NetworkMonitor that the network has disconnected. 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes public static final int CMD_NETWORK_DISCONNECTED = BASE + 8; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * Force evaluation even if it has succeeded in the past. 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int CMD_FORCE_REEVALUATION = BASE + 9; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Message to self indicating captive portal login is complete. 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg1 = Token to ignore old messages. 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg2 = 1 if we should use this network, 0 otherwise. 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CMD_CAPTIVE_PORTAL_LOGGED_IN = BASE + 10; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Message to self indicating user desires to log into captive portal. 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg1 = Token to ignore old messages. 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CMD_USER_WANTS_SIGN_IN = BASE + 11; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Request ConnectivityService display provisioning notification. 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg1 = Whether to make the notification visible. 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * arg2 = NetID. 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * obj = Intent to be launched when notification selected by user, null if !arg1. 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 12; 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten /** 180e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat * Message to self indicating sign-in app bypassed captive portal. 181f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten */ 182f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private static final int EVENT_APP_BYPASSED_CAPTIVE_PORTAL = BASE + 13; 183f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten 184887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn /** 185f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten * Message to self indicating no sign-in app responded. 186e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat */ 187e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat private static final int EVENT_NO_APP_RESPONSE = BASE + 14; 188e9d376b801b7890b1ef5006ed55de4208e64bb63San Mehat 18969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes /** 1903e458241d9930465a20a861ecb42744355d48e48San Mehat * Message to self indicating sign-in app indicates sign-in is not possible. 191f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten */ 1923e458241d9930465a20a861ecb42744355d48e48San Mehat private static final int EVENT_APP_INDICATES_SIGN_IN_IMPOSSIBLE = BASE + 15; 1933e458241d9930465a20a861ecb42744355d48e48San Mehat 1943e458241d9930465a20a861ecb42744355d48e48San Mehat private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger"; 1953e458241d9930465a20a861ecb42744355d48e48San Mehat // Default to 30s linger time-out. 1963e458241d9930465a20a861ecb42744355d48e48San Mehat private static final int DEFAULT_LINGER_DELAY_MS = 30000; 197f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private final int mLingerDelayMs; 1986793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten private int mLingerToken = 0; 1993e458241d9930465a20a861ecb42744355d48e48San Mehat 2003e458241d9930465a20a861ecb42744355d48e48San Mehat // Negative values disable reevaluation. 2013e458241d9930465a20a861ecb42744355d48e48San Mehat private static final String REEVALUATE_DELAY_PROPERTY = "persist.netmon.reeval_delay"; 202f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten // Default to 5s reevaluation delay. 203f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private static final int DEFAULT_REEVALUATE_DELAY_MS = 5000; 204f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private static final int MAX_RETRIES = 10; 205f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private final int mReevaluateDelayMs; 206f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private int mReevaluateToken = 0; 207f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten 208f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private int mCaptivePortalLoggedInToken = 0; 209a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private int mUserPromptedToken = 0; 210a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat 211a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private final Context mContext; 212a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private final Handler mConnectivityServiceHandler; 213a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private final NetworkAgentInfo mNetworkAgentInfo; 214a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private final TelephonyManager mTelephonyManager; 215a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private final WifiManager mWifiManager; 216a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat 217a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private String mServer; 218a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private boolean mIsCaptivePortalCheckEnabled = false; 219a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat 220a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat public boolean systemReady = false; 221a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat 22269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes private State mDefaultState = new DefaultState(); 223f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private State mOfflineState = new OfflineState(); 2245baa3a62a97544669fba6d65a11c07f252e654ddSteve Block private State mValidatedState = new ValidatedState(); 225a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private State mEvaluatingState = new EvaluatingState(); 2265baa3a62a97544669fba6d65a11c07f252e654ddSteve Block private State mUserPromptedState = new UserPromptedState(); 227a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private State mCaptivePortalState = new CaptivePortalState(); 228a5109a878eeff22e32ee5ce1b1cd15e8daad5234San Mehat private State mLingeringState = new LingeringState(); 2293e458241d9930465a20a861ecb42744355d48e48San Mehat 2303e458241d9930465a20a861ecb42744355d48e48San Mehat public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo) { 2311fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat // Add suffix indicating which NetworkMonitor we're talking about. 2321fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat super(TAG + networkAgentInfo.name()); 2336793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten 2343e458241d9930465a20a861ecb42744355d48e48San Mehat mContext = context; 2353e458241d9930465a20a861ecb42744355d48e48San Mehat mConnectivityServiceHandler = handler; 2363e458241d9930465a20a861ecb42744355d48e48San Mehat mNetworkAgentInfo = networkAgentInfo; 2373e458241d9930465a20a861ecb42744355d48e48San Mehat mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 2387e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 2397e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat 2407e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat addState(mDefaultState); 2413e458241d9930465a20a861ecb42744355d48e48San Mehat addState(mOfflineState, mDefaultState); 2423e458241d9930465a20a861ecb42744355d48e48San Mehat addState(mValidatedState, mDefaultState); 2437e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat addState(mEvaluatingState, mDefaultState); 2447e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat addState(mUserPromptedState, mDefaultState); 2457e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat addState(mCaptivePortalState, mDefaultState); 2463762c311729fe9f3af085c14c5c1fb471d994c03Steve Block addState(mLingeringState, mDefaultState); 2477e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat setInitialState(mOfflineState); 2487e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat 2491fd0ec738b0a2b97cc28701aa37b1a9869afc684San Mehat mServer = Settings.Global.getString(mContext.getContentResolver(), 25007b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten Settings.Global.CAPTIVE_PORTAL_SERVER); 25107b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten if (mServer == null) mServer = DEFAULT_SERVER; 25207b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten 25307b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten mLingerDelayMs = SystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS); 25407b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten mReevaluateDelayMs = SystemProperties.getInt(REEVALUATE_DELAY_PROPERTY, 25507b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten DEFAULT_REEVALUATE_DELAY_MS); 25607b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten 25707b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(), 25807b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1; 2597e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat 26007b0465095bd9ab3412caefa4fcacbdc3825c64bGlenn Kasten start(); 261f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten } 262f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten 263f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten private class DefaultState extends State { 264f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten @Override 2657e63789a0e0689d940609b1daceebc1bc08dcbefSan Mehat public boolean processMessage(Message message) { 26669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes if (DBG) log(getName() + message.toString()); 267f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten switch (message.what) { 268f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten case CMD_NETWORK_LINGER: 269f1b56449f58963e4f0473d5e26961f68c31759f4Glenn Kasten if (DBG) log("Lingering"); 2700a42b811aea490a9a605b75f0320101f6eafd283San Mehat transitionTo(mLingeringState); 271242d65bf9faf1d2bc3468490e510551140e23462San Mehat return HANDLED; 2723e458241d9930465a20a861ecb42744355d48e48San Mehat case CMD_NETWORK_CONNECTED: 2733e458241d9930465a20a861ecb42744355d48e48San Mehat if (DBG) log("Connected"); 2743e458241d9930465a20a861ecb42744355d48e48San Mehat transitionTo(mEvaluatingState); 2753e458241d9930465a20a861ecb42744355d48e48San Mehat return HANDLED; 2769e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey case CMD_NETWORK_DISCONNECTED: 2779e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey if (DBG) log("Disconnected - quitting"); 2789e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey quit(); 2799e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey return HANDLED; 2809e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey case CMD_FORCE_REEVALUATION: 2819e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey if (DBG) log("Forcing reevaluation"); 2829e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey transitionTo(mEvaluatingState); 2839e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey return HANDLED; 2849e57c414f39e1a31349bc215635fdcfaf1902ceeJeff Sharkey default: 285160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate return HANDLED; 286160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate } 287160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate } 288160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate } 28971f2cf116aab893e224056c38ab146bd1538dd3eSteve Block 290160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate private class OfflineState extends State { 291160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate @Override 292160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate public boolean processMessage(Message message) { 293160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate if (DBG) log(getName() + message.toString()); 294160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate return NOT_HANDLED; 295160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate } 296160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate } 297160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate 298160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate private class ValidatedState extends State { 299160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate @Override 300160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate public void enter() { 301160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate if (DBG) log("Validated"); 3026793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten mConnectivityServiceHandler.sendMessage( 3036793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten obtainMessage(EVENT_NETWORK_VALIDATED, mNetworkAgentInfo)); 3046793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten } 305cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten 3066793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten @Override 3076793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten public boolean processMessage(Message message) { 3086793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten if (DBG) log(getName() + message.toString()); 3096793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten switch (message.what) { 3106793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten case CMD_NETWORK_CONNECTED: 3116793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten transitionTo(mValidatedState); 312cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten return HANDLED; 313cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten default: 314cc767191cfb675f744e0165608b0a4196aba2b37Glenn Kasten return NOT_HANDLED; 3156793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten } 3166793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten } 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class EvaluatingState extends State { 320160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate private int mRetries; 321160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate 322160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate private class EvaluateInternetConnectivity extends Thread { 323160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate private int mToken; 324160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate EvaluateInternetConnectivity(int token) { 325160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate mToken = token; 326160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate } 3273762c311729fe9f3af085c14c5c1fb471d994c03Steve Block public void run() { 328160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate sendMessage(EVENT_REEVALUATION_COMPLETE, mToken, isCaptivePortal()); 329160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate } 330160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate } 331160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate 332160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate @Override 333160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate public void enter() { 334160edb3645f8b7012bab70ae6e6e8c4a5733082bChristopher Tate mRetries = 0; 335887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0); 336887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn } 337887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn 3386793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten @Override 339887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn public boolean processMessage(Message message) { 3406793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten if (DBG) log(getName() + message.toString()); 341887f355f99ff83d568ef2885a4fdcaae475583dfDianne Hackborn switch (message.what) { 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case CMD_REEVALUATE: 34369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes if (message.arg1 != mReevaluateToken) 3446215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block return HANDLED; 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mNetworkAgentInfo.isVPN()) { 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project transitionTo(mValidatedState); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If network provides no internet connectivity adjust evaluation. 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mNetworkAgentInfo.networkCapabilities.hasCapability( 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NetworkCapabilities.NET_CAPABILITY_INTERNET)) { 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Try to verify something works. Do all gateways respond to pings? 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project transitionTo(mValidatedState); 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Kick off a thread to perform internet connectivity evaluation. 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Thread thread = new EvaluateInternetConnectivity(mReevaluateToken); 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project thread.run(); 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case EVENT_REEVALUATION_COMPLETE: 3616793ac943afeb16642f477c43ddfd27e498db37bGlenn Kasten if (message.arg1 != mReevaluateToken) 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 3636215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block int httpResponseCode = message.arg2; 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (httpResponseCode == 204) { 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project transitionTo(mValidatedState); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (httpResponseCode >= 200 && httpResponseCode <= 399) { 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project transitionTo(mUserPromptedState); 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (++mRetries > MAX_RETRIES) { 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project transitionTo(mOfflineState); 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mReevaluateDelayMs >= 0) { 37110e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0); 37210e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown sendMessageDelayed(msg, mReevaluateDelayMs); 37310e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown } 37410e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown return HANDLED; 37510e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown default: 37610e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown return NOT_HANDLED; 37710e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown } 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 37910e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown } 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class UserPromptedState extends State { 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class UserRespondedBroadcastReceiver extends BroadcastReceiver { 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final int mToken; 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project UserRespondedBroadcastReceiver(int token) { 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mToken = token; 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 38769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes @Override 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Integer.parseInt(intent.getStringExtra(Intent.EXTRA_TEXT)) == 39069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes mNetworkAgentInfo.network.netId) { 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sendMessage(obtainMessage(CMD_USER_WANTS_SIGN_IN, mToken)); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private UserRespondedBroadcastReceiver mUserRespondedBroadcastReceiver; 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void enter() { 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wait for user to select sign-in notifcation. 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mUserRespondedBroadcastReceiver = new UserRespondedBroadcastReceiver( 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ++mUserPromptedToken); 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project IntentFilter filter = new IntentFilter(ACTION_SIGN_IN_REQUESTED); 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.registerReceiver(mUserRespondedBroadcastReceiver, filter); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Initiate notification to sign-in. 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent intent = new Intent(ACTION_SIGN_IN_REQUESTED); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project intent.putExtra(Intent.EXTRA_TEXT, String.valueOf(mNetworkAgentInfo.network.netId)); 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 1, 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNetworkAgentInfo.network.netId, 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mConnectivityServiceHandler.sendMessage(message); 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4156215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block public boolean processMessage(Message message) { 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log(getName() + message.toString()); 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (message.what) { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case CMD_USER_WANTS_SIGN_IN: 41959325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn if (message.arg1 != mUserPromptedToken) 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project transitionTo(mCaptivePortalState); 42269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return HANDLED; 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 4248564c8da817a845353d213acd8636b76f567b234Steve Block return NOT_HANDLED; 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 42769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void exit() { 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 0, 43169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes mNetworkAgentInfo.network.netId, null); 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mConnectivityServiceHandler.sendMessage(message); 4338564c8da817a845353d213acd8636b76f567b234Steve Block mContext.unregisterReceiver(mUserRespondedBroadcastReceiver); 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mUserRespondedBroadcastReceiver = null; 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class CaptivePortalState extends State { 4390bca96bcbfe559f9330a01f723c5c9cba51ec05aMarco Nelissen private class CaptivePortalLoggedInBroadcastReceiver extends BroadcastReceiver { 44069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes private final int mToken; 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 44259325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn CaptivePortalLoggedInBroadcastReceiver(int token) { 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mToken = token; 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Integer.parseInt(intent.getStringExtra(Intent.EXTRA_TEXT)) == 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNetworkAgentInfo.network.netId) { 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sendMessage(obtainMessage(CMD_CAPTIVE_PORTAL_LOGGED_IN, mToken, 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Integer.parseInt(intent.getStringExtra(LOGGED_IN_RESULT)))); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4550bca96bcbfe559f9330a01f723c5c9cba51ec05aMarco Nelissen 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private CaptivePortalLoggedInBroadcastReceiver mCaptivePortalLoggedInBroadcastReceiver; 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void enter() { 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent intent = new Intent(Intent.ACTION_SEND); 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project intent.putExtra(Intent.EXTRA_TEXT, String.valueOf(mNetworkAgentInfo.network.netId)); 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project intent.setType("text/plain"); 46369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes intent.setComponent(new ComponentName("com.android.captiveportallogin", 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "com.android.captiveportallogin.CaptivePortalLoginActivity")); 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 46759325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn // Wait for result. 46859325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn mCaptivePortalLoggedInBroadcastReceiver = new CaptivePortalLoggedInBroadcastReceiver( 46959325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn ++mCaptivePortalLoggedInToken); 47059325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn IntentFilter filter = new IntentFilter(ACTION_CAPTIVE_PORTAL_LOGGED_IN); 47159325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn mContext.registerReceiver(mCaptivePortalLoggedInBroadcastReceiver, filter); 47259325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn // Initiate app to log in. 47359325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn mContext.startActivityAsUser(intent, UserHandle.CURRENT); 47459325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn } 47559325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn 47659325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn @Override 47759325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn public boolean processMessage(Message message) { 47859325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn if (DBG) log(getName() + message.toString()); 47959325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn switch (message.what) { 48059325eb31f25704bb88c348160bb69e7c1aa3b48Dianne Hackborn case CMD_CAPTIVE_PORTAL_LOGGED_IN: 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (message.arg1 != mCaptivePortalLoggedInToken) 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (message.arg2 == 0) { 4846215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block // TODO: Should teardown network. 48569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes transitionTo(mOfflineState); 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 48769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes transitionTo(mValidatedState); 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 49069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes default: 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NOT_HANDLED; 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void exit() { 49769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes mContext.unregisterReceiver(mCaptivePortalLoggedInBroadcastReceiver); 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCaptivePortalLoggedInBroadcastReceiver = null; 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class LingeringState extends State { 50369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes @Override 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void enter() { 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Message message = obtainMessage(CMD_LINGER_EXPIRED, ++mLingerToken, 0); 50669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes sendMessageDelayed(message, mLingerDelayMs); 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean processMessage(Message message) { 5116215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block if (DBG) log(getName() + message.toString()); 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (message.what) { 51369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes case CMD_NETWORK_CONNECTED: 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Go straight to active as we've already evaluated. 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project transitionTo(mValidatedState); 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case CMD_LINGER_EXPIRED: 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (message.arg1 != mLingerToken) 51969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return HANDLED; 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mConnectivityServiceHandler.sendMessage( 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project obtainMessage(EVENT_NETWORK_LINGER_COMPLETE, mNetworkAgentInfo)); 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return HANDLED; 52369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes default: 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NOT_HANDLED; 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 52869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 5296215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block /** 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Do a URL fetch on a known server to see if we get the data we expect. 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns HTTP response code. 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 53369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes private int isCaptivePortal() { 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mIsCaptivePortalCheckEnabled) return 204; 53569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HttpURLConnection urlConnection = null; 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int httpResponseCode = 599; 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project URL url = new URL("http", mServer, "/generate_204"); 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) { 54169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes log("Checking " + url.toString() + " on " + 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mNetworkAgentInfo.networkInfo.getExtraInfo()); 5438564c8da817a845353d213acd8636b76f567b234Steve Block } 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project url = mNetworkAgentInfo.network.getBoundURL(url); 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection = (HttpURLConnection) url.openConnection(); 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.setInstanceFollowRedirects(false); 54769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); 54969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes urlConnection.setUseCaches(false); 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Time how long it takes to get a response to our request 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long requestTimestamp = SystemClock.elapsedRealtime(); 5536215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.getInputStream(); 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Time how long it takes to get a response to our request 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long responseTimestamp = SystemClock.elapsedRealtime(); 558add868cebaf62cffe96e79764ea0b7f2320a03ebAmith Yamasani 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project httpResponseCode = urlConnection.getResponseCode(); 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) { 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project log("isCaptivePortal: ret=" + httpResponseCode + 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " headers=" + urlConnection.getHeaderFields()); 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // portal. The only example of this seen so far was a captive portal. For 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the time being go with prior behavior of assuming it's not a captive 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // portal. If it is considered a captive portal, a different sign-in URL 5686215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block // is needed (i.e. can't browse a 204). This could be the result of an HTTP 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // proxy server. 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Consider 200 response with "Content-length=0" to not be a captive portal. 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // There's no point in considering this a captive portal as the user cannot 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // sign-in to an empty page. Probably the result of a broken transparent proxy. 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // See http://b/9972012. 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (httpResponseCode == 200 && urlConnection.getContentLength() == 0) { 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log("Empty 200 response interpreted as 204 response."); 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project httpResponseCode = 204; 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sendNetworkConditionsBroadcast(true /* response received */, httpResponseCode == 204, 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestTimestamp, responseTimestamp); 58269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes } catch (IOException e) { 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log("Probably not a portal: exception " + e); 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (httpResponseCode == 599) { 5858564c8da817a845353d213acd8636b76f567b234Steve Block // TODO: Ping gateway and DNS server and log results. 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 58769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes } finally { 5886215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block if (urlConnection != null) { 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project urlConnection.disconnect(); 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return httpResponseCode; 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 59669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * @param responseReceived - whether or not we received a valid HTTP response to our request. 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If false, isCaptivePortal and responseTimestampMs are ignored 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TODO: This should be moved to the transports. The latency could be passed to the transports 59969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes * along with the captive portal result. Currently the TYPE_MOBILE broadcasts appear unused so 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * perhaps this could just be added to the WiFi transport only. 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal, 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long requestTimestampMs, long responseTimestampMs) { 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Settings.Global.getInt(mContext.getContentResolver(), 60569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) { 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log("Don't send network conditions - lacking user consent."); 60769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return; 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 60969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (systemReady == false) return; 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED); 61369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes switch (mNetworkAgentInfo.networkInfo.getType()) { 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case ConnectivityManager.TYPE_WIFI: 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo(); 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (currentWifiInfo != null) { 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // NOTE: getSSID()'s behavior changed in API 17; before that, SSIDs were not 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // surrounded by double quotation marks (thus violating the Javadoc), but this 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // was changed to match the Javadoc in API 17. Since clients may have started 62069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes // sanitizing the output of this method since API 17 was released, we should 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // not change it here as it would become impossible to tell whether the SSID is 62269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes // simply being surrounded by quotes due to the API, or whether those quotes 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // are actually part of the SSID. 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID()); 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID()); 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found"); 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 63169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes case ConnectivityManager.TYPE_MOBILE: 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType()); 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<CellInfo> info = mTelephonyManager.getAllCellInfo(); 6346215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block if (info == null) return; 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numRegisteredCellInfo = 0; 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (CellInfo cellInfo : info) { 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cellInfo.isRegistered()) { 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numRegisteredCellInfo++; 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (numRegisteredCellInfo > 1) { 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) log("more than one registered CellInfo. Can't " + 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "tell which is active. Bailing."); 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cellInfo instanceof CellInfoCdma) { 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity(); 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (cellInfo instanceof CellInfoGsm) { 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity(); 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (cellInfo instanceof CellInfoLte) { 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity(); 65269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (cellInfo instanceof CellInfoWcdma) { 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity(); 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId); 65669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes } else { 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (DBG) logw("Registered cellinfo is unrecognized"); 65869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return; 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 66269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes break; 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkAgentInfo.networkInfo.getType()); 66769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived); 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs); 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (responseReceived) { 67169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal); 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs); 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(latencyBroadcast, PERMISSION_ACCESS_NETWORK_CONDITIONS); 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project