• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2015 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 package org.webrtc;
29 
30 import static org.webrtc.NetworkMonitorAutoDetect.ConnectionType;
31 import static org.webrtc.NetworkMonitorAutoDetect.INVALID_NET_ID;
32 
33 import android.content.Context;
34 import android.util.Log;
35 
36 import java.util.ArrayList;
37 
38 /**
39  * Borrowed from Chromium's src/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
40  *
41  * Triggers updates to the underlying network state from OS networking events.
42  *
43  * WARNING: This class is not thread-safe.
44  */
45 public class NetworkMonitor {
46   /**
47    * Alerted when the connection type of the network changes.
48    * The alert is fired on the UI thread.
49    */
50   public interface NetworkObserver {
onConnectionTypeChanged(ConnectionType connectionType)51     public void onConnectionTypeChanged(ConnectionType connectionType);
52   }
53 
54   private static final String TAG = "NetworkMonitor";
55   private static NetworkMonitor instance;
56 
57   private final Context applicationContext;
58 
59   // Native observers of the connection type changes.
60   private final ArrayList<Long> nativeNetworkObservers;
61   // Java observers of the connection type changes.
62   private final ArrayList<NetworkObserver> networkObservers;
63 
64   // Object that detects the connection type changes.
65   private NetworkMonitorAutoDetect autoDetector;
66 
67   private ConnectionType currentConnectionType = ConnectionType.CONNECTION_UNKNOWN;
68 
NetworkMonitor(Context context)69   private NetworkMonitor(Context context) {
70     assertIsTrue(context != null);
71     applicationContext =
72         context.getApplicationContext() == null ? context : context.getApplicationContext();
73 
74     nativeNetworkObservers = new ArrayList<Long>();
75     networkObservers = new ArrayList<NetworkObserver>();
76   }
77 
78   /**
79    * Initializes the singleton once.
80    * Called from the native code.
81    */
init(Context context)82   public static NetworkMonitor init(Context context) {
83     if (!isInitialized()) {
84       instance = new NetworkMonitor(context);
85     }
86     return instance;
87   }
88 
isInitialized()89   public static boolean isInitialized() {
90     return instance != null;
91   }
92 
93   /**
94    * Returns the singleton instance.
95    */
getInstance()96   public static NetworkMonitor getInstance() {
97     return instance;
98   }
99 
100   /**
101    * Enables auto detection of the current network state based on notifications from the system.
102    * Note that passing true here requires the embedding app have the platform ACCESS_NETWORK_STATE
103    * permission.
104    *
105    * @param shouldAutoDetect true if the NetworkMonitor should listen for system changes in
106    *  network connectivity.
107    */
setAutoDetectConnectivityState(boolean shouldAutoDetect)108   public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
109     getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
110   }
111 
assertIsTrue(boolean condition)112   private static void assertIsTrue(boolean condition) {
113     if (!condition) {
114       throw new AssertionError("Expected to be true");
115     }
116   }
117 
118   // Called by the native code.
startMonitoring(long nativeObserver)119   private void startMonitoring(long nativeObserver) {
120     Log.d(TAG, "Start monitoring from native observer " + nativeObserver);
121     nativeNetworkObservers.add(nativeObserver);
122     setAutoDetectConnectivityStateInternal(true);
123   }
124 
125   // Called by the native code.
stopMonitoring(long nativeObserver)126   private void stopMonitoring(long nativeObserver) {
127     Log.d(TAG, "Stop monitoring from native observer " + nativeObserver);
128     setAutoDetectConnectivityStateInternal(false);
129     nativeNetworkObservers.remove(nativeObserver);
130   }
131 
getCurrentConnectionType()132   private ConnectionType getCurrentConnectionType() {
133     return currentConnectionType;
134   }
135 
getCurrentDefaultNetId()136   private int getCurrentDefaultNetId() {
137     return autoDetector == null ? INVALID_NET_ID : autoDetector.getDefaultNetId();
138   }
139 
destroyAutoDetector()140   private void destroyAutoDetector() {
141     if (autoDetector != null) {
142       autoDetector.destroy();
143       autoDetector = null;
144     }
145   }
146 
setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect)147   private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) {
148     if (!shouldAutoDetect) {
149       destroyAutoDetector();
150       return;
151     }
152     if (autoDetector == null) {
153       autoDetector = new NetworkMonitorAutoDetect(
154         new NetworkMonitorAutoDetect.Observer() {
155           @Override
156           public void onConnectionTypeChanged(ConnectionType newConnectionType) {
157             updateCurrentConnectionType(newConnectionType);
158           }
159         },
160         applicationContext);
161       final NetworkMonitorAutoDetect.NetworkState networkState =
162           autoDetector.getCurrentNetworkState();
163       updateCurrentConnectionType(autoDetector.getCurrentConnectionType(networkState));
164     }
165   }
166 
updateCurrentConnectionType(ConnectionType newConnectionType)167   private void updateCurrentConnectionType(ConnectionType newConnectionType) {
168     currentConnectionType = newConnectionType;
169     notifyObserversOfConnectionTypeChange(newConnectionType);
170   }
171 
172   /**
173    * Alerts all observers of a connection change.
174    */
notifyObserversOfConnectionTypeChange(ConnectionType newConnectionType)175   private void notifyObserversOfConnectionTypeChange(ConnectionType newConnectionType) {
176     for (long nativeObserver : nativeNetworkObservers) {
177       nativeNotifyConnectionTypeChanged(nativeObserver);
178     }
179     for (NetworkObserver observer : networkObservers) {
180       observer.onConnectionTypeChanged(newConnectionType);
181     }
182   }
183 
184   /**
185    * Adds an observer for any connection type changes.
186    */
addNetworkObserver(NetworkObserver observer)187   public static void addNetworkObserver(NetworkObserver observer) {
188     getInstance().addNetworkObserverInternal(observer);
189   }
190 
addNetworkObserverInternal(NetworkObserver observer)191   private void addNetworkObserverInternal(NetworkObserver observer) {
192     networkObservers.add(observer);
193   }
194 
195   /**
196    * Removes an observer for any connection type changes.
197    */
removeNetworkObserver(NetworkObserver observer)198   public static void removeNetworkObserver(NetworkObserver observer) {
199     getInstance().removeNetworkObserverInternal(observer);
200   }
201 
removeNetworkObserverInternal(NetworkObserver observer)202   private void removeNetworkObserverInternal(NetworkObserver observer) {
203     networkObservers.remove(observer);
204   }
205 
206   /**
207    * Checks if there currently is connectivity.
208    */
isOnline()209   public static boolean isOnline() {
210     ConnectionType connectionType = getInstance().getCurrentConnectionType();
211     return connectionType != ConnectionType.CONNECTION_UNKNOWN
212         && connectionType != ConnectionType.CONNECTION_NONE;
213   }
214 
nativeCreateNetworkMonitor()215   private native long nativeCreateNetworkMonitor();
216 
nativeNotifyConnectionTypeChanged(long nativePtr)217   private native void nativeNotifyConnectionTypeChanged(long nativePtr);
218 
219   // For testing only.
resetInstanceForTests(Context context)220   static void resetInstanceForTests(Context context) {
221     instance = new NetworkMonitor(context);
222   }
223 
224   // For testing only.
getAutoDetectorForTest()225   public static NetworkMonitorAutoDetect getAutoDetectorForTest() {
226     return getInstance().autoDetector;
227   }
228 }
229