blob: 6658456f84b84b824aa606b1f714f1c4e1d9b12d [file] [log] [blame]
Irfan Sheriffda6da092012-08-16 12:49:23 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net;
18
Irfan Sheriff9538bdd2012-09-20 09:32:41 -070019import android.app.Activity;
Irfan Sheriffda6da092012-08-16 12:49:23 -070020import android.app.Notification;
21import android.app.NotificationManager;
22import android.app.PendingIntent;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.res.Resources;
Russell Brenner108da0c2013-02-12 10:03:14 -080028import android.database.ContentObserver;
Irfan Sheriffda6da092012-08-16 12:49:23 -070029import android.net.ConnectivityManager;
30import android.net.IConnectivityManager;
Brian Williammee1ed51622013-07-31 17:07:33 -070031import android.net.wifi.WifiInfo;
32import android.net.wifi.WifiManager;
Russell Brenner108da0c2013-02-12 10:03:14 -080033import android.os.Handler;
Irfan Sheriff9538bdd2012-09-20 09:32:41 -070034import android.os.UserHandle;
Irfan Sheriffda6da092012-08-16 12:49:23 -070035import android.os.Message;
36import android.os.RemoteException;
Brian Williammee1ed51622013-07-31 17:07:33 -070037import android.os.SystemClock;
Irfan Sheriffda6da092012-08-16 12:49:23 -070038import android.provider.Settings;
Brian Williammee1ed51622013-07-31 17:07:33 -070039import android.telephony.CellIdentityCdma;
40import android.telephony.CellIdentityGsm;
41import android.telephony.CellIdentityLte;
42import android.telephony.CellIdentityWcdma;
43import android.telephony.CellInfo;
44import android.telephony.CellInfoCdma;
45import android.telephony.CellInfoGsm;
46import android.telephony.CellInfoLte;
47import android.telephony.CellInfoWcdma;
Irfan Sheriffb8aad91f2012-10-02 14:01:28 -070048import android.telephony.TelephonyManager;
Wink Saville42d4f082013-07-20 20:31:59 -070049import android.text.TextUtils;
Irfan Sheriffda6da092012-08-16 12:49:23 -070050
Irfan Sheriff9538bdd2012-09-20 09:32:41 -070051import com.android.internal.util.State;
52import com.android.internal.util.StateMachine;
53
Irfan Sheriffda6da092012-08-16 12:49:23 -070054import java.io.IOException;
55import java.net.HttpURLConnection;
56import java.net.InetAddress;
57import java.net.Inet4Address;
Wink Savillebf341222013-08-02 11:25:23 -070058import java.net.SocketTimeoutException;
Irfan Sheriffda6da092012-08-16 12:49:23 -070059import java.net.URL;
60import java.net.UnknownHostException;
Brian Williammee1ed51622013-07-31 17:07:33 -070061import java.util.List;
Irfan Sheriffda6da092012-08-16 12:49:23 -070062
63import com.android.internal.R;
64
65/**
Irfan Sheriff9538bdd2012-09-20 09:32:41 -070066 * This class allows captive portal detection on a network.
Irfan Sheriffda6da092012-08-16 12:49:23 -070067 * @hide
68 */
Irfan Sheriff9538bdd2012-09-20 09:32:41 -070069public class CaptivePortalTracker extends StateMachine {
Wink Savillebf341222013-08-02 11:25:23 -070070 private static final boolean DBG = true;
Irfan Sheriffda6da092012-08-16 12:49:23 -070071 private static final String TAG = "CaptivePortalTracker";
72
73 private static final String DEFAULT_SERVER = "clients3.google.com";
74 private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
75
76 private static final int SOCKET_TIMEOUT_MS = 10000;
77
Brian Williammee1ed51622013-07-31 17:07:33 -070078 public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
79 "android.net.conn.NETWORK_CONDITIONS_MEASURED";
80 public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
81 public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
82 public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
83 public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
84 public static final String EXTRA_CELL_ID = "extra_cellid";
85 public static final String EXTRA_SSID = "extra_ssid";
86 public static final String EXTRA_BSSID = "extra_bssid";
87 /** real time since boot */
88 public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
89 public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
90
91 private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
92 "android.permission.ACCESS_NETWORK_CONDITIONS";
93
Irfan Sheriffda6da092012-08-16 12:49:23 -070094 private String mServer;
95 private String mUrl;
96 private boolean mNotificationShown = false;
97 private boolean mIsCaptivePortalCheckEnabled = false;
Irfan Sheriffda6da092012-08-16 12:49:23 -070098 private IConnectivityManager mConnService;
Irfan Sheriffb8aad91f2012-10-02 14:01:28 -070099 private TelephonyManager mTelephonyManager;
Brian Williammee1ed51622013-07-31 17:07:33 -0700100 private WifiManager mWifiManager;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700101 private Context mContext;
102 private NetworkInfo mNetworkInfo;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700103
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700104 private static final int CMD_DETECT_PORTAL = 0;
105 private static final int CMD_CONNECTIVITY_CHANGE = 1;
106 private static final int CMD_DELAYED_CAPTIVE_CHECK = 2;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700107
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700108 /* This delay happens every time before we do a captive check on a network */
109 private static final int DELAYED_CHECK_INTERVAL_MS = 10000;
110 private int mDelayedCheckToken = 0;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700111
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700112 private State mDefaultState = new DefaultState();
113 private State mNoActiveNetworkState = new NoActiveNetworkState();
114 private State mActiveNetworkState = new ActiveNetworkState();
115 private State mDelayedCaptiveCheckState = new DelayedCaptiveCheckState();
116
Russell Brenner108da0c2013-02-12 10:03:14 -0800117 private static final String SETUP_WIZARD_PACKAGE = "com.google.android.setupwizard";
118 private boolean mDeviceProvisioned = false;
119 private ProvisioningObserver mProvisioningObserver;
120
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700121 private CaptivePortalTracker(Context context, IConnectivityManager cs) {
122 super(TAG);
123
Irfan Sheriffda6da092012-08-16 12:49:23 -0700124 mContext = context;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700125 mConnService = cs;
Irfan Sheriffb8aad91f2012-10-02 14:01:28 -0700126 mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
Brian Williammee1ed51622013-07-31 17:07:33 -0700127 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Russell Brenner108da0c2013-02-12 10:03:14 -0800128 mProvisioningObserver = new ProvisioningObserver();
Irfan Sheriffda6da092012-08-16 12:49:23 -0700129
Irfan Sheriffda6da092012-08-16 12:49:23 -0700130 IntentFilter filter = new IntentFilter();
Irfan Sheriffda6da092012-08-16 12:49:23 -0700131 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
Russell Brenner108da0c2013-02-12 10:03:14 -0800132 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE);
Irfan Sheriffda6da092012-08-16 12:49:23 -0700133 mContext.registerReceiver(mReceiver, filter);
134
Jeff Sharkey625239a2012-09-26 22:03:49 -0700135 mServer = Settings.Global.getString(mContext.getContentResolver(),
136 Settings.Global.CAPTIVE_PORTAL_SERVER);
Irfan Sheriffda6da092012-08-16 12:49:23 -0700137 if (mServer == null) mServer = DEFAULT_SERVER;
138
Jeff Sharkey625239a2012-09-26 22:03:49 -0700139 mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
140 Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700141
142 addState(mDefaultState);
143 addState(mNoActiveNetworkState, mDefaultState);
144 addState(mActiveNetworkState, mDefaultState);
145 addState(mDelayedCaptiveCheckState, mActiveNetworkState);
146 setInitialState(mNoActiveNetworkState);
Irfan Sheriffda6da092012-08-16 12:49:23 -0700147 }
148
Russell Brenner108da0c2013-02-12 10:03:14 -0800149 private class ProvisioningObserver extends ContentObserver {
150 ProvisioningObserver() {
151 super(new Handler());
152 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
153 Settings.Global.DEVICE_PROVISIONED), false, this);
154 onChange(false); // load initial value
155 }
156
157 @Override
158 public void onChange(boolean selfChange) {
159 mDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
160 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
161 }
162 }
163
Irfan Sheriffda6da092012-08-16 12:49:23 -0700164 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
165 @Override
166 public void onReceive(Context context, Intent intent) {
167 String action = intent.getAction();
Russell Brenner108da0c2013-02-12 10:03:14 -0800168 // Normally, we respond to CONNECTIVITY_ACTION, allowing time for the change in
169 // connectivity to stabilize, but if the device is not yet provisioned, respond
170 // immediately to speed up transit through the setup wizard.
171 if ((mDeviceProvisioned && action.equals(ConnectivityManager.CONNECTIVITY_ACTION))
172 || (!mDeviceProvisioned
173 && action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE))) {
Irfan Sheriffda6da092012-08-16 12:49:23 -0700174 NetworkInfo info = intent.getParcelableExtra(
175 ConnectivityManager.EXTRA_NETWORK_INFO);
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700176 sendMessage(obtainMessage(CMD_CONNECTIVITY_CHANGE, info));
Irfan Sheriffda6da092012-08-16 12:49:23 -0700177 }
178 }
179 };
180
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700181 public static CaptivePortalTracker makeCaptivePortalTracker(Context context,
Irfan Sheriffda6da092012-08-16 12:49:23 -0700182 IConnectivityManager cs) {
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700183 CaptivePortalTracker captivePortal = new CaptivePortalTracker(context, cs);
184 captivePortal.start();
Irfan Sheriffda6da092012-08-16 12:49:23 -0700185 return captivePortal;
186 }
187
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700188 public void detectCaptivePortal(NetworkInfo info) {
189 sendMessage(obtainMessage(CMD_DETECT_PORTAL, info));
190 }
191
192 private class DefaultState extends State {
193 @Override
194 public void enter() {
195 if (DBG) log(getName() + "\n");
Irfan Sheriffda6da092012-08-16 12:49:23 -0700196 }
197
198 @Override
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700199 public boolean processMessage(Message message) {
200 if (DBG) log(getName() + message.toString() + "\n");
201 switch (message.what) {
202 case CMD_DETECT_PORTAL:
203 NetworkInfo info = (NetworkInfo) message.obj;
204 // Checking on a secondary connection is not supported
205 // yet
206 notifyPortalCheckComplete(info);
Irfan Sheriffda6da092012-08-16 12:49:23 -0700207 break;
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700208 case CMD_CONNECTIVITY_CHANGE:
209 case CMD_DELAYED_CAPTIVE_CHECK:
210 break;
211 default:
212 loge("Ignoring " + message);
213 break;
214 }
215 return HANDLED;
216 }
217 }
Irfan Sheriffda6da092012-08-16 12:49:23 -0700218
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700219 private class NoActiveNetworkState extends State {
220 @Override
221 public void enter() {
222 if (DBG) log(getName() + "\n");
223 mNetworkInfo = null;
224 /* Clear any previous notification */
225 setNotificationVisible(false);
226 }
Irfan Sheriffda6da092012-08-16 12:49:23 -0700227
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700228 @Override
229 public boolean processMessage(Message message) {
230 if (DBG) log(getName() + message.toString() + "\n");
231 InetAddress server;
232 NetworkInfo info;
233 switch (message.what) {
234 case CMD_CONNECTIVITY_CHANGE:
235 info = (NetworkInfo) message.obj;
236 if (info.isConnected() && isActiveNetwork(info)) {
237 mNetworkInfo = info;
238 transitionTo(mDelayedCaptiveCheckState);
Irfan Sheriffda6da092012-08-16 12:49:23 -0700239 }
240 break;
241 default:
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700242 return NOT_HANDLED;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700243 }
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700244 return HANDLED;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700245 }
246 }
247
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700248 private class ActiveNetworkState extends State {
249 @Override
250 public void enter() {
251 if (DBG) log(getName() + "\n");
252 }
253
254 @Override
255 public boolean processMessage(Message message) {
256 NetworkInfo info;
257 switch (message.what) {
258 case CMD_CONNECTIVITY_CHANGE:
259 info = (NetworkInfo) message.obj;
260 if (!info.isConnected()
261 && info.getType() == mNetworkInfo.getType()) {
262 if (DBG) log("Disconnected from active network " + info);
263 transitionTo(mNoActiveNetworkState);
264 } else if (info.getType() != mNetworkInfo.getType() &&
265 info.isConnected() &&
266 isActiveNetwork(info)) {
267 if (DBG) log("Active network switched " + info);
268 deferMessage(message);
269 transitionTo(mNoActiveNetworkState);
270 }
271 break;
272 default:
273 return NOT_HANDLED;
274 }
275 return HANDLED;
276 }
Irfan Sheriffda6da092012-08-16 12:49:23 -0700277 }
278
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700279
280
281 private class DelayedCaptiveCheckState extends State {
282 @Override
283 public void enter() {
284 if (DBG) log(getName() + "\n");
Russell Brenner108da0c2013-02-12 10:03:14 -0800285 Message message = obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0);
286 if (mDeviceProvisioned) {
287 sendMessageDelayed(message, DELAYED_CHECK_INTERVAL_MS);
288 } else {
289 sendMessage(message);
290 }
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700291 }
292
293 @Override
294 public boolean processMessage(Message message) {
295 if (DBG) log(getName() + message.toString() + "\n");
296 switch (message.what) {
297 case CMD_DELAYED_CAPTIVE_CHECK:
298 if (message.arg1 == mDelayedCheckToken) {
299 InetAddress server = lookupHost(mServer);
Russell Brenner108da0c2013-02-12 10:03:14 -0800300 boolean captive = server != null && isCaptivePortal(server);
301 if (captive) {
302 if (DBG) log("Captive network " + mNetworkInfo);
303 } else {
304 if (DBG) log("Not captive network " + mNetworkInfo);
305 }
306 if (mDeviceProvisioned) {
307 if (captive) {
308 // Setup Wizard will assist the user in connecting to a captive
309 // portal, so make the notification visible unless during setup
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700310 setNotificationVisible(true);
311 }
Russell Brenner108da0c2013-02-12 10:03:14 -0800312 } else {
313 Intent intent = new Intent(
314 ConnectivityManager.ACTION_CAPTIVE_PORTAL_TEST_COMPLETED);
315 intent.putExtra(ConnectivityManager.EXTRA_IS_CAPTIVE_PORTAL, captive);
316 intent.setPackage(SETUP_WIZARD_PACKAGE);
317 mContext.sendBroadcast(intent);
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700318 }
Russell Brenner108da0c2013-02-12 10:03:14 -0800319
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700320 transitionTo(mActiveNetworkState);
321 }
322 break;
323 default:
324 return NOT_HANDLED;
325 }
326 return HANDLED;
327 }
328 }
329
330 private void notifyPortalCheckComplete(NetworkInfo info) {
331 if (info == null) {
332 loge("notifyPortalCheckComplete on null");
333 return;
334 }
Irfan Sheriffda6da092012-08-16 12:49:23 -0700335 try {
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700336 mConnService.captivePortalCheckComplete(info);
Irfan Sheriffda6da092012-08-16 12:49:23 -0700337 } catch(RemoteException e) {
338 e.printStackTrace();
339 }
340 }
341
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700342 private boolean isActiveNetwork(NetworkInfo info) {
Irfan Sheriffda6da092012-08-16 12:49:23 -0700343 try {
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700344 NetworkInfo active = mConnService.getActiveNetworkInfo();
345 if (active != null && active.getType() == info.getType()) {
346 return true;
347 }
Irfan Sheriffda6da092012-08-16 12:49:23 -0700348 } catch (RemoteException e) {
349 e.printStackTrace();
350 }
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700351 return false;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700352 }
353
354 /**
Brian Williammee1ed51622013-07-31 17:07:33 -0700355 * Do a URL fetch on a known server to see if we get the data we expect.
356 * Measure the response time and broadcast that.
Irfan Sheriffda6da092012-08-16 12:49:23 -0700357 */
358 private boolean isCaptivePortal(InetAddress server) {
359 HttpURLConnection urlConnection = null;
360 if (!mIsCaptivePortalCheckEnabled) return false;
361
362 mUrl = "http://" + server.getHostAddress() + "/generate_204";
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700363 if (DBG) log("Checking " + mUrl);
Brian Williammee1ed51622013-07-31 17:07:33 -0700364 long requestTimestamp = -1;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700365 try {
366 URL url = new URL(mUrl);
367 urlConnection = (HttpURLConnection) url.openConnection();
368 urlConnection.setInstanceFollowRedirects(false);
369 urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
370 urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
371 urlConnection.setUseCaches(false);
Brian Williammee1ed51622013-07-31 17:07:33 -0700372
373 // Time how long it takes to get a response to our request
374 requestTimestamp = SystemClock.elapsedRealtime();
375
Irfan Sheriffda6da092012-08-16 12:49:23 -0700376 urlConnection.getInputStream();
Brian Williammee1ed51622013-07-31 17:07:33 -0700377
378 // Time how long it takes to get a response to our request
379 long responseTimestamp = SystemClock.elapsedRealtime();
380
Irfan Sheriffda6da092012-08-16 12:49:23 -0700381 // we got a valid response, but not from the real google
Brian Williammee1ed51622013-07-31 17:07:33 -0700382 boolean isCaptivePortal = urlConnection.getResponseCode() != 204;
383
384 sendNetworkConditionsBroadcast(true /* response received */, isCaptivePortal,
385 requestTimestamp, responseTimestamp);
386 return isCaptivePortal;
Wink Savillebf341222013-08-02 11:25:23 -0700387 } catch (SocketTimeoutException e) {
388 if (DBG) log("Probably a portal: exception " + e);
Wink Savillef35f3202013-08-08 16:51:46 -0700389 if (requestTimestamp != -1) {
390 sendFailedCaptivePortalCheckBroadcast(requestTimestamp);
391 } // else something went wrong with setting up the urlConnection
Wink Savillebf341222013-08-02 11:25:23 -0700392 return true;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700393 } catch (IOException e) {
394 if (DBG) log("Probably not a portal: exception " + e);
Brian Williammee1ed51622013-07-31 17:07:33 -0700395 if (requestTimestamp != -1) {
396 sendFailedCaptivePortalCheckBroadcast(requestTimestamp);
397 } // else something went wrong with setting up the urlConnection
Irfan Sheriffda6da092012-08-16 12:49:23 -0700398 return false;
399 } finally {
400 if (urlConnection != null) {
401 urlConnection.disconnect();
402 }
403 }
404 }
405
406 private InetAddress lookupHost(String hostname) {
407 InetAddress inetAddress[];
408 try {
409 inetAddress = InetAddress.getAllByName(hostname);
410 } catch (UnknownHostException e) {
Brian Williammee1ed51622013-07-31 17:07:33 -0700411 sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime());
Irfan Sheriffda6da092012-08-16 12:49:23 -0700412 return null;
413 }
414
415 for (InetAddress a : inetAddress) {
416 if (a instanceof Inet4Address) return a;
417 }
Brian Williammee1ed51622013-07-31 17:07:33 -0700418
419 sendFailedCaptivePortalCheckBroadcast(SystemClock.elapsedRealtime());
Irfan Sheriffda6da092012-08-16 12:49:23 -0700420 return null;
421 }
422
423 private void setNotificationVisible(boolean visible) {
424 // if it should be hidden and it is already hidden, then noop
425 if (!visible && !mNotificationShown) {
Wink Saville42d4f082013-07-20 20:31:59 -0700426 if (DBG) log("setNotivicationVisible: false and not shown, so noop");
Irfan Sheriffda6da092012-08-16 12:49:23 -0700427 return;
428 }
429
430 Resources r = Resources.getSystem();
431 NotificationManager notificationManager = (NotificationManager) mContext
432 .getSystemService(Context.NOTIFICATION_SERVICE);
433
434 if (visible) {
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700435 CharSequence title;
Irfan Sheriffb8aad91f2012-10-02 14:01:28 -0700436 CharSequence details;
Irfan Sheriffebb8f412012-10-02 16:12:05 -0700437 int icon;
Wink Saville42d4f082013-07-20 20:31:59 -0700438 String url = null;
Irfan Sheriffb8aad91f2012-10-02 14:01:28 -0700439 switch (mNetworkInfo.getType()) {
440 case ConnectivityManager.TYPE_WIFI:
441 title = r.getString(R.string.wifi_available_sign_in, 0);
442 details = r.getString(R.string.network_available_sign_in_detailed,
443 mNetworkInfo.getExtraInfo());
Irfan Sheriffebb8f412012-10-02 16:12:05 -0700444 icon = R.drawable.stat_notify_wifi_in_range;
Wink Saville42d4f082013-07-20 20:31:59 -0700445 url = mUrl;
Irfan Sheriffb8aad91f2012-10-02 14:01:28 -0700446 break;
447 case ConnectivityManager.TYPE_MOBILE:
448 title = r.getString(R.string.network_available_sign_in, 0);
449 // TODO: Change this to pull from NetworkInfo once a printable
450 // name has been added to it
451 details = mTelephonyManager.getNetworkOperatorName();
Irfan Sheriffebb8f412012-10-02 16:12:05 -0700452 icon = R.drawable.stat_notify_rssi_in_range;
Wink Saville42d4f082013-07-20 20:31:59 -0700453 try {
454 url = mConnService.getMobileProvisioningUrl();
455 if (TextUtils.isEmpty(url)) {
456 url = mConnService.getMobileRedirectedProvisioningUrl();
457 }
458 } catch(RemoteException e) {
459 e.printStackTrace();
460 }
461 if (TextUtils.isEmpty(url)) {
462 url = mUrl;
463 }
Irfan Sheriffb8aad91f2012-10-02 14:01:28 -0700464 break;
465 default:
466 title = r.getString(R.string.network_available_sign_in, 0);
467 details = r.getString(R.string.network_available_sign_in_detailed,
468 mNetworkInfo.getExtraInfo());
Irfan Sheriffebb8f412012-10-02 16:12:05 -0700469 icon = R.drawable.stat_notify_rssi_in_range;
Wink Saville42d4f082013-07-20 20:31:59 -0700470 url = mUrl;
Irfan Sheriffb8aad91f2012-10-02 14:01:28 -0700471 break;
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700472 }
Irfan Sheriffda6da092012-08-16 12:49:23 -0700473
474 Notification notification = new Notification();
475 notification.when = 0;
Irfan Sheriffebb8f412012-10-02 16:12:05 -0700476 notification.icon = icon;
Irfan Sheriffda6da092012-08-16 12:49:23 -0700477 notification.flags = Notification.FLAG_AUTO_CANCEL;
Wink Saville42d4f082013-07-20 20:31:59 -0700478 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
Irfan Sheriff9538bdd2012-09-20 09:32:41 -0700479 intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
480 Intent.FLAG_ACTIVITY_NEW_TASK);
481 notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
Irfan Sheriffda6da092012-08-16 12:49:23 -0700482 notification.tickerText = title;
483 notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
484
Wink Saville42d4f082013-07-20 20:31:59 -0700485 if (DBG) log("setNotivicationVisible: make visible");
Irfan Sheriffda6da092012-08-16 12:49:23 -0700486 notificationManager.notify(NOTIFICATION_ID, 1, notification);
487 } else {
Wink Saville42d4f082013-07-20 20:31:59 -0700488 if (DBG) log("setNotivicationVisible: cancel notification");
Irfan Sheriffda6da092012-08-16 12:49:23 -0700489 notificationManager.cancel(NOTIFICATION_ID, 1);
490 }
491 mNotificationShown = visible;
492 }
Brian Williammee1ed51622013-07-31 17:07:33 -0700493
494 private void sendFailedCaptivePortalCheckBroadcast(long requestTimestampMs) {
495 sendNetworkConditionsBroadcast(false /* response received */, false /* ignored */,
496 requestTimestampMs, 0 /* ignored */);
497 }
498
499 /**
500 * @param responseReceived - whether or not we received a valid HTTP response to our request.
501 * If false, isCaptivePortal and responseTimestampMs are ignored
502 */
503 private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
504 long requestTimestampMs, long responseTimestampMs) {
505 if (Settings.Global.getInt(mContext.getContentResolver(),
506 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 0) {
507 if (DBG) log("Don't send network conditions - lacking user consent.");
508 return;
509 }
510
511 Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
512 switch (mNetworkInfo.getType()) {
513 case ConnectivityManager.TYPE_WIFI:
514 WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
515 if (currentWifiInfo != null) {
516 latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
517 latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
518 } else {
519 if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
520 return;
521 }
522 break;
523 case ConnectivityManager.TYPE_MOBILE:
524 latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType());
525 List<CellInfo> info = mTelephonyManager.getAllCellInfo();
526 if (info == null) return;
527 StringBuffer uniqueCellId = new StringBuffer();
528 int numRegisteredCellInfo = 0;
529 for (CellInfo cellInfo : info) {
530 if (cellInfo.isRegistered()) {
531 numRegisteredCellInfo++;
532 if (numRegisteredCellInfo > 1) {
533 if (DBG) log("more than one registered CellInfo. Can't " +
534 "tell which is active. Bailing.");
535 return;
536 }
537 if (cellInfo instanceof CellInfoCdma) {
538 CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
539 latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
540 } else if (cellInfo instanceof CellInfoGsm) {
541 CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
542 latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
543 } else if (cellInfo instanceof CellInfoLte) {
544 CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
545 latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
546 } else if (cellInfo instanceof CellInfoWcdma) {
547 CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
548 latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
549 } else {
550 if (DBG) logw("Registered cellinfo is unrecognized");
551 return;
552 }
553 }
554 }
555 break;
556 default:
557 return;
558 }
559 latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkInfo.getType());
560 latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived);
561 latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs);
562
563 if (responseReceived) {
564 latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
565 latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
566 }
567 mContext.sendBroadcast(latencyBroadcast, PERMISSION_ACCESS_NETWORK_CONDITIONS);
568 }
Irfan Sheriffda6da092012-08-16 12:49:23 -0700569}