• 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 
45     private final Context mContext;
46     private final ArrayList<Long> mNativeChangeNotifiers;
47     private final ObserverList<ConnectionTypeObserver> mConnectionTypeObservers;
48     private NetworkChangeNotifierAutoDetect mAutoDetector;
49     private int mCurrentConnectionType = CONNECTION_UNKNOWN;
50 
51     private static NetworkChangeNotifier sInstance;
52 
NetworkChangeNotifier(Context context)53     private NetworkChangeNotifier(Context context) {
54         mContext = context.getApplicationContext();
55         mNativeChangeNotifiers = new ArrayList<Long>();
56         mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>();
57     }
58 
59     /**
60      * Initializes the singleton once.
61      */
62     @CalledByNative
init(Context context)63     public static NetworkChangeNotifier init(Context context) {
64         if (sInstance == null) {
65             sInstance = new NetworkChangeNotifier(context);
66         }
67         return sInstance;
68     }
69 
isInitialized()70     public static boolean isInitialized() {
71         return sInstance != null;
72     }
73 
resetInstanceForTests(Context context)74     static void resetInstanceForTests(Context context) {
75         sInstance = new NetworkChangeNotifier(context);
76     }
77 
78     @CalledByNative
getCurrentConnectionType()79     public int getCurrentConnectionType() {
80         return mCurrentConnectionType;
81     }
82 
83     /**
84      * Adds a native-side observer.
85      */
86     @CalledByNative
addNativeObserver(long nativeChangeNotifier)87     public void addNativeObserver(long nativeChangeNotifier) {
88         mNativeChangeNotifiers.add(nativeChangeNotifier);
89     }
90 
91     /**
92      * Removes a native-side observer.
93      */
94     @CalledByNative
removeNativeObserver(long nativeChangeNotifier)95     public void removeNativeObserver(long nativeChangeNotifier) {
96         mNativeChangeNotifiers.remove(nativeChangeNotifier);
97     }
98 
99     /**
100      * Returns the singleton instance.
101      */
getInstance()102     public static NetworkChangeNotifier getInstance() {
103         assert sInstance != null;
104         return sInstance;
105     }
106 
107     /**
108      * Enables auto detection of the current network state based on notifications from the system.
109      * Note that passing true here requires the embedding app have the platform ACCESS_NETWORK_STATE
110      * permission.
111      *
112      * @param shouldAutoDetect true if the NetworkChangeNotifier should listen for system changes in
113      *    network connectivity.
114      */
setAutoDetectConnectivityState(boolean shouldAutoDetect)115     public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
116         getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
117     }
118 
destroyAutoDetector()119     private void destroyAutoDetector() {
120         if (mAutoDetector != null) {
121             mAutoDetector.destroy();
122             mAutoDetector = null;
123         }
124     }
125 
setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect)126     private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) {
127         if (shouldAutoDetect) {
128             if (mAutoDetector == null) {
129                 mAutoDetector = new NetworkChangeNotifierAutoDetect(
130                     new NetworkChangeNotifierAutoDetect.Observer() {
131                         @Override
132                         public void onConnectionTypeChanged(int newConnectionType) {
133                             updateCurrentConnectionType(newConnectionType);
134                         }
135                     },
136                     mContext);
137                 mCurrentConnectionType = mAutoDetector.getCurrentConnectionType();
138             }
139         } else {
140             destroyAutoDetector();
141         }
142     }
143 
144     /**
145      * Updates the perceived network state when not auto-detecting changes to connectivity.
146      *
147      * @param networkAvailable True if the NetworkChangeNotifier should perceive a "connected"
148      *    state, false implies "disconnected".
149      */
150     @CalledByNative
forceConnectivityState(boolean networkAvailable)151     public static void forceConnectivityState(boolean networkAvailable) {
152         setAutoDetectConnectivityState(false);
153         getInstance().forceConnectivityStateInternal(networkAvailable);
154     }
155 
forceConnectivityStateInternal(boolean forceOnline)156     private void forceConnectivityStateInternal(boolean forceOnline) {
157         boolean connectionCurrentlyExists = mCurrentConnectionType != CONNECTION_NONE;
158         if (connectionCurrentlyExists != forceOnline) {
159             updateCurrentConnectionType(forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE);
160         }
161     }
162 
updateCurrentConnectionType(int newConnectionType)163     private void updateCurrentConnectionType(int newConnectionType) {
164         mCurrentConnectionType = newConnectionType;
165         notifyObserversOfConnectionTypeChange(newConnectionType);
166     }
167 
168     /**
169      * Alerts all observers of a connection change.
170      */
notifyObserversOfConnectionTypeChange(int newConnectionType)171     void notifyObserversOfConnectionTypeChange(int newConnectionType) {
172         for (Long nativeChangeNotifier : mNativeChangeNotifiers) {
173             nativeNotifyConnectionTypeChanged(nativeChangeNotifier, newConnectionType);
174         }
175         for (ConnectionTypeObserver observer : mConnectionTypeObservers) {
176             observer.onConnectionTypeChanged(newConnectionType);
177         }
178     }
179 
180     /**
181      * Adds an observer for any connection type changes.
182      */
addConnectionTypeObserver(ConnectionTypeObserver observer)183     public static void addConnectionTypeObserver(ConnectionTypeObserver observer) {
184         getInstance().addConnectionTypeObserverInternal(observer);
185     }
186 
addConnectionTypeObserverInternal(ConnectionTypeObserver observer)187     private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
188         if (!mConnectionTypeObservers.hasObserver(observer)) {
189             mConnectionTypeObservers.addObserver(observer);
190         }
191     }
192 
193     /**
194      * Removes an observer for any connection type changes.
195      */
removeConnectionTypeObserver(ConnectionTypeObserver observer)196     public static void removeConnectionTypeObserver(ConnectionTypeObserver observer) {
197         getInstance().removeConnectionTypeObserverInternal(observer);
198     }
199 
removeConnectionTypeObserverInternal(ConnectionTypeObserver observer)200     private void removeConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
201         mConnectionTypeObservers.removeObserver(observer);
202     }
203 
204     @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid")
nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType)205     private native void nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType);
206 
207     // For testing only.
getAutoDetectorForTest()208     public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() {
209         return getInstance().mAutoDetector;
210     }
211 
212     /**
213      * Checks if there currently is connectivity.
214      */
isOnline()215     public static boolean isOnline() {
216         int connectionType = getInstance().getCurrentConnectionType();
217         return connectionType != CONNECTION_UNKNOWN && connectionType != CONNECTION_NONE;
218     }
219 }
220