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
3 // found in the LICENSE file.
5 package org.chromium.net;
7 import android.content.Context;
9 import org.chromium.base.CalledByNative;
10 import org.chromium.base.JNINamespace;
11 import org.chromium.base.NativeClassQualifiedName;
12 import org.chromium.base.ObserverList;
14 import java.util.ArrayList;
17 * Triggers updates to the underlying network state in Chrome.
19 * By default, connectivity is assumed and changes must pushed from the embedder via the
20 * forceConnectivityState function.
21 * Embedders may choose to have this class auto-detect changes in network connectivity by invoking
22 * the setAutoDetectConnectivityState function.
24 * WARNING: This class is not thread-safe.
27 public class NetworkChangeNotifier {
29 * Alerted when the connection type of the network changes.
30 * The alert is fired on the UI thread.
32 public interface ConnectionTypeObserver {
33 public void onConnectionTypeChanged(int connectionType);
36 // These constants must always match the ones in network_change_notifier.h.
37 public static final int CONNECTION_UNKNOWN = 0;
38 public static final int CONNECTION_ETHERNET = 1;
39 public static final int CONNECTION_WIFI = 2;
40 public static final int CONNECTION_2G = 3;
41 public static final int CONNECTION_3G = 4;
42 public static final int CONNECTION_4G = 5;
43 public static final int CONNECTION_NONE = 6;
44 public static final int CONNECTION_BLUETOOTH = 7;
46 private final Context mContext;
47 private final ArrayList<Long> mNativeChangeNotifiers;
48 private final ObserverList<ConnectionTypeObserver> mConnectionTypeObservers;
49 private NetworkChangeNotifierAutoDetect mAutoDetector;
50 private int mCurrentConnectionType = CONNECTION_UNKNOWN;
52 private static NetworkChangeNotifier sInstance;
54 private NetworkChangeNotifier(Context context) {
55 mContext = context.getApplicationContext();
56 mNativeChangeNotifiers = new ArrayList<Long>();
57 mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>();
61 * Initializes the singleton once.
64 public static NetworkChangeNotifier init(Context context) {
65 if (sInstance == null) {
66 sInstance = new NetworkChangeNotifier(context);
71 public static boolean isInitialized() {
72 return sInstance != null;
75 static void resetInstanceForTests(Context context) {
76 sInstance = new NetworkChangeNotifier(context);
80 public int getCurrentConnectionType() {
81 return mCurrentConnectionType;
85 * Adds a native-side observer.
88 public void addNativeObserver(long nativeChangeNotifier) {
89 mNativeChangeNotifiers.add(nativeChangeNotifier);
93 * Removes a native-side observer.
96 public void removeNativeObserver(long nativeChangeNotifier) {
97 mNativeChangeNotifiers.remove(nativeChangeNotifier);
101 * Returns the singleton instance.
103 public static NetworkChangeNotifier getInstance() {
104 assert sInstance != null;
109 * Enables auto detection of the current network state based on notifications from the system.
110 * Note that passing true here requires the embedding app have the platform ACCESS_NETWORK_STATE
113 * @param shouldAutoDetect true if the NetworkChangeNotifier should listen for system changes in
114 * network connectivity.
116 public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
117 getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect, false);
120 private void destroyAutoDetector() {
121 if (mAutoDetector != null) {
122 mAutoDetector.destroy();
123 mAutoDetector = null;
128 * Registers to always receive network change notifications no matter if
129 * the app is in the background or foreground.
130 * Note that in normal circumstances, chrome embedders should use
131 * {@code setAutoDetectConnectivityState} to listen to network changes only
132 * when the app is in the foreground, because network change observers
133 * might perform expensive work depending on the network connectivity.
135 public static void registerToReceiveNotificationsAlways() {
136 getInstance().setAutoDetectConnectivityStateInternal(true, true);
139 private void setAutoDetectConnectivityStateInternal(
140 boolean shouldAutoDetect, boolean alwaysWatchForChanges) {
141 if (shouldAutoDetect) {
142 if (mAutoDetector == null) {
143 mAutoDetector = new NetworkChangeNotifierAutoDetect(
144 new NetworkChangeNotifierAutoDetect.Observer() {
146 public void onConnectionTypeChanged(int newConnectionType) {
147 updateCurrentConnectionType(newConnectionType);
151 alwaysWatchForChanges);
152 updateCurrentConnectionType(mAutoDetector.getCurrentConnectionType());
155 destroyAutoDetector();
160 * Updates the perceived network state when not auto-detecting changes to connectivity.
162 * @param networkAvailable True if the NetworkChangeNotifier should perceive a "connected"
163 * state, false implies "disconnected".
166 public static void forceConnectivityState(boolean networkAvailable) {
167 setAutoDetectConnectivityState(false);
168 getInstance().forceConnectivityStateInternal(networkAvailable);
171 private void forceConnectivityStateInternal(boolean forceOnline) {
172 boolean connectionCurrentlyExists = mCurrentConnectionType != CONNECTION_NONE;
173 if (connectionCurrentlyExists != forceOnline) {
174 updateCurrentConnectionType(forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE);
178 private void updateCurrentConnectionType(int newConnectionType) {
179 mCurrentConnectionType = newConnectionType;
180 notifyObserversOfConnectionTypeChange(newConnectionType);
184 * Alerts all observers of a connection change.
186 void notifyObserversOfConnectionTypeChange(int newConnectionType) {
187 for (Long nativeChangeNotifier : mNativeChangeNotifiers) {
188 nativeNotifyConnectionTypeChanged(nativeChangeNotifier, newConnectionType);
190 for (ConnectionTypeObserver observer : mConnectionTypeObservers) {
191 observer.onConnectionTypeChanged(newConnectionType);
196 * Adds an observer for any connection type changes.
198 public static void addConnectionTypeObserver(ConnectionTypeObserver observer) {
199 getInstance().addConnectionTypeObserverInternal(observer);
202 private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
203 mConnectionTypeObservers.addObserver(observer);
207 * Removes an observer for any connection type changes.
209 public static void removeConnectionTypeObserver(ConnectionTypeObserver observer) {
210 getInstance().removeConnectionTypeObserverInternal(observer);
213 private void removeConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
214 mConnectionTypeObservers.removeObserver(observer);
217 @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid")
218 private native void nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType);
221 public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() {
222 return getInstance().mAutoDetector;
226 * Checks if there currently is connectivity.
228 public static boolean isOnline() {
229 int connectionType = getInstance().getCurrentConnectionType();
230 return connectionType != CONNECTION_UNKNOWN && connectionType != CONNECTION_NONE;