NetworkChangeNotifier.java revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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.Context;
8
9import org.chromium.base.CalledByNative;
10import org.chromium.base.JNINamespace;
11import org.chromium.base.NativeClassQualifiedName;
12import org.chromium.base.ObserverList;
13
14import java.util.ArrayList;
15
16/**
17 * Triggers updates to the underlying network state in Chrome.
18 *
19 * By default, connectivity is assumed and changes must pushed from the embedder via the
20 * forceConnectivityState function.
21 * Embedders may choose to have this class auto-detect changes in network connectivity by invoking
22 * the setAutoDetectConnectivityState function.
23 *
24 * WARNING: This class is not thread-safe.
25 */
26@JNINamespace("net")
27public class NetworkChangeNotifier {
28    /**
29     * Alerted when the connection type of the network changes.
30     * The alert is fired on the UI thread.
31     */
32    public interface ConnectionTypeObserver {
33        public void onConnectionTypeChanged(int connectionType);
34    }
35
36    // These constants must always match the ones in network_change_notifier.h.
37    public static final int CONNECTION_UNKNOWN = 0;
38    public static final int CONNECTION_ETHERNET = 1;
39    public static final int CONNECTION_WIFI = 2;
40    public static final int CONNECTION_2G = 3;
41    public static final int CONNECTION_3G = 4;
42    public static final int CONNECTION_4G = 5;
43    public static final int CONNECTION_NONE = 6;
44
45    private final Context mContext;
46    private final ArrayList<Long> mNativeChangeNotifiers;
47    private final ObserverList<ConnectionTypeObserver> mConnectionTypeObservers;
48    private NetworkChangeNotifierAutoDetect mAutoDetector;
49    private int mCurrentConnectionType = CONNECTION_UNKNOWN;
50
51    private static NetworkChangeNotifier sInstance;
52
53    private NetworkChangeNotifier(Context context) {
54        mContext = context.getApplicationContext();
55        mNativeChangeNotifiers = new ArrayList<Long>();
56        mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>();
57    }
58
59    /**
60     * Initializes the singleton once.
61     */
62    @CalledByNative
63    public static NetworkChangeNotifier init(Context context) {
64        if (sInstance == null) {
65            sInstance = new NetworkChangeNotifier(context);
66        }
67        return sInstance;
68    }
69
70    public static boolean isInitialized() {
71        return sInstance != null;
72    }
73
74    static void resetInstanceForTests(Context context) {
75        sInstance = new NetworkChangeNotifier(context);
76    }
77
78    @CalledByNative
79    public int getCurrentConnectionType() {
80        return mCurrentConnectionType;
81    }
82
83    /**
84     * Adds a native-side observer.
85     */
86    @CalledByNative
87    public void addNativeObserver(long nativeChangeNotifier) {
88        mNativeChangeNotifiers.add(nativeChangeNotifier);
89    }
90
91    /**
92     * Removes a native-side observer.
93     */
94    @CalledByNative
95    public void removeNativeObserver(long nativeChangeNotifier) {
96        mNativeChangeNotifiers.remove(nativeChangeNotifier);
97    }
98
99    /**
100     * Returns the singleton instance.
101     */
102    public static NetworkChangeNotifier getInstance() {
103        assert sInstance != null;
104        return sInstance;
105    }
106
107    /**
108     * Enables auto detection of the current network state based on notifications from the system.
109     * Note that passing true here requires the embedding app have the platform ACCESS_NETWORK_STATE
110     * permission.
111     *
112     * @param shouldAutoDetect true if the NetworkChangeNotifier should listen for system changes in
113     *    network connectivity.
114     */
115    public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
116        getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
117    }
118
119    private void destroyAutoDetector() {
120        if (mAutoDetector != null) {
121            mAutoDetector.destroy();
122            mAutoDetector = null;
123        }
124    }
125
126    private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) {
127        if (shouldAutoDetect) {
128            if (mAutoDetector == null) {
129                mAutoDetector = new NetworkChangeNotifierAutoDetect(
130                    new NetworkChangeNotifierAutoDetect.Observer() {
131                        @Override
132                        public void onConnectionTypeChanged(int newConnectionType) {
133                            updateCurrentConnectionType(newConnectionType);
134                        }
135                    },
136                    mContext);
137                mCurrentConnectionType = mAutoDetector.getCurrentConnectionType();
138            }
139        } else {
140            destroyAutoDetector();
141        }
142    }
143
144    /**
145     * Updates the perceived network state when not auto-detecting changes to connectivity.
146     *
147     * @param networkAvailable True if the NetworkChangeNotifier should perceive a "connected"
148     *    state, false implies "disconnected".
149     */
150    @CalledByNative
151    public static void forceConnectivityState(boolean networkAvailable) {
152        setAutoDetectConnectivityState(false);
153        getInstance().forceConnectivityStateInternal(networkAvailable);
154    }
155
156    private void forceConnectivityStateInternal(boolean forceOnline) {
157        boolean connectionCurrentlyExists = mCurrentConnectionType != CONNECTION_NONE;
158        if (connectionCurrentlyExists != forceOnline) {
159            updateCurrentConnectionType(forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE);
160        }
161    }
162
163    private void updateCurrentConnectionType(int newConnectionType) {
164        mCurrentConnectionType = newConnectionType;
165        notifyObserversOfConnectionTypeChange(newConnectionType);
166    }
167
168    /**
169     * Alerts all observers of a connection change.
170     */
171    void notifyObserversOfConnectionTypeChange(int newConnectionType) {
172        for (Long nativeChangeNotifier : mNativeChangeNotifiers) {
173            nativeNotifyConnectionTypeChanged(nativeChangeNotifier, newConnectionType);
174        }
175        for (ConnectionTypeObserver observer : mConnectionTypeObservers) {
176            observer.onConnectionTypeChanged(newConnectionType);
177        }
178    }
179
180    /**
181     * Adds an observer for any connection type changes.
182     */
183    public static void addConnectionTypeObserver(ConnectionTypeObserver observer) {
184        getInstance().addConnectionTypeObserverInternal(observer);
185    }
186
187    private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
188        mConnectionTypeObservers.addObserver(observer);
189    }
190
191    /**
192     * Removes an observer for any connection type changes.
193     */
194    public static void removeConnectionTypeObserver(ConnectionTypeObserver observer) {
195        getInstance().removeConnectionTypeObserverInternal(observer);
196    }
197
198    private void removeConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
199        mConnectionTypeObservers.removeObserver(observer);
200    }
201
202    @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid")
203    private native void nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType);
204
205    // For testing only.
206    public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() {
207        return getInstance().mAutoDetector;
208    }
209
210    /**
211     * Checks if there currently is connectivity.
212     */
213    public static boolean isOnline() {
214        int connectionType = getInstance().getCurrentConnectionType();
215        return connectionType != CONNECTION_UNKNOWN && connectionType != CONNECTION_NONE;
216    }
217}
218