NetworkChangeNotifier.java revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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 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 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 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 64 public static NetworkChangeNotifier init(Context context) { 65 if (sInstance == null) { 66 sInstance = new NetworkChangeNotifier(context); 67 } 68 return sInstance; 69 } 70 71 public static boolean isInitialized() { 72 return sInstance != null; 73 } 74 75 static void resetInstanceForTests(Context context) { 76 sInstance = new NetworkChangeNotifier(context); 77 } 78 79 @CalledByNative 80 public int getCurrentConnectionType() { 81 return mCurrentConnectionType; 82 } 83 84 /** 85 * Adds a native-side observer. 86 */ 87 @CalledByNative 88 public void addNativeObserver(long nativeChangeNotifier) { 89 mNativeChangeNotifiers.add(nativeChangeNotifier); 90 } 91 92 /** 93 * Removes a native-side observer. 94 */ 95 @CalledByNative 96 public void removeNativeObserver(long nativeChangeNotifier) { 97 mNativeChangeNotifiers.remove(nativeChangeNotifier); 98 } 99 100 /** 101 * Returns the singleton instance. 102 */ 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 */ 116 public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) { 117 getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect); 118 } 119 120 private void destroyAutoDetector() { 121 if (mAutoDetector != null) { 122 mAutoDetector.destroy(); 123 mAutoDetector = null; 124 } 125 } 126 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 152 public static void forceConnectivityState(boolean networkAvailable) { 153 setAutoDetectConnectivityState(false); 154 getInstance().forceConnectivityStateInternal(networkAvailable); 155 } 156 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 164 private void updateCurrentConnectionType(int newConnectionType) { 165 mCurrentConnectionType = newConnectionType; 166 notifyObserversOfConnectionTypeChange(newConnectionType); 167 } 168 169 /** 170 * Alerts all observers of a connection change. 171 */ 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 */ 184 public static void addConnectionTypeObserver(ConnectionTypeObserver observer) { 185 getInstance().addConnectionTypeObserverInternal(observer); 186 } 187 188 private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) { 189 mConnectionTypeObservers.addObserver(observer); 190 } 191 192 /** 193 * Removes an observer for any connection type changes. 194 */ 195 public static void removeConnectionTypeObserver(ConnectionTypeObserver observer) { 196 getInstance().removeConnectionTypeObserverInternal(observer); 197 } 198 199 private void removeConnectionTypeObserverInternal(ConnectionTypeObserver observer) { 200 mConnectionTypeObservers.removeObserver(observer); 201 } 202 203 @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid") 204 private native void nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType); 205 206 // For testing only. 207 public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() { 208 return getInstance().mAutoDetector; 209 } 210 211 /** 212 * Checks if there currently is connectivity. 213 */ 214 public static boolean isOnline() { 215 int connectionType = getInstance().getCurrentConnectionType(); 216 return connectionType != CONNECTION_UNKNOWN && connectionType != CONNECTION_NONE; 217 } 218} 219