NetworkChangeNotifier.java revision 5821806d5e7f356e8fa4b058a389a808ea183019
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; 12 13import java.util.concurrent.CopyOnWriteArrayList; 14 15/** 16 * Triggers updates to the underlying network state in Chrome. 17 * By default, connectivity is assumed and changes must pushed from 18 * the embedder via the forceConnectivityState function. 19 * Embedders may choose to have this class auto-detect changes in 20 * network connectivity by invoking the autoDetectConnectivityState 21 * function. 22 * This class is not thread-safe. 23 */ 24@JNINamespace("net") 25public class NetworkChangeNotifier { 26 /** 27 * Alerted when the connection type of the network changes. 28 * The alert is fired on the UI thread. 29 */ 30 public interface ConnectionTypeObserver { 31 public void onConnectionTypeChanged(int connectionType); 32 } 33 34 // These constants must always match the ones in network_change_notifier.h. 35 public static final int CONNECTION_UNKNOWN = 0; 36 public static final int CONNECTION_ETHERNET = 1; 37 public static final int CONNECTION_WIFI = 2; 38 public static final int CONNECTION_2G = 3; 39 public static final int CONNECTION_3G = 4; 40 public static final int CONNECTION_4G = 5; 41 public static final int CONNECTION_NONE = 6; 42 43 private final Context mContext; 44 private int mNativeChangeNotifier; 45 private final CopyOnWriteArrayList<ConnectionTypeObserver> mConnectionTypeObservers; 46 private NetworkChangeNotifierAutoDetect mAutoDetector; 47 48 private static NetworkChangeNotifier sInstance; 49 50 private NetworkChangeNotifier(Context context, int nativeChangeNotifier) { 51 mContext = context; 52 mNativeChangeNotifier = nativeChangeNotifier; 53 mConnectionTypeObservers = new CopyOnWriteArrayList<ConnectionTypeObserver>(); 54 } 55 56 private void destroy() { 57 if (mAutoDetector != null) { 58 mAutoDetector.destroy(); 59 } 60 mNativeChangeNotifier = 0; 61 mConnectionTypeObservers.clear(); 62 } 63 64 /** 65 * Creates the singleton used by the native-side NetworkChangeNotifier. 66 */ 67 @CalledByNative 68 static NetworkChangeNotifier createInstance(Context context, int nativeChangeNotifier) { 69 assert sInstance == null; 70 sInstance = new NetworkChangeNotifier(context, nativeChangeNotifier); 71 return sInstance; 72 } 73 74 /** 75 * Destroys the singleton used by the native-side NetworkChangeNotifier. 76 */ 77 @CalledByNative 78 private static void destroyInstance() { 79 assert sInstance != null; 80 sInstance.destroy(); 81 sInstance = null; 82 } 83 84 /** 85 * Returns the instance used by the native-side NetworkChangeNotifier. 86 */ 87 public static NetworkChangeNotifier getInstance() { 88 assert sInstance != null; 89 return sInstance; 90 } 91 92 /** 93 * Enable auto detection of the current network state based on notifications 94 * from the system. Note that passing true here requires the embedding app 95 * have the platform ACCESS_NETWORK_STATE permission. 96 * 97 * @param shouldAutoDetect true if the NetworkChangeNotifier should listen 98 * for system changes in network connectivity. 99 */ 100 public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) { 101 // We should only get a call to this after the native object is created and 102 // hence the singleton initialised. 103 getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect); 104 } 105 106 private void destroyAutoDetector() { 107 if (mAutoDetector != null) { 108 mAutoDetector.destroy(); 109 mAutoDetector = null; 110 } 111 } 112 113 private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) { 114 if (shouldAutoDetect) { 115 if (mAutoDetector == null) { 116 mAutoDetector = new NetworkChangeNotifierAutoDetect( 117 new NetworkChangeNotifierAutoDetect.Observer() { 118 @Override 119 public void onConnectionTypeChanged(int newConnectionType) { 120 notifyObserversOfConnectionTypeChange(newConnectionType); 121 } 122 }, 123 mContext); 124 } 125 } else { 126 destroyAutoDetector(); 127 } 128 } 129 130 /** 131 * Update the perceived network state when not auto-detecting 132 * changes to connectivity. 133 * 134 * @param networkAvailable True if the NetworkChangeNotifier should 135 * perceive a "connected" state, false implies "disconnected". 136 */ 137 @CalledByNative 138 public static void forceConnectivityState(boolean networkAvailable) { 139 setAutoDetectConnectivityState(false); 140 getInstance().forceConnectivityStateInternal(networkAvailable); 141 } 142 143 private void forceConnectivityStateInternal(boolean forceOnline) { 144 if (mNativeChangeNotifier == 0) { 145 return; 146 } 147 boolean connectionCurrentlyExists = 148 nativeGetConnectionType(mNativeChangeNotifier) != CONNECTION_NONE; 149 if (connectionCurrentlyExists != forceOnline) { 150 notifyObserversOfConnectionTypeChange( 151 forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE); 152 } 153 } 154 155 /** 156 * Alerts all observers of a connection change. 157 */ 158 void notifyObserversOfConnectionTypeChange(int newConnectionType) { 159 if (mNativeChangeNotifier != 0) { 160 nativeNotifyObserversOfConnectionTypeChange(mNativeChangeNotifier, newConnectionType); 161 } 162 163 for (ConnectionTypeObserver observer : mConnectionTypeObservers) { 164 observer.onConnectionTypeChanged(newConnectionType); 165 } 166 } 167 168 /** 169 * Adds an observer for any connection type changes. 170 */ 171 public static void addConnectionTypeObserver(ConnectionTypeObserver observer) { 172 getInstance().addConnectionTypeObserverInternal(observer); 173 } 174 175 private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) { 176 if (!mConnectionTypeObservers.contains(observer)) 177 mConnectionTypeObservers.add(observer); 178 } 179 180 /** 181 * Removes an observer for any connection type changes. 182 */ 183 public static boolean removeConnectionTypeObserver(ConnectionTypeObserver observer) { 184 return getInstance().removeConnectionTypeObserverInternal(observer); 185 } 186 187 private boolean removeConnectionTypeObserverInternal(ConnectionTypeObserver observer) { 188 return mConnectionTypeObservers.remove(observer); 189 } 190 191 @NativeClassQualifiedName("NetworkChangeNotifierAndroid") 192 private native void nativeNotifyObserversOfConnectionTypeChange( 193 int nativePtr, int newConnectionType); 194 195 @NativeClassQualifiedName("NetworkChangeNotifierAndroid") 196 private native int nativeGetConnectionType(int nativePtr); 197 198 // For testing only. 199 public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() { 200 return getInstance().mAutoDetector; 201 } 202} 203