OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.net; | 5 package org.chromium.net; |
6 | 6 |
7 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; | 7 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; |
8 | 8 |
9 import android.Manifest.permission; | 9 import android.Manifest.permission; |
10 import android.annotation.SuppressLint; | 10 import android.annotation.SuppressLint; |
11 import android.content.BroadcastReceiver; | 11 import android.content.BroadcastReceiver; |
12 import android.content.Context; | 12 import android.content.Context; |
13 import android.content.Intent; | 13 import android.content.Intent; |
14 import android.content.IntentFilter; | 14 import android.content.IntentFilter; |
15 import android.content.pm.PackageManager; | 15 import android.content.pm.PackageManager; |
16 import android.net.ConnectivityManager; | 16 import android.net.ConnectivityManager; |
17 import android.net.ConnectivityManager.NetworkCallback; | 17 import android.net.ConnectivityManager.NetworkCallback; |
18 import android.net.Network; | 18 import android.net.Network; |
19 import android.net.NetworkCapabilities; | 19 import android.net.NetworkCapabilities; |
20 import android.net.NetworkInfo; | 20 import android.net.NetworkInfo; |
21 import android.net.NetworkRequest; | 21 import android.net.NetworkRequest; |
22 import android.net.wifi.WifiInfo; | 22 import android.net.wifi.WifiInfo; |
23 import android.net.wifi.WifiManager; | 23 import android.net.wifi.WifiManager; |
24 import android.os.Build; | 24 import android.os.Build; |
25 import android.telephony.TelephonyManager; | 25 import android.telephony.TelephonyManager; |
26 import android.util.Log; | 26 import android.util.Log; |
27 | 27 |
28 import org.chromium.base.ApplicationState; | |
29 import org.chromium.base.ApplicationStatus; | |
30 import org.chromium.base.ThreadUtils; | 28 import org.chromium.base.ThreadUtils; |
31 import org.chromium.base.VisibleForTesting; | 29 import org.chromium.base.VisibleForTesting; |
32 | 30 |
33 /** | 31 /** |
34 * Used by the NetworkChangeNotifier to listens to platform changes in connectiv
ity. | 32 * Used by the NetworkChangeNotifier to listens to platform changes in connectiv
ity. |
35 * Note that use of this class requires that the app have the platform | 33 * Note that use of this class requires that the app have the platform |
36 * ACCESS_NETWORK_STATE permission. | 34 * ACCESS_NETWORK_STATE permission. |
37 */ | 35 */ |
38 public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver | 36 public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver { |
39 implements ApplicationStatus.ApplicationStateListener { | |
40 | |
41 static class NetworkState { | 37 static class NetworkState { |
42 private final boolean mConnected; | 38 private final boolean mConnected; |
43 private final int mType; | 39 private final int mType; |
44 private final int mSubtype; | 40 private final int mSubtype; |
45 | 41 |
46 public NetworkState(boolean connected, int type, int subtype) { | 42 public NetworkState(boolean connected, int type, int subtype) { |
47 mConnected = connected; | 43 mConnected = connected; |
48 mType = type; | 44 mType = type; |
49 mSubtype = subtype; | 45 mSubtype = subtype; |
50 } | 46 } |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 final int netId = networkToNetId(network); | 289 final int netId = networkToNetId(network); |
294 ThreadUtils.postOnUiThread(new Runnable() { | 290 ThreadUtils.postOnUiThread(new Runnable() { |
295 @Override | 291 @Override |
296 public void run() { | 292 public void run() { |
297 mObserver.onNetworkDisconnect(netId); | 293 mObserver.onNetworkDisconnect(netId); |
298 } | 294 } |
299 }); | 295 }); |
300 } | 296 } |
301 } | 297 } |
302 | 298 |
| 299 /** |
| 300 * Abstract class for providing a policy regarding when the NetworkChangeNot
ifier |
| 301 * should listen for network changes. |
| 302 */ |
| 303 public abstract static class RegistrationPolicy { |
| 304 private NetworkChangeNotifierAutoDetect mNotifier; |
| 305 |
| 306 /** |
| 307 * Start listening for network changes. |
| 308 */ |
| 309 protected final void register() { |
| 310 assert mNotifier != null; |
| 311 mNotifier.register(); |
| 312 } |
| 313 |
| 314 /** |
| 315 * Stop listening for network changes. |
| 316 */ |
| 317 protected final void unregister() { |
| 318 assert mNotifier != null; |
| 319 mNotifier.unregister(); |
| 320 } |
| 321 |
| 322 /** |
| 323 * Initializes the policy with the notifier, overriding subclasses shoul
d always |
| 324 * call this method. |
| 325 */ |
| 326 protected void init(NetworkChangeNotifierAutoDetect notifier) { |
| 327 mNotifier = notifier; |
| 328 } |
| 329 |
| 330 protected abstract void destroy(); |
| 331 } |
| 332 |
303 private static final String TAG = "NetworkChangeNotifierAutoDetect"; | 333 private static final String TAG = "NetworkChangeNotifierAutoDetect"; |
304 private static final int UNKNOWN_LINK_SPEED = -1; | 334 private static final int UNKNOWN_LINK_SPEED = -1; |
| 335 |
305 private final NetworkConnectivityIntentFilter mIntentFilter; | 336 private final NetworkConnectivityIntentFilter mIntentFilter; |
| 337 private final Observer mObserver; |
| 338 private final Context mContext; |
| 339 private final RegistrationPolicy mRegistrationPolicy; |
306 | 340 |
307 private final Observer mObserver; | |
308 | |
309 private final Context mContext; | |
310 // mConnectivityManagerDelegates and mWifiManagerDelegate are only non-final
for testing. | 341 // mConnectivityManagerDelegates and mWifiManagerDelegate are only non-final
for testing. |
311 private ConnectivityManagerDelegate mConnectivityManagerDelegate; | 342 private ConnectivityManagerDelegate mConnectivityManagerDelegate; |
312 private WifiManagerDelegate mWifiManagerDelegate; | 343 private WifiManagerDelegate mWifiManagerDelegate; |
313 // mNetworkCallback and mNetworkRequest are only non-null in Android L and a
bove. | 344 // mNetworkCallback and mNetworkRequest are only non-null in Android L and a
bove. |
314 private final NetworkCallback mNetworkCallback; | 345 private final NetworkCallback mNetworkCallback; |
315 private final NetworkRequest mNetworkRequest; | 346 private final NetworkRequest mNetworkRequest; |
316 private boolean mRegistered; | 347 private boolean mRegistered; |
317 private final boolean mApplicationStateRegistered; | |
318 private int mConnectionType; | 348 private int mConnectionType; |
319 private String mWifiSSID; | 349 private String mWifiSSID; |
320 private double mMaxBandwidthMbps; | 350 private double mMaxBandwidthMbps; |
321 | 351 |
322 /** | 352 /** |
323 * Observer interface by which observer is notified of network changes. | 353 * Observer interface by which observer is notified of network changes. |
324 */ | 354 */ |
325 public static interface Observer { | 355 public static interface Observer { |
326 /** | 356 /** |
327 * Called when default network changes. | 357 * Called when default network changes. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 public void updateActiveNetworkList(int[] activeNetIds); | 392 public void updateActiveNetworkList(int[] activeNetIds); |
363 } | 393 } |
364 | 394 |
365 /** | 395 /** |
366 * Constructs a NetworkChangeNotifierAutoDetect. Should only be called on UI
thread. | 396 * Constructs a NetworkChangeNotifierAutoDetect. Should only be called on UI
thread. |
367 * @param alwaysWatchForChanges If true, always watch for network changes. | 397 * @param alwaysWatchForChanges If true, always watch for network changes. |
368 * Otherwise, only watch if app is in foreground. | 398 * Otherwise, only watch if app is in foreground. |
369 */ | 399 */ |
370 @SuppressLint("NewApi") | 400 @SuppressLint("NewApi") |
371 public NetworkChangeNotifierAutoDetect( | 401 public NetworkChangeNotifierAutoDetect( |
372 Observer observer, Context context, boolean alwaysWatchForChanges) { | 402 Observer observer, Context context, RegistrationPolicy policy) { |
373 // Since BroadcastReceiver is always called back on UI thread, ensure | 403 // Since BroadcastReceiver is always called back on UI thread, ensure |
374 // running on UI thread so notification logic can be single-threaded. | 404 // running on UI thread so notification logic can be single-threaded. |
375 ThreadUtils.assertOnUiThread(); | 405 ThreadUtils.assertOnUiThread(); |
376 mObserver = observer; | 406 mObserver = observer; |
377 mContext = context.getApplicationContext(); | 407 mContext = context.getApplicationContext(); |
378 mConnectivityManagerDelegate = new ConnectivityManagerDelegate(context); | 408 mConnectivityManagerDelegate = new ConnectivityManagerDelegate(context); |
379 mWifiManagerDelegate = new WifiManagerDelegate(context); | 409 mWifiManagerDelegate = new WifiManagerDelegate(context); |
380 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | 410 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
381 mNetworkCallback = new MyNetworkCallback(); | 411 mNetworkCallback = new MyNetworkCallback(); |
382 mNetworkRequest = | 412 mNetworkRequest = |
383 new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IN
TERNET).build(); | 413 new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IN
TERNET).build(); |
384 } else { | 414 } else { |
385 mNetworkCallback = null; | 415 mNetworkCallback = null; |
386 mNetworkRequest = null; | 416 mNetworkRequest = null; |
387 } | 417 } |
388 final NetworkState networkState = mConnectivityManagerDelegate.getNetwor
kState(); | 418 final NetworkState networkState = mConnectivityManagerDelegate.getNetwor
kState(); |
389 mConnectionType = getCurrentConnectionType(networkState); | 419 mConnectionType = getCurrentConnectionType(networkState); |
390 mWifiSSID = getCurrentWifiSSID(networkState); | 420 mWifiSSID = getCurrentWifiSSID(networkState); |
391 mMaxBandwidthMbps = getCurrentMaxBandwidthInMbps(networkState); | 421 mMaxBandwidthMbps = getCurrentMaxBandwidthInMbps(networkState); |
392 mIntentFilter = | 422 mIntentFilter = |
393 new NetworkConnectivityIntentFilter(mWifiManagerDelegate.getHasW
ifiPermission()); | 423 new NetworkConnectivityIntentFilter(mWifiManagerDelegate.getHasW
ifiPermission()); |
394 | 424 mRegistrationPolicy = policy; |
395 if (alwaysWatchForChanges) { | 425 mRegistrationPolicy.init(this); |
396 registerReceiver(); | |
397 mApplicationStateRegistered = false; | |
398 } else { | |
399 ApplicationStatus.registerApplicationStateListener(this); | |
400 onApplicationStateChange(getApplicationState()); | |
401 mApplicationStateRegistered = true; | |
402 } | |
403 } | 426 } |
404 | 427 |
405 /** | 428 /** |
406 * Allows overriding the ConnectivityManagerDelegate for tests. | 429 * Allows overriding the ConnectivityManagerDelegate for tests. |
407 */ | 430 */ |
408 void setConnectivityManagerDelegateForTests(ConnectivityManagerDelegate dele
gate) { | 431 void setConnectivityManagerDelegateForTests(ConnectivityManagerDelegate dele
gate) { |
409 mConnectivityManagerDelegate = delegate; | 432 mConnectivityManagerDelegate = delegate; |
410 } | 433 } |
411 | 434 |
412 /** | 435 /** |
413 * Allows overriding the WifiManagerDelegate for tests. | 436 * Allows overriding the WifiManagerDelegate for tests. |
414 */ | 437 */ |
415 void setWifiManagerDelegateForTests(WifiManagerDelegate delegate) { | 438 void setWifiManagerDelegateForTests(WifiManagerDelegate delegate) { |
416 mWifiManagerDelegate = delegate; | 439 mWifiManagerDelegate = delegate; |
417 } | 440 } |
418 | 441 |
419 /** | |
420 * Returns the activity's status. | |
421 * @return an {@code int} that is one of {@code ApplicationState.HAS_*_ACTIV
ITIES}. | |
422 */ | |
423 @VisibleForTesting | 442 @VisibleForTesting |
424 int getApplicationState() { | 443 RegistrationPolicy getRegistrationPolicy() { |
425 return ApplicationStatus.getStateForApplication(); | 444 return mRegistrationPolicy; |
426 } | 445 } |
427 | 446 |
428 /** | 447 /** |
429 * Returns whether the object has registered to receive network connectivity
intents. | 448 * Returns whether the object has registered to receive network connectivity
intents. |
430 */ | 449 */ |
431 @VisibleForTesting | 450 @VisibleForTesting |
432 boolean isReceiverRegisteredForTesting() { | 451 boolean isReceiverRegisteredForTesting() { |
433 return mRegistered; | 452 return mRegistered; |
434 } | 453 } |
435 | 454 |
436 public void destroy() { | 455 public void destroy() { |
437 if (mApplicationStateRegistered) ApplicationStatus.unregisterApplication
StateListener(this); | 456 mRegistrationPolicy.destroy(); |
438 unregisterReceiver(); | 457 unregister(); |
439 } | 458 } |
440 | 459 |
441 /** | 460 /** |
442 * Registers a BroadcastReceiver in the given context. | 461 * Registers a BroadcastReceiver in the given context. |
443 */ | 462 */ |
444 private void registerReceiver() { | 463 public void register() { |
445 if (!mRegistered) { | 464 if (mRegistered) return; |
446 mRegistered = true; | 465 |
447 mContext.registerReceiver(this, mIntentFilter); | 466 final NetworkState networkState = getCurrentNetworkState(); |
448 if (mNetworkCallback != null) { | 467 connectionTypeChanged(networkState); |
449 mConnectivityManagerDelegate.registerNetworkCallback( | 468 maxBandwidthChanged(networkState); |
450 mNetworkRequest, mNetworkCallback); | 469 mContext.registerReceiver(this, mIntentFilter); |
451 // registerNetworkCallback() will rematch our NetworkRequest | 470 mRegistered = true; |
452 // against active networks, so a cached list of active networks | 471 |
453 // will be repopulated immediatly after this. However we need to | 472 if (mNetworkCallback != null) { |
454 // purge any cached networks as they may have been disconnected | 473 mConnectivityManagerDelegate.registerNetworkCallback(mNetworkRequest
, mNetworkCallback); |
455 // while mNetworkCallback was unregistered. | 474 // registerNetworkCallback() will rematch our NetworkRequest |
456 final Network[] networks = mConnectivityManagerDelegate.getAllNe
tworks(); | 475 // against active networks, so a cached list of active networks |
457 // Convert Networks to NetIDs. | 476 // will be repopulated immediatly after this. However we need to |
458 final int[] netIds = new int[networks.length]; | 477 // purge any cached networks as they may have been disconnected |
459 for (int i = 0; i < networks.length; i++) { | 478 // while mNetworkCallback was unregistered. |
460 netIds[i] = networkToNetId(networks[i]); | 479 final Network[] networks = mConnectivityManagerDelegate.getAllNetwor
ks(); |
461 } | 480 // Convert Networks to NetIDs. |
462 mObserver.updateActiveNetworkList(netIds); | 481 final int[] netIds = new int[networks.length]; |
| 482 for (int i = 0; i < networks.length; i++) { |
| 483 netIds[i] = networkToNetId(networks[i]); |
463 } | 484 } |
| 485 mObserver.updateActiveNetworkList(netIds); |
464 } | 486 } |
465 } | 487 } |
466 | 488 |
467 /** | 489 /** |
468 * Unregisters the BroadcastReceiver in the given context. | 490 * Unregisters a BroadcastReceiver in the given context. |
469 */ | 491 */ |
470 private void unregisterReceiver() { | 492 public void unregister() { |
471 if (mRegistered) { | 493 if (!mRegistered) return; |
472 mRegistered = false; | 494 mContext.unregisterReceiver(this); |
473 mContext.unregisterReceiver(this); | 495 mRegistered = false; |
474 if (mNetworkCallback != null) { | 496 if (mNetworkCallback != null) { |
475 mConnectivityManagerDelegate.unregisterNetworkCallback(mNetworkC
allback); | 497 mConnectivityManagerDelegate.unregisterNetworkCallback(mNetworkCallb
ack); |
476 } | |
477 } | 498 } |
478 } | 499 } |
479 | 500 |
480 public NetworkState getCurrentNetworkState() { | 501 public NetworkState getCurrentNetworkState() { |
481 return mConnectivityManagerDelegate.getNetworkState(); | 502 return mConnectivityManagerDelegate.getNetworkState(); |
482 } | 503 } |
483 | 504 |
484 /** | 505 /** |
485 * Returns an array of all of the device's currently connected | 506 * Returns an array of all of the device's currently connected |
486 * networks and ConnectionTypes. Array elements are a repeated sequence of: | 507 * networks and ConnectionTypes. Array elements are a repeated sequence of: |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 public void onReceive(Context context, Intent intent) { | 666 public void onReceive(Context context, Intent intent) { |
646 final NetworkState networkState = getCurrentNetworkState(); | 667 final NetworkState networkState = getCurrentNetworkState(); |
647 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
{ | 668 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
{ |
648 connectionTypeChanged(networkState); | 669 connectionTypeChanged(networkState); |
649 maxBandwidthChanged(networkState); | 670 maxBandwidthChanged(networkState); |
650 } else if (WifiManager.RSSI_CHANGED_ACTION.equals(intent.getAction())) { | 671 } else if (WifiManager.RSSI_CHANGED_ACTION.equals(intent.getAction())) { |
651 maxBandwidthChanged(networkState); | 672 maxBandwidthChanged(networkState); |
652 } | 673 } |
653 } | 674 } |
654 | 675 |
655 // ApplicationStatus.ApplicationStateListener | |
656 @Override | |
657 public void onApplicationStateChange(int newState) { | |
658 final NetworkState networkState = getCurrentNetworkState(); | |
659 if (newState == ApplicationState.HAS_RUNNING_ACTIVITIES) { | |
660 connectionTypeChanged(networkState); | |
661 maxBandwidthChanged(networkState); | |
662 registerReceiver(); | |
663 } else if (newState == ApplicationState.HAS_PAUSED_ACTIVITIES) { | |
664 unregisterReceiver(); | |
665 } | |
666 } | |
667 | |
668 private void connectionTypeChanged(NetworkState networkState) { | 676 private void connectionTypeChanged(NetworkState networkState) { |
669 int newConnectionType = getCurrentConnectionType(networkState); | 677 int newConnectionType = getCurrentConnectionType(networkState); |
670 String newWifiSSID = getCurrentWifiSSID(networkState); | 678 String newWifiSSID = getCurrentWifiSSID(networkState); |
671 if (newConnectionType == mConnectionType && newWifiSSID.equals(mWifiSSID
)) return; | 679 if (newConnectionType == mConnectionType && newWifiSSID.equals(mWifiSSID
)) return; |
672 | 680 |
673 mConnectionType = newConnectionType; | 681 mConnectionType = newConnectionType; |
674 mWifiSSID = newWifiSSID; | 682 mWifiSSID = newWifiSSID; |
675 Log.d(TAG, "Network connectivity changed, type is: " + mConnectionType); | 683 Log.d(TAG, "Network connectivity changed, type is: " + mConnectionType); |
676 mObserver.onConnectionTypeChanged(newConnectionType); | 684 mObserver.onConnectionTypeChanged(newConnectionType); |
677 } | 685 } |
(...skipping 16 matching lines...) Expand all Loading... |
694 * Extracts NetID of network. Only available on Lollipop and newer releases. | 702 * Extracts NetID of network. Only available on Lollipop and newer releases. |
695 */ | 703 */ |
696 @SuppressLint("NewApi") | 704 @SuppressLint("NewApi") |
697 private static int networkToNetId(Network network) { | 705 private static int networkToNetId(Network network) { |
698 // NOTE(pauljensen): This depends on Android framework implementation de
tails. | 706 // NOTE(pauljensen): This depends on Android framework implementation de
tails. |
699 // Fortunately this functionality is unlikely to ever change. | 707 // Fortunately this functionality is unlikely to ever change. |
700 // TODO(pauljensen): When we update to Android M SDK, use Network.getNet
workHandle(). | 708 // TODO(pauljensen): When we update to Android M SDK, use Network.getNet
workHandle(). |
701 return Integer.parseInt(network.toString()); | 709 return Integer.parseInt(network.toString()); |
702 } | 710 } |
703 } | 711 } |
OLD | NEW |