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