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