Home | History | Annotate | Download | only in net
      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 
      5 package org.chromium.net;
      6 
      7 import android.content.Context;
      8 
      9 import org.chromium.base.CalledByNative;
     10 import org.chromium.base.JNINamespace;
     11 import org.chromium.base.NativeClassQualifiedName;
     12 import org.chromium.base.ObserverList;
     13 
     14 import 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")
     27 public 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     public static final int CONNECTION_BLUETOOTH = 7;
     45 
     46     private final Context mContext;
     47     private final ArrayList<Long> mNativeChangeNotifiers;
     48     private final ObserverList<ConnectionTypeObserver> mConnectionTypeObservers;
     49     private NetworkChangeNotifierAutoDetect mAutoDetector;
     50     private int mCurrentConnectionType = CONNECTION_UNKNOWN;
     51 
     52     private static NetworkChangeNotifier sInstance;
     53 
     54     private NetworkChangeNotifier(Context context) {
     55         mContext = context.getApplicationContext();
     56         mNativeChangeNotifiers = new ArrayList<Long>();
     57         mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>();
     58     }
     59 
     60     /**
     61      * Initializes the singleton once.
     62      */
     63     @CalledByNative
     64     public static NetworkChangeNotifier init(Context context) {
     65         if (sInstance == null) {
     66             sInstance = new NetworkChangeNotifier(context);
     67         }
     68         return sInstance;
     69     }
     70 
     71     public static boolean isInitialized() {
     72         return sInstance != null;
     73     }
     74 
     75     static void resetInstanceForTests(Context context) {
     76         sInstance = new NetworkChangeNotifier(context);
     77     }
     78 
     79     @CalledByNative
     80     public int getCurrentConnectionType() {
     81         return mCurrentConnectionType;
     82     }
     83 
     84     /**
     85      * Adds a native-side observer.
     86      */
     87     @CalledByNative
     88     public void addNativeObserver(long nativeChangeNotifier) {
     89         mNativeChangeNotifiers.add(nativeChangeNotifier);
     90     }
     91 
     92     /**
     93      * Removes a native-side observer.
     94      */
     95     @CalledByNative
     96     public void removeNativeObserver(long nativeChangeNotifier) {
     97         mNativeChangeNotifiers.remove(nativeChangeNotifier);
     98     }
     99 
    100     /**
    101      * Returns the singleton instance.
    102      */
    103     public static NetworkChangeNotifier getInstance() {
    104         assert sInstance != null;
    105         return sInstance;
    106     }
    107 
    108     /**
    109      * Enables auto detection of the current network state based on notifications from the system.
    110      * Note that passing true here requires the embedding app have the platform ACCESS_NETWORK_STATE
    111      * permission.
    112      *
    113      * @param shouldAutoDetect true if the NetworkChangeNotifier should listen for system changes in
    114      *    network connectivity.
    115      */
    116     public static void setAutoDetectConnectivityState(boolean shouldAutoDetect) {
    117         getInstance().setAutoDetectConnectivityStateInternal(shouldAutoDetect);
    118     }
    119 
    120     private void destroyAutoDetector() {
    121         if (mAutoDetector != null) {
    122             mAutoDetector.destroy();
    123             mAutoDetector = null;
    124         }
    125     }
    126 
    127     private void setAutoDetectConnectivityStateInternal(boolean shouldAutoDetect) {
    128         if (shouldAutoDetect) {
    129             if (mAutoDetector == null) {
    130                 mAutoDetector = new NetworkChangeNotifierAutoDetect(
    131                     new NetworkChangeNotifierAutoDetect.Observer() {
    132                         @Override
    133                         public void onConnectionTypeChanged(int newConnectionType) {
    134                             updateCurrentConnectionType(newConnectionType);
    135                         }
    136                     },
    137                     mContext);
    138                 updateCurrentConnectionType(mAutoDetector.getCurrentConnectionType());
    139             }
    140         } else {
    141             destroyAutoDetector();
    142         }
    143     }
    144 
    145     /**
    146      * Updates the perceived network state when not auto-detecting changes to connectivity.
    147      *
    148      * @param networkAvailable True if the NetworkChangeNotifier should perceive a "connected"
    149      *    state, false implies "disconnected".
    150      */
    151     @CalledByNative
    152     public static void forceConnectivityState(boolean networkAvailable) {
    153         setAutoDetectConnectivityState(false);
    154         getInstance().forceConnectivityStateInternal(networkAvailable);
    155     }
    156 
    157     private void forceConnectivityStateInternal(boolean forceOnline) {
    158         boolean connectionCurrentlyExists = mCurrentConnectionType != CONNECTION_NONE;
    159         if (connectionCurrentlyExists != forceOnline) {
    160             updateCurrentConnectionType(forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE);
    161         }
    162     }
    163 
    164     private void updateCurrentConnectionType(int newConnectionType) {
    165         mCurrentConnectionType = newConnectionType;
    166         notifyObserversOfConnectionTypeChange(newConnectionType);
    167     }
    168 
    169     /**
    170      * Alerts all observers of a connection change.
    171      */
    172     void notifyObserversOfConnectionTypeChange(int newConnectionType) {
    173         for (Long nativeChangeNotifier : mNativeChangeNotifiers) {
    174             nativeNotifyConnectionTypeChanged(nativeChangeNotifier, newConnectionType);
    175         }
    176         for (ConnectionTypeObserver observer : mConnectionTypeObservers) {
    177             observer.onConnectionTypeChanged(newConnectionType);
    178         }
    179     }
    180 
    181     /**
    182      * Adds an observer for any connection type changes.
    183      */
    184     public static void addConnectionTypeObserver(ConnectionTypeObserver observer) {
    185         getInstance().addConnectionTypeObserverInternal(observer);
    186     }
    187 
    188     private void addConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
    189         mConnectionTypeObservers.addObserver(observer);
    190     }
    191 
    192     /**
    193      * Removes an observer for any connection type changes.
    194      */
    195     public static void removeConnectionTypeObserver(ConnectionTypeObserver observer) {
    196         getInstance().removeConnectionTypeObserverInternal(observer);
    197     }
    198 
    199     private void removeConnectionTypeObserverInternal(ConnectionTypeObserver observer) {
    200         mConnectionTypeObservers.removeObserver(observer);
    201     }
    202 
    203     @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid")
    204     private native void nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType);
    205 
    206     // For testing only.
    207     public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() {
    208         return getInstance().mAutoDetector;
    209     }
    210 
    211     /**
    212      * Checks if there currently is connectivity.
    213      */
    214     public static boolean isOnline() {
    215         int connectionType = getInstance().getCurrentConnectionType();
    216         return connectionType != CONNECTION_UNKNOWN && connectionType != CONNECTION_NONE;
    217     }
    218 }
    219