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