NetworkChangeNotifierAutoDetect.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.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.Listener {
25
26    /** Queries the ConnectivityManager for information about the current connection. */
27    static class ConnectivityManagerDelegate {
28        private ConnectivityManager mConnectivityManager;
29
30        ConnectivityManagerDelegate(Context context) {
31            if (context != null) {
32                mConnectivityManager = (ConnectivityManager)
33                       context.getSystemService(Context.CONNECTIVITY_SERVICE);
34            }
35        }
36
37        boolean activeNetworkExists() {
38            return mConnectivityManager != null &&
39                    mConnectivityManager.getActiveNetworkInfo() != null;
40        }
41
42        int getNetworkType() {
43            return mConnectivityManager.getActiveNetworkInfo().getType();
44        }
45
46        int getNetworkSubtype() {
47            return mConnectivityManager.getActiveNetworkInfo().getSubtype();
48        }
49    }
50
51    private static final String TAG = "NetworkChangeNotifierAutoDetect";
52
53    private final NetworkConnectivityIntentFilter mIntentFilter =
54            new NetworkConnectivityIntentFilter();
55
56    private final Observer mObserver;
57
58    private final Context mContext;
59    private ConnectivityManagerDelegate mConnectivityManagerDelegate;
60    private boolean mRegistered;
61    private int mConnectionType;
62
63    /**
64     * Observer notified on the UI thread whenever a new connection type was detected.
65     */
66    public static interface Observer {
67        public void onConnectionTypeChanged(int newConnectionType);
68    }
69
70    public NetworkChangeNotifierAutoDetect(Observer observer, Context context) {
71        mObserver = observer;
72        mContext = context;
73        mConnectivityManagerDelegate = new ConnectivityManagerDelegate(context);
74        mConnectionType = currentConnectionType(context);
75
76        ActivityStatus status = ActivityStatus.getInstance();
77        if (!status.isPaused()) {
78          registerReceiver();
79        }
80        status.registerListener(this);
81    }
82
83    /**
84     * Allows overriding the ConnectivityManagerDelegate for tests.
85     */
86    void setConnectivityManagerDelegateForTests(ConnectivityManagerDelegate delegate) {
87        mConnectivityManagerDelegate = delegate;
88    }
89
90    public void destroy() {
91        unregisterReceiver();
92    }
93
94    /**
95     * Register a BroadcastReceiver in the given context.
96     */
97    private void registerReceiver() {
98        if (!mRegistered) {
99          mRegistered = true;
100          mContext.registerReceiver(this, mIntentFilter);
101        }
102    }
103
104    /**
105     * Unregister the BroadcastReceiver in the given context.
106     */
107    private void unregisterReceiver() {
108        if (mRegistered) {
109           mRegistered = false;
110           mContext.unregisterReceiver(this);
111        }
112    }
113
114    private int currentConnectionType(Context context) {
115        // Track exactly what type of connection we have.
116        if (!mConnectivityManagerDelegate.activeNetworkExists()) {
117            return NetworkChangeNotifier.CONNECTION_NONE;
118        }
119
120        switch (mConnectivityManagerDelegate.getNetworkType()) {
121            case ConnectivityManager.TYPE_ETHERNET:
122                return NetworkChangeNotifier.CONNECTION_ETHERNET;
123            case ConnectivityManager.TYPE_WIFI:
124                return NetworkChangeNotifier.CONNECTION_WIFI;
125            case ConnectivityManager.TYPE_WIMAX:
126                return NetworkChangeNotifier.CONNECTION_4G;
127            case ConnectivityManager.TYPE_MOBILE:
128                // Use information from TelephonyManager to classify the connection.
129                switch (mConnectivityManagerDelegate.getNetworkSubtype()) {
130                    case TelephonyManager.NETWORK_TYPE_GPRS:
131                    case TelephonyManager.NETWORK_TYPE_EDGE:
132                    case TelephonyManager.NETWORK_TYPE_CDMA:
133                    case TelephonyManager.NETWORK_TYPE_1xRTT:
134                    case TelephonyManager.NETWORK_TYPE_IDEN:
135                        return NetworkChangeNotifier.CONNECTION_2G;
136                    case TelephonyManager.NETWORK_TYPE_UMTS:
137                    case TelephonyManager.NETWORK_TYPE_EVDO_0:
138                    case TelephonyManager.NETWORK_TYPE_EVDO_A:
139                    case TelephonyManager.NETWORK_TYPE_HSDPA:
140                    case TelephonyManager.NETWORK_TYPE_HSUPA:
141                    case TelephonyManager.NETWORK_TYPE_HSPA:
142                    case TelephonyManager.NETWORK_TYPE_EVDO_B:
143                    case TelephonyManager.NETWORK_TYPE_EHRPD:
144                    case TelephonyManager.NETWORK_TYPE_HSPAP:
145                        return NetworkChangeNotifier.CONNECTION_3G;
146                    case TelephonyManager.NETWORK_TYPE_LTE:
147                        return NetworkChangeNotifier.CONNECTION_4G;
148                    default:
149                        return NetworkChangeNotifier.CONNECTION_UNKNOWN;
150                }
151            default:
152                return NetworkChangeNotifier.CONNECTION_UNKNOWN;
153        }
154    }
155
156    // BroadcastReceiver
157    @Override
158    public void onReceive(Context context, Intent intent) {
159        boolean noConnection =
160                intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
161        int newConnectionType = noConnection ?
162                NetworkChangeNotifier.CONNECTION_NONE : currentConnectionType(context);
163
164        if (newConnectionType != mConnectionType) {
165            mConnectionType = newConnectionType;
166            Log.d(TAG, "Network connectivity changed, type is: " + mConnectionType);
167            mObserver.onConnectionTypeChanged(newConnectionType);
168        }
169    }
170
171    // AcitivityStatus.Listener
172    @Override
173    public void onActivityStatusChanged(boolean isPaused) {
174        if (isPaused) {
175            unregisterReceiver();
176        } else {
177            registerReceiver();
178        }
179    }
180
181    private static class NetworkConnectivityIntentFilter extends IntentFilter {
182        NetworkConnectivityIntentFilter() {
183                addAction(ConnectivityManager.CONNECTIVITY_ACTION);
184        }
185    }
186}
187