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