• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 package org.chromium.net;
6 
7 import android.content.Context;
8 
9 import org.chromium.base.CalledByNative;
10 import org.chromium.base.JNINamespace;
11 import org.chromium.base.NativeClassQualifiedName;
12 import org.chromium.base.ObserverList;
13 
14 import java.util.ArrayList;
15 
16 /**
17  * Triggers updates to the underlying network state in Chrome.
18  *
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.
23  *
24  * WARNING: This class is not thread-safe.
25  */
26 @JNINamespace("net")
27 public class NetworkChangeNotifier {
28     /**
29      * Alerted when the connection type of the network changes.
30      * The alert is fired on the UI thread.
31      */
32     public interface ConnectionTypeObserver {
onConnectionTypeChanged(int connectionType)33         public void onConnectionTypeChanged(int connectionType);
34     }
35 
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;
45 
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;
51 
52     private static NetworkChangeNotifier sInstance;
53 
NetworkChangeNotifier(Context context)54     private NetworkChangeNotifier(Context context) {
55         mContext = context.getApplicationContext();
56         mNativeChangeNotifiers = new ArrayList<Long>();
57         mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>();
58     }
59 
60     /**
61      * Initializes the singleton once.
62      */
63     @CalledByNative
init(Context context)64     public static NetworkChangeNotifier init(Context context) {
65         if (sInstance == null) {
66             sInstance = new NetworkChangeNotifier(context);
67         }
68         return sInstance;
69     }
70 
isInitialized()71     public static boolean isInitialized() {
72         return sInstance != null;
73     }
74 
resetInstanceForTests(Context context)75     static void resetInstanceForTests(Context context) {
76         sInstance = new NetworkChangeNotifier(context);
77     }
78 
79     @CalledByNative
getCurrentConnectionType()80     public int getCurrentConnectionType() {
81         return mCurrentConnectionType;
82     }
83 
84     /**
85      * Adds a native-side observer.
86      */
87     @CalledByNative
addNativeObserver(long nativeChangeNotifier)88     public void addNativeObserver(long nativeChangeNotifier) {
89         mNativeChangeNotifiers.add(nativeChangeNotifier);
90     }
91 
92     /**
93      * Removes a native-side observer.
94      */
95     @CalledByNative
removeNativeObserver(long nativeChangeNotifier)96     public void removeNativeObserver(long nativeChangeNotifier) {
97         mNativeChangeNotifiers.remove(nativeChangeNotifier);
98     }
99 
100     /**
101      * Returns the singleton instance.
102      */
getInstance()103     public static NetworkChangeNotifier getInstance() {
104         assert sInstance != null;
105         return sInstance;
106     }
107 
108     /**
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
111      * permission.
112      *
113      * @param shouldAutoDetect true if the NetworkChangeNotifier should listen for system changes in
114      *    network connectivity.
115      */
setAutoDetectConnectivityState(boolean shouldAutoDetect)116     public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
117         getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
118     }
119 
destroyAutoDetector()120     private void destroyAutoDetector() {
121         if (mAutoDetector != null) {
122             mAutoDetector.destroy();
123             mAutoDetector = null;
124         }
125     }
126 
setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect)127     private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) {
128         if (shouldAutoDetect) {
129             if (mAutoDetector == null) {
130                 mAutoDetector = new NetworkChangeNotifierAutoDetect(
131                     new NetworkChangeNotifierAutoDetect.Observer() {
132                         @Override
133                         public void onConnectionTypeChanged(int newConnectionType) {
134                             updateCurrentConnectionType(newConnectionType);
135                         }
136                     },
137                     mContext);
138                 updateCurrentConnectionType(mAutoDetector.getCurrentConnectionType());
139             }
140         } else {
141             destroyAutoDetector();
142         }
143     }
144 
145     /**
146      * Updates the perceived network state when not auto-detecting changes to connectivity.
147      *
148      * @param networkAvailable True if the NetworkChangeNotifier should perceive a "connected"
149      *    state, false implies "disconnected".
150      */
151     @CalledByNative
forceConnectivityState(boolean networkAvailable)152     public static void forceConnectivityState(boolean networkAvailable) {
153         setAutoDetectConnectivityState(false);
154         getInstance().forceConnectivityStateInternal(networkAvailable);
155     }
156 
forceConnectivityStateInternal(boolean forceOnline)157     private void forceConnectivityStateInternal(boolean forceOnline) {
158         boolean connectionCurrentlyExists = mCurrentConnectionType != CONNECTION_NONE;
159         if (connectionCurrentlyExists != forceOnline) {
160             updateCurrentConnectionType(forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE);
161         }
162     }
163 
updateCurrentConnectionType(int newConnectionType)164     private void updateCurrentConnectionType(int newConnectionType) {
165         mCurrentConnectionType = newConnectionType;
166         notifyObserversOfConnectionTypeChange(newConnectionType);
167     }
168 
169     /**
170      * Alerts all observers of a connection change.
171      */
notifyObserversOfConnectionTypeChange(int newConnectionType)172     void notifyObserversOfConnectionTypeChange(int newConnectionType) {
173         for (Long nativeChangeNotifier : mNativeChangeNotifiers) {
174             nativeNotifyConnectionTypeChanged(nativeChangeNotifier, newConnectionType);
175         }
176         for (ConnectionTypeObserver observer : mConnectionTypeObservers) {
177             observer.onConnectionTypeChanged(newConnectionType);
178         }
179     }
180 
181     /**
182      * Adds an observer for any connection type changes.
183      */
addConnectionTypeObserver(ConnectionTypeObserver observer)184     public static void addConnectionTypeObserver(ConnectionTypeObserver observer) {
185         getInstance().addConnectionTypeObserverInternal(observer);
186     }
187 
addConnectionTypeObserverInternal(ConnectionTypeObserver observer)188     private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
189         mConnectionTypeObservers.addObserver(observer);
190     }
191 
192     /**
193      * Removes an observer for any connection type changes.
194      */
removeConnectionTypeObserver(ConnectionTypeObserver observer)195     public static void removeConnectionTypeObserver(ConnectionTypeObserver observer) {
196         getInstance().removeConnectionTypeObserverInternal(observer);
197     }
198 
removeConnectionTypeObserverInternal(ConnectionTypeObserver observer)199     private void removeConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
200         mConnectionTypeObservers.removeObserver(observer);
201     }
202 
203     @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid")
nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType)204     private native void nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType);
205 
206     // For testing only.
getAutoDetectorForTest()207     public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() {
208         return getInstance().mAutoDetector;
209     }
210 
211     /**
212      * Checks if there currently is connectivity.
213      */
isOnline()214     public static boolean isOnline() {
215         int connectionType = getInstance().getCurrentConnectionType();
216         return connectionType != CONNECTION_UNKNOWN && connectionType != CONNECTION_NONE;
217     }
218 }
219