NetworkChangeNotifierAutoDetect.java revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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.BroadcastReceiver; 8import android.content.Context; 9import android.content.Intent; 10import android.content.IntentFilter; 11import android.net.ConnectivityManager; 12import android.net.wifi.WifiInfo; 13import android.net.wifi.WifiManager; 14import android.telephony.TelephonyManager; 15import android.util.Log; 16 17import org.chromium.base.ActivityStatus; 18 19/** 20 * Used by the NetworkChangeNotifier to listens to platform changes in connectivity. 21 * Note that use of this class requires that the app have the platform 22 * ACCESS_NETWORK_STATE permission. 23 */ 24public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver 25 implements ActivityStatus.StateListener { 26 27 /** Queries the ConnectivityManager for information about the current connection. */ 28 static class ConnectivityManagerDelegate { 29 private final ConnectivityManager mConnectivityManager; 30 31 ConnectivityManagerDelegate(Context context) { 32 mConnectivityManager = 33 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 34 } 35 36 // For testing. 37 ConnectivityManagerDelegate() { 38 // All the methods below should be overridden. 39 mConnectivityManager = null; 40 } 41 42 boolean activeNetworkExists() { 43 return mConnectivityManager.getActiveNetworkInfo() != null; 44 } 45 46 boolean isConnected() { 47 return mConnectivityManager.getActiveNetworkInfo().isConnected(); 48 } 49 50 int getNetworkType() { 51 return mConnectivityManager.getActiveNetworkInfo().getType(); 52 } 53 54 int getNetworkSubtype() { 55 return mConnectivityManager.getActiveNetworkInfo().getSubtype(); 56 } 57 } 58 59 /** Queries the WifiManager for SSID of the current Wifi connection. */ 60 static class WifiManagerDelegate { 61 private final WifiManager mWifiManager; 62 63 WifiManagerDelegate(Context context) { 64 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 65 } 66 67 // For testing. 68 WifiManagerDelegate() { 69 // All the methods below should be overridden. 70 mWifiManager = null; 71 } 72 73 String getWifiSSID() { 74 WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); 75 if (wifiInfo == null) 76 return ""; 77 String ssid = wifiInfo.getSSID(); 78 return ssid == null ? "" : ssid; 79 } 80 } 81 82 private static final String TAG = "NetworkChangeNotifierAutoDetect"; 83 84 private final NetworkConnectivityIntentFilter mIntentFilter = 85 new NetworkConnectivityIntentFilter(); 86 87 private final Observer mObserver; 88 89 private final Context mContext; 90 private ConnectivityManagerDelegate mConnectivityManagerDelegate; 91 private WifiManagerDelegate mWifiManagerDelegate; 92 private boolean mRegistered; 93 private int mConnectionType; 94 private String mWifiSSID; 95 96 /** 97 * Observer notified on the UI thread whenever a new connection type was detected. 98 */ 99 public static interface Observer { 100 public void onConnectionTypeChanged(int newConnectionType); 101 } 102 103 public NetworkChangeNotifierAutoDetect(Observer observer, Context context) { 104 mObserver = observer; 105 mContext = context.getApplicationContext(); 106 mConnectivityManagerDelegate = new ConnectivityManagerDelegate(context); 107 mWifiManagerDelegate = new WifiManagerDelegate(context); 108 mConnectionType = getCurrentConnectionType(); 109 mWifiSSID = getCurrentWifiSSID(); 110 ActivityStatus.registerStateListener(this); 111 } 112 113 /** 114 * Allows overriding the ConnectivityManagerDelegate for tests. 115 */ 116 void setConnectivityManagerDelegateForTests(ConnectivityManagerDelegate delegate) { 117 mConnectivityManagerDelegate = delegate; 118 } 119 120 /** 121 * Allows overriding the WifiManagerDelegate for tests. 122 */ 123 void setWifiManagerDelegateForTests(WifiManagerDelegate delegate) { 124 mWifiManagerDelegate = delegate; 125 } 126 127 public void destroy() { 128 unregisterReceiver(); 129 } 130 131 /** 132 * Register a BroadcastReceiver in the given context. 133 */ 134 private void registerReceiver() { 135 if (!mRegistered) { 136 mRegistered = true; 137 mContext.registerReceiver(this, mIntentFilter); 138 } 139 } 140 141 /** 142 * Unregister the BroadcastReceiver in the given context. 143 */ 144 private void unregisterReceiver() { 145 if (mRegistered) { 146 mRegistered = false; 147 mContext.unregisterReceiver(this); 148 } 149 } 150 151 public int getCurrentConnectionType() { 152 // Track exactly what type of connection we have. 153 if (!mConnectivityManagerDelegate.activeNetworkExists() || 154 !mConnectivityManagerDelegate.isConnected()) { 155 return NetworkChangeNotifier.CONNECTION_NONE; 156 } 157 158 switch (mConnectivityManagerDelegate.getNetworkType()) { 159 case ConnectivityManager.TYPE_ETHERNET: 160 return NetworkChangeNotifier.CONNECTION_ETHERNET; 161 case ConnectivityManager.TYPE_WIFI: 162 return NetworkChangeNotifier.CONNECTION_WIFI; 163 case ConnectivityManager.TYPE_WIMAX: 164 return NetworkChangeNotifier.CONNECTION_4G; 165 case ConnectivityManager.TYPE_MOBILE: 166 // Use information from TelephonyManager to classify the connection. 167 switch (mConnectivityManagerDelegate.getNetworkSubtype()) { 168 case TelephonyManager.NETWORK_TYPE_GPRS: 169 case TelephonyManager.NETWORK_TYPE_EDGE: 170 case TelephonyManager.NETWORK_TYPE_CDMA: 171 case TelephonyManager.NETWORK_TYPE_1xRTT: 172 case TelephonyManager.NETWORK_TYPE_IDEN: 173 return NetworkChangeNotifier.CONNECTION_2G; 174 case TelephonyManager.NETWORK_TYPE_UMTS: 175 case TelephonyManager.NETWORK_TYPE_EVDO_0: 176 case TelephonyManager.NETWORK_TYPE_EVDO_A: 177 case TelephonyManager.NETWORK_TYPE_HSDPA: 178 case TelephonyManager.NETWORK_TYPE_HSUPA: 179 case TelephonyManager.NETWORK_TYPE_HSPA: 180 case TelephonyManager.NETWORK_TYPE_EVDO_B: 181 case TelephonyManager.NETWORK_TYPE_EHRPD: 182 case TelephonyManager.NETWORK_TYPE_HSPAP: 183 return NetworkChangeNotifier.CONNECTION_3G; 184 case TelephonyManager.NETWORK_TYPE_LTE: 185 return NetworkChangeNotifier.CONNECTION_4G; 186 default: 187 return NetworkChangeNotifier.CONNECTION_UNKNOWN; 188 } 189 default: 190 return NetworkChangeNotifier.CONNECTION_UNKNOWN; 191 } 192 } 193 194 private String getCurrentWifiSSID() { 195 if (getCurrentConnectionType() != NetworkChangeNotifier.CONNECTION_WIFI) 196 return ""; 197 return mWifiManagerDelegate.getWifiSSID(); 198 } 199 200 // BroadcastReceiver 201 @Override 202 public void onReceive(Context context, Intent intent) { 203 connectionTypeChanged(); 204 } 205 206 // ActivityStatus.StateListener 207 @Override 208 public void onActivityStateChange(int state) { 209 if (state == ActivityStatus.RESUMED) { 210 // Note that this also covers the case where the main activity is created. The CREATED 211 // event is always followed by the RESUMED event. This is a temporary "hack" until 212 // http://crbug.com/176837 is fixed. The CREATED event can't be used reliably for now 213 // since its notification is deferred. This means that it can immediately follow a 214 // DESTROYED/STOPPED/... event which is problematic. 215 // TODO(pliard): fix http://crbug.com/176837. 216 connectionTypeChanged(); 217 registerReceiver(); 218 } else if (state == ActivityStatus.PAUSED) { 219 unregisterReceiver(); 220 } 221 } 222 223 private void connectionTypeChanged() { 224 int newConnectionType = getCurrentConnectionType(); 225 String newWifiSSID = getCurrentWifiSSID(); 226 if (newConnectionType == mConnectionType && newWifiSSID.equals(mWifiSSID)) 227 return; 228 229 mConnectionType = newConnectionType; 230 mWifiSSID = newWifiSSID; 231 Log.d(TAG, "Network connectivity changed, type is: " + mConnectionType); 232 mObserver.onConnectionTypeChanged(newConnectionType); 233 } 234 235 private static class NetworkConnectivityIntentFilter extends IntentFilter { 236 NetworkConnectivityIntentFilter() { 237 addAction(ConnectivityManager.CONNECTIVITY_ACTION); 238 } 239 } 240} 241