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