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.
5 package org.chromium.net;
7 import android.content.BroadcastReceiver;
8 import android.content.Context;
9 import android.content.Intent;
10 import android.content.IntentFilter;
11 import android.net.ConnectivityManager;
12 import android.net.wifi.WifiInfo;
13 import android.net.wifi.WifiManager;
14 import android.telephony.TelephonyManager;
15 import android.util.Log;
17 import org.chromium.base.ActivityStatus;
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.
24 public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver
25 implements ActivityStatus.StateListener {
27 /** Queries the ConnectivityManager for information about the current connection. */
28 static class ConnectivityManagerDelegate {
29 private final ConnectivityManager mConnectivityManager;
31 ConnectivityManagerDelegate(Context context) {
32 mConnectivityManager =
33 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
37 ConnectivityManagerDelegate() {
38 // All the methods below should be overridden.
39 mConnectivityManager = null;
42 boolean activeNetworkExists() {
43 return mConnectivityManager.getActiveNetworkInfo() != null;
46 boolean isConnected() {
47 return mConnectivityManager.getActiveNetworkInfo().isConnected();
50 int getNetworkType() {
51 return mConnectivityManager.getActiveNetworkInfo().getType();
54 int getNetworkSubtype() {
55 return mConnectivityManager.getActiveNetworkInfo().getSubtype();
59 /** Queries the WifiManager for SSID of the current Wifi connection. */
60 static class WifiManagerDelegate {
61 private final WifiManager mWifiManager;
63 WifiManagerDelegate(Context context) {
64 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
68 WifiManagerDelegate() {
69 // All the methods below should be overridden.
73 String getWifiSSID() {
74 WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
77 String ssid = wifiInfo.getSSID();
78 return ssid == null ? "" : ssid;
82 private static final String TAG = "NetworkChangeNotifierAutoDetect";
84 private final NetworkConnectivityIntentFilter mIntentFilter =
85 new NetworkConnectivityIntentFilter();
87 private final Observer mObserver;
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;
97 * Observer notified on the UI thread whenever a new connection type was detected.
99 public static interface Observer {
100 public void onConnectionTypeChanged(int newConnectionType);
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);
114 * Allows overriding the ConnectivityManagerDelegate for tests.
116 void setConnectivityManagerDelegateForTests(ConnectivityManagerDelegate delegate) {
117 mConnectivityManagerDelegate = delegate;
121 * Allows overriding the WifiManagerDelegate for tests.
123 void setWifiManagerDelegateForTests(WifiManagerDelegate delegate) {
124 mWifiManagerDelegate = delegate;
127 public void destroy() {
128 unregisterReceiver();
132 * Register a BroadcastReceiver in the given context.
134 private void registerReceiver() {
137 mContext.registerReceiver(this, mIntentFilter);
142 * Unregister the BroadcastReceiver in the given context.
144 private void unregisterReceiver() {
147 mContext.unregisterReceiver(this);
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;
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;
187 return NetworkChangeNotifier.CONNECTION_UNKNOWN;
190 return NetworkChangeNotifier.CONNECTION_UNKNOWN;
194 private String getCurrentWifiSSID() {
195 if (getCurrentConnectionType() != NetworkChangeNotifier.CONNECTION_WIFI)
197 return mWifiManagerDelegate.getWifiSSID();
202 public void onReceive(Context context, Intent intent) {
203 connectionTypeChanged();
206 // ActivityStatus.StateListener
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();
218 } else if (state == ActivityStatus.PAUSED) {
219 unregisterReceiver();
223 private void connectionTypeChanged() {
224 int newConnectionType = getCurrentConnectionType();
225 String newWifiSSID = getCurrentWifiSSID();
226 if (newConnectionType == mConnectionType && newWifiSSID.equals(mWifiSSID))
229 mConnectionType = newConnectionType;
230 mWifiSSID = newWifiSSID;
231 Log.d(TAG, "Network connectivity changed, type is: " + mConnectionType);
232 mObserver.onConnectionTypeChanged(newConnectionType);
235 private static class NetworkConnectivityIntentFilter extends IntentFilter {
236 NetworkConnectivityIntentFilter() {
237 addAction(ConnectivityManager.CONNECTIVITY_ACTION);