1 // Copyright (c) 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;
45 private final Context mContext;
46 private final ArrayList<Integer> mNativeChangeNotifiers;
47 private final ObserverList<ConnectionTypeObserver> mConnectionTypeObservers;
48 private NetworkChangeNotifierAutoDetect mAutoDetector;
49 private int mCurrentConnectionType = CONNECTION_UNKNOWN;
51 private static NetworkChangeNotifier sInstance;
53 private NetworkChangeNotifier(Context context) {
54 mContext = context.getApplicationContext();
55 mNativeChangeNotifiers = new ArrayList<Integer>();
56 mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>();
60 * Initializes the singleton once.
63 public static NetworkChangeNotifier init(Context context) {
64 if (sInstance == null) {
65 sInstance = new NetworkChangeNotifier(context);
70 public static boolean isInitialized() {
71 return sInstance != null;
74 static void resetInstanceForTests(Context context) {
75 sInstance = new NetworkChangeNotifier(context);
79 public int getCurrentConnectionType() {
80 return mCurrentConnectionType;
84 * Adds a native-side observer.
87 public void addNativeObserver(int nativeChangeNotifier) {
88 mNativeChangeNotifiers.add(nativeChangeNotifier);
92 * Removes a native-side observer.
95 public void removeNativeObserver(int nativeChangeNotifier) {
96 // Please keep the cast performing the boxing below. It ensures that the right method
97 // overload is used. ArrayList<T> has both remove(int index) and remove(T element).
98 mNativeChangeNotifiers.remove((Integer) nativeChangeNotifier);
102 * Returns the singleton instance.
104 public static NetworkChangeNotifier getInstance() {
105 assert sInstance != null;
110 * Enables auto detection of the current network state based on notifications from the system.
111 * Note that passing true here requires the embedding app have the platform ACCESS_NETWORK_STATE
114 * @param shouldAutoDetect true if the NetworkChangeNotifier should listen for system changes in
115 * network connectivity.
117 public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
118 getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
121 private void destroyAutoDetector() {
122 if (mAutoDetector != null) {
123 mAutoDetector.destroy();
124 mAutoDetector = null;
128 private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) {
129 if (shouldAutoDetect) {
130 if (mAutoDetector == null) {
131 mAutoDetector = new NetworkChangeNotifierAutoDetect(
132 new NetworkChangeNotifierAutoDetect.Observer() {
134 public void onConnectionTypeChanged(int newConnectionType) {
135 updateCurrentConnectionType(newConnectionType);
139 mCurrentConnectionType = mAutoDetector.getCurrentConnectionType();
142 destroyAutoDetector();
147 * Updates the perceived network state when not auto-detecting changes to connectivity.
149 * @param networkAvailable True if the NetworkChangeNotifier should perceive a "connected"
150 * state, false implies "disconnected".
153 public static void forceConnectivityState(boolean networkAvailable) {
154 setAutoDetectConnectivityState(false);
155 getInstance().forceConnectivityStateInternal(networkAvailable);
158 private void forceConnectivityStateInternal(boolean forceOnline) {
159 boolean connectionCurrentlyExists = mCurrentConnectionType != CONNECTION_NONE;
160 if (connectionCurrentlyExists != forceOnline) {
161 updateCurrentConnectionType(forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE);
165 private void updateCurrentConnectionType(int newConnectionType) {
166 mCurrentConnectionType = newConnectionType;
167 notifyObserversOfConnectionTypeChange(newConnectionType);
171 * Alerts all observers of a connection change.
173 void notifyObserversOfConnectionTypeChange(int newConnectionType) {
174 for (Integer nativeChangeNotifier : mNativeChangeNotifiers) {
175 nativeNotifyConnectionTypeChanged(nativeChangeNotifier, newConnectionType);
177 for (ConnectionTypeObserver observer : mConnectionTypeObservers) {
178 observer.onConnectionTypeChanged(newConnectionType);
183 * Adds an observer for any connection type changes.
185 public static void addConnectionTypeObserver(ConnectionTypeObserver observer) {
186 getInstance().addConnectionTypeObserverInternal(observer);
189 private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
190 if (!mConnectionTypeObservers.hasObserver(observer)) {
191 mConnectionTypeObservers.addObserver(observer);
196 * Removes an observer for any connection type changes.
198 public static void removeConnectionTypeObserver(ConnectionTypeObserver observer) {
199 getInstance().removeConnectionTypeObserverInternal(observer);
202 private void removeConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
203 mConnectionTypeObservers.removeObserver(observer);
206 @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid")
207 private native void nativeNotifyConnectionTypeChanged(int nativePtr, int newConnectionType);
209 @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid")
210 private native int nativeGetConnectionType(int nativePtr);
213 public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() {
214 return getInstance().mAutoDetector;
218 * Checks if there currently is connectivity.
220 public static boolean isOnline() {
221 int connectionType = getInstance().getCurrentConnectionType();
222 return connectionType != CONNECTION_UNKNOWN && connectionType != CONNECTION_NONE;