Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net.wifi;
     18 
     19 import android.annotation.SdkConstant;
     20 import android.annotation.SdkConstant.SdkConstantType;
     21 import android.content.Context;
     22 import android.net.DhcpInfo;
     23 import android.os.Binder;
     24 import android.os.IBinder;
     25 import android.os.Handler;
     26 import android.os.HandlerThread;
     27 import android.os.Looper;
     28 import android.os.Message;
     29 import android.os.RemoteException;
     30 import android.os.WorkSource;
     31 import android.os.Messenger;
     32 import android.util.Log;
     33 import android.util.SparseArray;
     34 
     35 import java.util.concurrent.CountDownLatch;
     36 
     37 import com.android.internal.util.AsyncChannel;
     38 import com.android.internal.util.Protocol;
     39 
     40 import java.util.List;
     41 
     42 /**
     43  * This class provides the primary API for managing all aspects of Wi-Fi
     44  * connectivity. Get an instance of this class by calling
     45  * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
     46 
     47  * It deals with several categories of items:
     48  * <ul>
     49  * <li>The list of configured networks. The list can be viewed and updated,
     50  * and attributes of individual entries can be modified.</li>
     51  * <li>The currently active Wi-Fi network, if any. Connectivity can be
     52  * established or torn down, and dynamic information about the state of
     53  * the network can be queried.</li>
     54  * <li>Results of access point scans, containing enough information to
     55  * make decisions about what access point to connect to.</li>
     56  * <li>It defines the names of various Intent actions that are broadcast
     57  * upon any sort of change in Wi-Fi state.
     58  * </ul>
     59  * This is the API to use when performing Wi-Fi specific operations. To
     60  * perform operations that pertain to network connectivity at an abstract
     61  * level, use {@link android.net.ConnectivityManager}.
     62  */
     63 public class WifiManager {
     64 
     65     private static final String TAG = "WifiManager";
     66     // Supplicant error codes:
     67     /**
     68      * The error code if there was a problem authenticating.
     69      */
     70     public static final int ERROR_AUTHENTICATING = 1;
     71 
     72     /**
     73      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
     74      * enabling, disabling, or unknown. One extra provides this state as an int.
     75      * Another extra provides the previous state, if available.
     76      *
     77      * @see #EXTRA_WIFI_STATE
     78      * @see #EXTRA_PREVIOUS_WIFI_STATE
     79      */
     80     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     81     public static final String WIFI_STATE_CHANGED_ACTION =
     82         "android.net.wifi.WIFI_STATE_CHANGED";
     83     /**
     84      * The lookup key for an int that indicates whether Wi-Fi is enabled,
     85      * disabled, enabling, disabling, or unknown.  Retrieve it with
     86      * {@link android.content.Intent#getIntExtra(String,int)}.
     87      *
     88      * @see #WIFI_STATE_DISABLED
     89      * @see #WIFI_STATE_DISABLING
     90      * @see #WIFI_STATE_ENABLED
     91      * @see #WIFI_STATE_ENABLING
     92      * @see #WIFI_STATE_UNKNOWN
     93      */
     94     public static final String EXTRA_WIFI_STATE = "wifi_state";
     95     /**
     96      * The previous Wi-Fi state.
     97      *
     98      * @see #EXTRA_WIFI_STATE
     99      */
    100     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
    101 
    102     /**
    103      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
    104      * it finishes successfully.
    105      *
    106      * @see #WIFI_STATE_CHANGED_ACTION
    107      * @see #getWifiState()
    108      */
    109     public static final int WIFI_STATE_DISABLING = 0;
    110     /**
    111      * Wi-Fi is disabled.
    112      *
    113      * @see #WIFI_STATE_CHANGED_ACTION
    114      * @see #getWifiState()
    115      */
    116     public static final int WIFI_STATE_DISABLED = 1;
    117     /**
    118      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
    119      * it finishes successfully.
    120      *
    121      * @see #WIFI_STATE_CHANGED_ACTION
    122      * @see #getWifiState()
    123      */
    124     public static final int WIFI_STATE_ENABLING = 2;
    125     /**
    126      * Wi-Fi is enabled.
    127      *
    128      * @see #WIFI_STATE_CHANGED_ACTION
    129      * @see #getWifiState()
    130      */
    131     public static final int WIFI_STATE_ENABLED = 3;
    132     /**
    133      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
    134      * or disabling.
    135      *
    136      * @see #WIFI_STATE_CHANGED_ACTION
    137      * @see #getWifiState()
    138      */
    139     public static final int WIFI_STATE_UNKNOWN = 4;
    140 
    141     /**
    142      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
    143      * enabling, disabling, or failed.
    144      *
    145      * @hide
    146      */
    147     public static final String WIFI_AP_STATE_CHANGED_ACTION =
    148         "android.net.wifi.WIFI_AP_STATE_CHANGED";
    149 
    150     /**
    151      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
    152      * disabled, enabling, disabling, or failed.  Retrieve it with
    153      * {@link android.content.Intent#getIntExtra(String,int)}.
    154      *
    155      * @see #WIFI_AP_STATE_DISABLED
    156      * @see #WIFI_AP_STATE_DISABLING
    157      * @see #WIFI_AP_STATE_ENABLED
    158      * @see #WIFI_AP_STATE_ENABLING
    159      * @see #WIFI_AP_STATE_FAILED
    160      *
    161      * @hide
    162      */
    163     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
    164     /**
    165      * The previous Wi-Fi state.
    166      *
    167      * @see #EXTRA_WIFI_AP_STATE
    168      *
    169      * @hide
    170      */
    171     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
    172     /**
    173      * Wi-Fi AP is currently being disabled. The state will change to
    174      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
    175      *
    176      * @see #WIFI_AP_STATE_CHANGED_ACTION
    177      * @see #getWifiApState()
    178      *
    179      * @hide
    180      */
    181     public static final int WIFI_AP_STATE_DISABLING = 10;
    182     /**
    183      * Wi-Fi AP is disabled.
    184      *
    185      * @see #WIFI_AP_STATE_CHANGED_ACTION
    186      * @see #getWifiState()
    187      *
    188      * @hide
    189      */
    190     public static final int WIFI_AP_STATE_DISABLED = 11;
    191     /**
    192      * Wi-Fi AP is currently being enabled. The state will change to
    193      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
    194      *
    195      * @see #WIFI_AP_STATE_CHANGED_ACTION
    196      * @see #getWifiApState()
    197      *
    198      * @hide
    199      */
    200     public static final int WIFI_AP_STATE_ENABLING = 12;
    201     /**
    202      * Wi-Fi AP is enabled.
    203      *
    204      * @see #WIFI_AP_STATE_CHANGED_ACTION
    205      * @see #getWifiApState()
    206      *
    207      * @hide
    208      */
    209     public static final int WIFI_AP_STATE_ENABLED = 13;
    210     /**
    211      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
    212      * enabling or disabling
    213      *
    214      * @see #WIFI_AP_STATE_CHANGED_ACTION
    215      * @see #getWifiApState()
    216      *
    217      * @hide
    218      */
    219     public static final int WIFI_AP_STATE_FAILED = 14;
    220 
    221     /**
    222      * Broadcast intent action indicating that a connection to the supplicant has
    223      * been established (and it is now possible
    224      * to perform Wi-Fi operations) or the connection to the supplicant has been
    225      * lost. One extra provides the connection state as a boolean, where {@code true}
    226      * means CONNECTED.
    227      * @see #EXTRA_SUPPLICANT_CONNECTED
    228      */
    229     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    230     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
    231         "android.net.wifi.supplicant.CONNECTION_CHANGE";
    232     /**
    233      * The lookup key for a boolean that indicates whether a connection to
    234      * the supplicant daemon has been gained or lost. {@code true} means
    235      * a connection now exists.
    236      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
    237      */
    238     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
    239     /**
    240      * Broadcast intent action indicating that the state of Wi-Fi connectivity
    241      * has changed. One extra provides the new state
    242      * in the form of a {@link android.net.NetworkInfo} object. If the new
    243      * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of
    244      * the access point.
    245      * as a {@code String}.
    246      * @see #EXTRA_NETWORK_INFO
    247      * @see #EXTRA_BSSID
    248      * @see #EXTRA_WIFI_INFO
    249      */
    250     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    251     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
    252     /**
    253      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
    254      * Wi-Fi network. Retrieve with
    255      * {@link android.content.Intent#getParcelableExtra(String)}.
    256      */
    257     public static final String EXTRA_NETWORK_INFO = "networkInfo";
    258     /**
    259      * The lookup key for a String giving the BSSID of the access point to which
    260      * we are connected. Only present when the new state is CONNECTED.
    261      * Retrieve with
    262      * {@link android.content.Intent#getStringExtra(String)}.
    263      */
    264     public static final String EXTRA_BSSID = "bssid";
    265     /**
    266      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
    267      * information about the access point to which we are connected. Only present
    268      * when the new state is CONNECTED.  Retrieve with
    269      * {@link android.content.Intent#getParcelableExtra(String)}.
    270      */
    271     public static final String EXTRA_WIFI_INFO = "wifiInfo";
    272     /**
    273      * Broadcast intent action indicating that the state of establishing a connection to
    274      * an access point has changed.One extra provides the new
    275      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
    276      * is not generally the most useful thing to look at if you are just interested in
    277      * the overall state of connectivity.
    278      * @see #EXTRA_NEW_STATE
    279      * @see #EXTRA_SUPPLICANT_ERROR
    280      */
    281     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    282     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
    283         "android.net.wifi.supplicant.STATE_CHANGE";
    284     /**
    285      * The lookup key for a {@link SupplicantState} describing the new state
    286      * Retrieve with
    287      * {@link android.content.Intent#getParcelableExtra(String)}.
    288      */
    289     public static final String EXTRA_NEW_STATE = "newState";
    290 
    291     /**
    292      * The lookup key for a {@link SupplicantState} describing the supplicant
    293      * error code if any
    294      * Retrieve with
    295      * {@link android.content.Intent#getIntExtra(String, int)}.
    296      * @see #ERROR_AUTHENTICATING
    297      */
    298     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
    299 
    300     /**
    301      * Broadcast intent action indicating that the configured networks changed.
    302      * This can be as a result of adding/updating/deleting a network. If
    303      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration
    304      * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple
    305      * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present.
    306      * @hide
    307      */
    308     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
    309         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
    310     /**
    311      * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing
    312      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
    313      * broadcast is sent.
    314      * @hide
    315      */
    316     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
    317     /**
    318      * Multiple network configurations have changed.
    319      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
    320      *
    321      * @hide
    322      */
    323     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
    324     /**
    325      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
    326      * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false}
    327      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
    328      * @hide
    329      */
    330     public static final String EXTRA_CHANGE_REASON = "changeReason";
    331     /**
    332      * The configuration is new and was added.
    333      * @hide
    334      */
    335     public static final int CHANGE_REASON_ADDED = 0;
    336     /**
    337      * The configuration was removed and is no longer present in the system's list of
    338      * configured networks.
    339      * @hide
    340      */
    341     public static final int CHANGE_REASON_REMOVED = 1;
    342     /**
    343      * The configuration has changed as a result of explicit action or because the system
    344      * took an automated action such as disabling a malfunctioning configuration.
    345      * @hide
    346      */
    347     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
    348     /**
    349      * An access point scan has completed, and results are available from the supplicant.
    350      * Call {@link #getScanResults()} to obtain the results.
    351      */
    352     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    353     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
    354     /**
    355      * The RSSI (signal strength) has changed.
    356      * @see #EXTRA_NEW_RSSI
    357      */
    358     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    359     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
    360     /**
    361      * The lookup key for an {@code int} giving the new RSSI in dBm.
    362      */
    363     public static final String EXTRA_NEW_RSSI = "newRssi";
    364 
    365     /**
    366      * Broadcast intent action indicating that the link configuration
    367      * changed on wifi.
    368      * @hide
    369      */
    370     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
    371         "android.net.wifi.LINK_CONFIGURATION_CHANGED";
    372 
    373     /**
    374      * The lookup key for a {@link android.net.LinkProperties} object associated with the
    375      * Wi-Fi network. Retrieve with
    376      * {@link android.content.Intent#getParcelableExtra(String)}.
    377      * @hide
    378      */
    379     public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
    380 
    381     /**
    382      * The lookup key for a {@link android.net.LinkCapabilities} object associated with the
    383      * Wi-Fi network. Retrieve with
    384      * {@link android.content.Intent#getParcelableExtra(String)}.
    385      * @hide
    386      */
    387     public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
    388 
    389     /**
    390      * The network IDs of the configured networks could have changed.
    391      */
    392     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    393     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
    394 
    395     /**
    396      * Activity Action: Pick a Wi-Fi network to connect to.
    397      * <p>Input: Nothing.
    398      * <p>Output: Nothing.
    399      */
    400     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    401     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
    402 
    403     /**
    404      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
    405      * and will behave normally, i.e., it will attempt to automatically
    406      * establish a connection to a remembered access point that is
    407      * within range, and will do periodic scans if there are remembered
    408      * access points but none are in range.
    409      */
    410     public static final int WIFI_MODE_FULL = 1;
    411     /**
    412      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
    413      * but the only operation that will be supported is initiation of
    414      * scans, and the subsequent reporting of scan results. No attempts
    415      * will be made to automatically connect to remembered access points,
    416      * nor will periodic scans be automatically performed looking for
    417      * remembered access points. Scans must be explicitly requested by
    418      * an application in this mode.
    419      */
    420     public static final int WIFI_MODE_SCAN_ONLY = 2;
    421     /**
    422      * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode
    423      * {@link #WIFI_MODE_FULL} but it operates at high performance
    424      * with minimum packet loss and low packet latency even when
    425      * the device screen is off. This mode will consume more power
    426      * and hence should be used only when there is a need for such
    427      * an active connection.
    428      * <p>
    429      * An example use case is when a voice connection needs to be
    430      * kept active even after the device screen goes off. Holding the
    431      * regular {@link #WIFI_MODE_FULL} lock will keep the wifi
    432      * connection active, but the connection can be lossy.
    433      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
    434      * duration of the voice call will improve the call quality.
    435      * <p>
    436      * When there is no support from the hardware, this lock mode
    437      * will have the same behavior as {@link #WIFI_MODE_FULL}
    438      */
    439     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
    440 
    441     /** Anything worse than or equal to this will show 0 bars. */
    442     private static final int MIN_RSSI = -100;
    443 
    444     /** Anything better than or equal to this will show the max bars. */
    445     private static final int MAX_RSSI = -55;
    446 
    447     /**
    448      * Number of RSSI levels used in the framework to initiate
    449      * {@link #RSSI_CHANGED_ACTION} broadcast
    450      * @hide
    451      */
    452     public static final int RSSI_LEVELS = 5;
    453 
    454     /**
    455      * Auto settings in the driver. The driver could choose to operate on both
    456      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
    457      * @hide
    458      */
    459     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
    460 
    461     /**
    462      * Operation on 5 GHz alone
    463      * @hide
    464      */
    465     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
    466 
    467     /**
    468      * Operation on 2.4 GHz alone
    469      * @hide
    470      */
    471     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
    472 
    473     /** List of asyncronous notifications
    474      * @hide
    475      */
    476     public static final int DATA_ACTIVITY_NOTIFICATION = 1;
    477 
    478     //Lowest bit indicates data reception and the second lowest
    479     //bit indicates data transmitted
    480     /** @hide */
    481     public static final int DATA_ACTIVITY_NONE         = 0x00;
    482     /** @hide */
    483     public static final int DATA_ACTIVITY_IN           = 0x01;
    484     /** @hide */
    485     public static final int DATA_ACTIVITY_OUT          = 0x02;
    486     /** @hide */
    487     public static final int DATA_ACTIVITY_INOUT        = 0x03;
    488 
    489     /* Maximum number of active locks we allow.
    490      * This limit was added to prevent apps from creating a ridiculous number
    491      * of locks and crashing the system by overflowing the global ref table.
    492      */
    493     private static final int MAX_ACTIVE_LOCKS = 50;
    494 
    495     /* Number of currently active WifiLocks and MulticastLocks */
    496     private int mActiveLockCount;
    497 
    498     private Context mContext;
    499     IWifiManager mService;
    500 
    501     private static final int INVALID_KEY = 0;
    502     private int mListenerKey = 1;
    503     private final SparseArray mListenerMap = new SparseArray();
    504     private final Object mListenerMapLock = new Object();
    505 
    506     private AsyncChannel mAsyncChannel = new AsyncChannel();
    507     private ServiceHandler mHandler;
    508     private Messenger mWifiServiceMessenger;
    509     private final CountDownLatch mConnected = new CountDownLatch(1);
    510 
    511     /**
    512      * Create a new WifiManager instance.
    513      * Applications will almost always want to use
    514      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
    515      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
    516      * @param context the application context
    517      * @param service the Binder interface
    518      * @hide - hide this because it takes in a parameter of type IWifiManager, which
    519      * is a system private class.
    520      */
    521     public WifiManager(Context context, IWifiManager service) {
    522         mContext = context;
    523         mService = service;
    524         init();
    525     }
    526 
    527     /**
    528      * Return a list of all the networks configured in the supplicant.
    529      * Not all fields of WifiConfiguration are returned. Only the following
    530      * fields are filled in:
    531      * <ul>
    532      * <li>networkId</li>
    533      * <li>SSID</li>
    534      * <li>BSSID</li>
    535      * <li>priority</li>
    536      * <li>allowedProtocols</li>
    537      * <li>allowedKeyManagement</li>
    538      * <li>allowedAuthAlgorithms</li>
    539      * <li>allowedPairwiseCiphers</li>
    540      * <li>allowedGroupCiphers</li>
    541      * </ul>
    542      * @return a list of network configurations in the form of a list
    543      * of {@link WifiConfiguration} objects. Upon failure to fetch or
    544      * when when Wi-Fi is turned off, it can be null.
    545      */
    546     public List<WifiConfiguration> getConfiguredNetworks() {
    547         try {
    548             return mService.getConfiguredNetworks();
    549         } catch (RemoteException e) {
    550             return null;
    551         }
    552     }
    553 
    554     /**
    555      * Add a new network description to the set of configured networks.
    556      * The {@code networkId} field of the supplied configuration object
    557      * is ignored.
    558      * <p/>
    559      * The new network will be marked DISABLED by default. To enable it,
    560      * called {@link #enableNetwork}.
    561      *
    562      * @param config the set of variables that describe the configuration,
    563      *            contained in a {@link WifiConfiguration} object.
    564      * @return the ID of the newly created network description. This is used in
    565      *         other operations to specified the network to be acted upon.
    566      *         Returns {@code -1} on failure.
    567      */
    568     public int addNetwork(WifiConfiguration config) {
    569         if (config == null) {
    570             return -1;
    571         }
    572         config.networkId = -1;
    573         return addOrUpdateNetwork(config);
    574     }
    575 
    576     /**
    577      * Update the network description of an existing configured network.
    578      *
    579      * @param config the set of variables that describe the configuration,
    580      *            contained in a {@link WifiConfiguration} object. It may
    581      *            be sparse, so that only the items that are being changed
    582      *            are non-<code>null</code>. The {@code networkId} field
    583      *            must be set to the ID of the existing network being updated.
    584      * @return Returns the {@code networkId} of the supplied
    585      *         {@code WifiConfiguration} on success.
    586      *         <br/>
    587      *         Returns {@code -1} on failure, including when the {@code networkId}
    588      *         field of the {@code WifiConfiguration} does not refer to an
    589      *         existing network.
    590      */
    591     public int updateNetwork(WifiConfiguration config) {
    592         if (config == null || config.networkId < 0) {
    593             return -1;
    594         }
    595         return addOrUpdateNetwork(config);
    596     }
    597 
    598     /**
    599      * Internal method for doing the RPC that creates a new network description
    600      * or updates an existing one.
    601      *
    602      * @param config The possibly sparse object containing the variables that
    603      *         are to set or updated in the network description.
    604      * @return the ID of the network on success, {@code -1} on failure.
    605      */
    606     private int addOrUpdateNetwork(WifiConfiguration config) {
    607         try {
    608             return mService.addOrUpdateNetwork(config);
    609         } catch (RemoteException e) {
    610             return -1;
    611         }
    612     }
    613 
    614     /**
    615      * Remove the specified network from the list of configured networks.
    616      * This may result in the asynchronous delivery of state change
    617      * events.
    618      * @param netId the integer that identifies the network configuration
    619      * to the supplicant
    620      * @return {@code true} if the operation succeeded
    621      */
    622     public boolean removeNetwork(int netId) {
    623         try {
    624             return mService.removeNetwork(netId);
    625         } catch (RemoteException e) {
    626             return false;
    627         }
    628     }
    629 
    630     /**
    631      * Allow a previously configured network to be associated with. If
    632      * <code>disableOthers</code> is true, then all other configured
    633      * networks are disabled, and an attempt to connect to the selected
    634      * network is initiated. This may result in the asynchronous delivery
    635      * of state change events.
    636      * @param netId the ID of the network in the list of configured networks
    637      * @param disableOthers if true, disable all other networks. The way to
    638      * select a particular network to connect to is specify {@code true}
    639      * for this parameter.
    640      * @return {@code true} if the operation succeeded
    641      */
    642     public boolean enableNetwork(int netId, boolean disableOthers) {
    643         try {
    644             return mService.enableNetwork(netId, disableOthers);
    645         } catch (RemoteException e) {
    646             return false;
    647         }
    648     }
    649 
    650     /**
    651      * Disable a configured network. The specified network will not be
    652      * a candidate for associating. This may result in the asynchronous
    653      * delivery of state change events.
    654      * @param netId the ID of the network as returned by {@link #addNetwork}.
    655      * @return {@code true} if the operation succeeded
    656      */
    657     public boolean disableNetwork(int netId) {
    658         try {
    659             return mService.disableNetwork(netId);
    660         } catch (RemoteException e) {
    661             return false;
    662         }
    663     }
    664 
    665     /**
    666      * Disassociate from the currently active access point. This may result
    667      * in the asynchronous delivery of state change events.
    668      * @return {@code true} if the operation succeeded
    669      */
    670     public boolean disconnect() {
    671         try {
    672             mService.disconnect();
    673             return true;
    674         } catch (RemoteException e) {
    675             return false;
    676         }
    677     }
    678 
    679     /**
    680      * Reconnect to the currently active access point, if we are currently
    681      * disconnected. This may result in the asynchronous delivery of state
    682      * change events.
    683      * @return {@code true} if the operation succeeded
    684      */
    685     public boolean reconnect() {
    686         try {
    687             mService.reconnect();
    688             return true;
    689         } catch (RemoteException e) {
    690             return false;
    691         }
    692     }
    693 
    694     /**
    695      * Reconnect to the currently active access point, even if we are already
    696      * connected. This may result in the asynchronous delivery of state
    697      * change events.
    698      * @return {@code true} if the operation succeeded
    699      */
    700     public boolean reassociate() {
    701         try {
    702             mService.reassociate();
    703             return true;
    704         } catch (RemoteException e) {
    705             return false;
    706         }
    707     }
    708 
    709     /**
    710      * Check that the supplicant daemon is responding to requests.
    711      * @return {@code true} if we were able to communicate with the supplicant and
    712      * it returned the expected response to the PING message.
    713      */
    714     public boolean pingSupplicant() {
    715         if (mService == null)
    716             return false;
    717         try {
    718             return mService.pingSupplicant();
    719         } catch (RemoteException e) {
    720             return false;
    721         }
    722     }
    723 
    724     /**
    725      * Request a scan for access points. Returns immediately. The availability
    726      * of the results is made known later by means of an asynchronous event sent
    727      * on completion of the scan.
    728      * @return {@code true} if the operation succeeded, i.e., the scan was initiated
    729      */
    730     public boolean startScan() {
    731         try {
    732             mService.startScan(false);
    733             return true;
    734         } catch (RemoteException e) {
    735             return false;
    736         }
    737     }
    738 
    739     /**
    740      * Request a scan for access points. Returns immediately. The availability
    741      * of the results is made known later by means of an asynchronous event sent
    742      * on completion of the scan.
    743      * This is a variant of startScan that forces an active scan, even if passive
    744      * scans are the current default
    745      * @return {@code true} if the operation succeeded, i.e., the scan was initiated
    746      *
    747      * @hide
    748      */
    749     public boolean startScanActive() {
    750         try {
    751             mService.startScan(true);
    752             return true;
    753         } catch (RemoteException e) {
    754             return false;
    755         }
    756     }
    757 
    758     /**
    759      * Return dynamic information about the current Wi-Fi connection, if any is active.
    760      * @return the Wi-Fi information, contained in {@link WifiInfo}.
    761      */
    762     public WifiInfo getConnectionInfo() {
    763         try {
    764             return mService.getConnectionInfo();
    765         } catch (RemoteException e) {
    766             return null;
    767         }
    768     }
    769 
    770     /**
    771      * Return the results of the latest access point scan.
    772      * @return the list of access points found in the most recent scan.
    773      */
    774     public List<ScanResult> getScanResults() {
    775         try {
    776             return mService.getScanResults();
    777         } catch (RemoteException e) {
    778             return null;
    779         }
    780     }
    781 
    782     /**
    783      * Tell the supplicant to persist the current list of configured networks.
    784      * <p>
    785      * Note: It is possible for this method to change the network IDs of
    786      * existing networks. You should assume the network IDs can be different
    787      * after calling this method.
    788      *
    789      * @return {@code true} if the operation succeeded
    790      */
    791     public boolean saveConfiguration() {
    792         try {
    793             return mService.saveConfiguration();
    794         } catch (RemoteException e) {
    795             return false;
    796         }
    797     }
    798 
    799     /**
    800      * Set the country code.
    801      * @param countryCode country code in ISO 3166 format.
    802      * @param persist {@code true} if this needs to be remembered
    803      *
    804      * @hide
    805      */
    806     public void setCountryCode(String country, boolean persist) {
    807         try {
    808             mService.setCountryCode(country, persist);
    809         } catch (RemoteException e) { }
    810     }
    811 
    812     /**
    813      * Set the operational frequency band.
    814      * @param band  One of
    815      *     {@link #WIFI_FREQUENCY_BAND_AUTO},
    816      *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
    817      *     {@link #WIFI_FREQUENCY_BAND_2GHZ},
    818      * @param persist {@code true} if this needs to be remembered
    819      * @hide
    820      */
    821     public void setFrequencyBand(int band, boolean persist) {
    822         try {
    823             mService.setFrequencyBand(band, persist);
    824         } catch (RemoteException e) { }
    825     }
    826 
    827     /**
    828      * Get the operational frequency band.
    829      * @return One of
    830      *     {@link #WIFI_FREQUENCY_BAND_AUTO},
    831      *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
    832      *     {@link #WIFI_FREQUENCY_BAND_2GHZ} or
    833      *     {@code -1} on failure.
    834      * @hide
    835      */
    836     public int getFrequencyBand() {
    837         try {
    838             return mService.getFrequencyBand();
    839         } catch (RemoteException e) {
    840             return -1;
    841         }
    842     }
    843 
    844     /**
    845      * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
    846      * @return {@code true} if supported, {@code false} otherwise.
    847      * @hide
    848      */
    849     public boolean isDualBandSupported() {
    850         try {
    851             return mService.isDualBandSupported();
    852         } catch (RemoteException e) {
    853             return false;
    854         }
    855     }
    856 
    857     /**
    858      * Return the DHCP-assigned addresses from the last successful DHCP request,
    859      * if any.
    860      * @return the DHCP information
    861      */
    862     public DhcpInfo getDhcpInfo() {
    863         try {
    864             return mService.getDhcpInfo();
    865         } catch (RemoteException e) {
    866             return null;
    867         }
    868     }
    869 
    870 
    871     /**
    872      * Enable or disable Wi-Fi.
    873      * @param enabled {@code true} to enable, {@code false} to disable.
    874      * @return {@code true} if the operation succeeds (or if the existing state
    875      *         is the same as the requested state).
    876      */
    877     public boolean setWifiEnabled(boolean enabled) {
    878         try {
    879             return mService.setWifiEnabled(enabled);
    880         } catch (RemoteException e) {
    881             return false;
    882         }
    883     }
    884 
    885     /**
    886      * Gets the Wi-Fi enabled state.
    887      * @return One of {@link #WIFI_STATE_DISABLED},
    888      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
    889      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
    890      * @see #isWifiEnabled()
    891      */
    892     public int getWifiState() {
    893         try {
    894             return mService.getWifiEnabledState();
    895         } catch (RemoteException e) {
    896             return WIFI_STATE_UNKNOWN;
    897         }
    898     }
    899 
    900     /**
    901      * Return whether Wi-Fi is enabled or disabled.
    902      * @return {@code true} if Wi-Fi is enabled
    903      * @see #getWifiState()
    904      */
    905     public boolean isWifiEnabled() {
    906         return getWifiState() == WIFI_STATE_ENABLED;
    907     }
    908 
    909     /**
    910      * Return TX packet counter, for CTS test of WiFi watchdog.
    911      * @param listener is the interface to receive result
    912      *
    913      * @hide for CTS test only
    914      */
    915     public void getTxPacketCount(TxPacketCountListener listener) {
    916         validateChannel();
    917         mAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
    918     }
    919 
    920     /**
    921      * Calculates the level of the signal. This should be used any time a signal
    922      * is being shown.
    923      *
    924      * @param rssi The power of the signal measured in RSSI.
    925      * @param numLevels The number of levels to consider in the calculated
    926      *            level.
    927      * @return A level of the signal, given in the range of 0 to numLevels-1
    928      *         (both inclusive).
    929      */
    930     public static int calculateSignalLevel(int rssi, int numLevels) {
    931         if (rssi <= MIN_RSSI) {
    932             return 0;
    933         } else if (rssi >= MAX_RSSI) {
    934             return numLevels - 1;
    935         } else {
    936             float inputRange = (MAX_RSSI - MIN_RSSI);
    937             float outputRange = (numLevels - 1);
    938             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
    939         }
    940     }
    941 
    942     /**
    943      * Compares two signal strengths.
    944      *
    945      * @param rssiA The power of the first signal measured in RSSI.
    946      * @param rssiB The power of the second signal measured in RSSI.
    947      * @return Returns <0 if the first signal is weaker than the second signal,
    948      *         0 if the two signals have the same strength, and >0 if the first
    949      *         signal is stronger than the second signal.
    950      */
    951     public static int compareSignalLevel(int rssiA, int rssiB) {
    952         return rssiA - rssiB;
    953     }
    954 
    955     /**
    956      * Start AccessPoint mode with the specified
    957      * configuration. If the radio is already running in
    958      * AP mode, update the new configuration
    959      * Note that starting in access point mode disables station
    960      * mode operation
    961      * @param wifiConfig SSID, security and channel details as
    962      *        part of WifiConfiguration
    963      * @return {@code true} if the operation succeeds, {@code false} otherwise
    964      *
    965      * @hide Dont open up yet
    966      */
    967     public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
    968         try {
    969             mService.setWifiApEnabled(wifiConfig, enabled);
    970             return true;
    971         } catch (RemoteException e) {
    972             return false;
    973         }
    974     }
    975 
    976     /**
    977      * Gets the Wi-Fi enabled state.
    978      * @return One of {@link #WIFI_AP_STATE_DISABLED},
    979      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
    980      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
    981      * @see #isWifiApEnabled()
    982      *
    983      * @hide Dont open yet
    984      */
    985     public int getWifiApState() {
    986         try {
    987             return mService.getWifiApEnabledState();
    988         } catch (RemoteException e) {
    989             return WIFI_AP_STATE_FAILED;
    990         }
    991     }
    992 
    993     /**
    994      * Return whether Wi-Fi AP is enabled or disabled.
    995      * @return {@code true} if Wi-Fi AP is enabled
    996      * @see #getWifiApState()
    997      *
    998      * @hide Dont open yet
    999      */
   1000     public boolean isWifiApEnabled() {
   1001         return getWifiApState() == WIFI_AP_STATE_ENABLED;
   1002     }
   1003 
   1004     /**
   1005      * Gets the Wi-Fi AP Configuration.
   1006      * @return AP details in WifiConfiguration
   1007      *
   1008      * @hide Dont open yet
   1009      */
   1010     public WifiConfiguration getWifiApConfiguration() {
   1011         try {
   1012             return mService.getWifiApConfiguration();
   1013         } catch (RemoteException e) {
   1014             return null;
   1015         }
   1016     }
   1017 
   1018     /**
   1019      * Sets the Wi-Fi AP Configuration.
   1020      * @return {@code true} if the operation succeeded, {@code false} otherwise
   1021      *
   1022      * @hide Dont open yet
   1023      */
   1024     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
   1025         try {
   1026             mService.setWifiApConfiguration(wifiConfig);
   1027             return true;
   1028         } catch (RemoteException e) {
   1029             return false;
   1030         }
   1031     }
   1032 
   1033    /**
   1034      * Start the driver and connect to network.
   1035      *
   1036      * This function will over-ride WifiLock and device idle status. For example,
   1037      * even if the device is idle or there is only a scan-only lock held,
   1038      * a start wifi would mean that wifi connection is kept active until
   1039      * a stopWifi() is sent.
   1040      *
   1041      * This API is used by WifiStateTracker
   1042      *
   1043      * @return {@code true} if the operation succeeds else {@code false}
   1044      * @hide
   1045      */
   1046     public boolean startWifi() {
   1047         try {
   1048             mService.startWifi();
   1049             return true;
   1050         } catch (RemoteException e) {
   1051             return false;
   1052         }
   1053     }
   1054 
   1055     /**
   1056      * Disconnect from a network (if any) and stop the driver.
   1057      *
   1058      * This function will over-ride WifiLock and device idle status. Wi-Fi
   1059      * stays inactive until a startWifi() is issued.
   1060      *
   1061      * This API is used by WifiStateTracker
   1062      *
   1063      * @return {@code true} if the operation succeeds else {@code false}
   1064      * @hide
   1065      */
   1066     public boolean stopWifi() {
   1067         try {
   1068             mService.stopWifi();
   1069             return true;
   1070         } catch (RemoteException e) {
   1071             return false;
   1072         }
   1073     }
   1074 
   1075     /**
   1076      * Add a bssid to the supplicant blacklist
   1077      *
   1078      * This API is used by WifiWatchdogService
   1079      *
   1080      * @return {@code true} if the operation succeeds else {@code false}
   1081      * @hide
   1082      */
   1083     public boolean addToBlacklist(String bssid) {
   1084         try {
   1085             mService.addToBlacklist(bssid);
   1086             return true;
   1087         } catch (RemoteException e) {
   1088             return false;
   1089         }
   1090     }
   1091 
   1092     /**
   1093      * Clear the supplicant blacklist
   1094      *
   1095      * This API is used by WifiWatchdogService
   1096      *
   1097      * @return {@code true} if the operation succeeds else {@code false}
   1098      * @hide
   1099      */
   1100     public boolean clearBlacklist() {
   1101         try {
   1102             mService.clearBlacklist();
   1103             return true;
   1104         } catch (RemoteException e) {
   1105             return false;
   1106         }
   1107     }
   1108 
   1109     /* TODO: deprecate synchronous API and open up the following API */
   1110 
   1111     private static final int BASE = Protocol.BASE_WIFI_MANAGER;
   1112 
   1113     /* Commands to WifiService */
   1114     /** @hide */
   1115     public static final int CONNECT_NETWORK                 = BASE + 1;
   1116     /** @hide */
   1117     public static final int CONNECT_NETWORK_FAILED          = BASE + 2;
   1118     /** @hide */
   1119     public static final int CONNECT_NETWORK_SUCCEEDED       = BASE + 3;
   1120 
   1121     /** @hide */
   1122     public static final int FORGET_NETWORK                  = BASE + 4;
   1123     /** @hide */
   1124     public static final int FORGET_NETWORK_FAILED           = BASE + 5;
   1125     /** @hide */
   1126     public static final int FORGET_NETWORK_SUCCEEDED        = BASE + 6;
   1127 
   1128     /** @hide */
   1129     public static final int SAVE_NETWORK                    = BASE + 7;
   1130     /** @hide */
   1131     public static final int SAVE_NETWORK_FAILED             = BASE + 8;
   1132     /** @hide */
   1133     public static final int SAVE_NETWORK_SUCCEEDED          = BASE + 9;
   1134 
   1135     /** @hide */
   1136     public static final int START_WPS                       = BASE + 10;
   1137     /** @hide */
   1138     public static final int START_WPS_SUCCEEDED             = BASE + 11;
   1139     /** @hide */
   1140     public static final int WPS_FAILED                      = BASE + 12;
   1141     /** @hide */
   1142     public static final int WPS_COMPLETED                   = BASE + 13;
   1143 
   1144     /** @hide */
   1145     public static final int CANCEL_WPS                      = BASE + 14;
   1146     /** @hide */
   1147     public static final int CANCEL_WPS_FAILED               = BASE + 15;
   1148     /** @hide */
   1149     public static final int CANCEL_WPS_SUCCEDED             = BASE + 16;
   1150 
   1151     /** @hide */
   1152     public static final int DISABLE_NETWORK                 = BASE + 17;
   1153     /** @hide */
   1154     public static final int DISABLE_NETWORK_FAILED          = BASE + 18;
   1155     /** @hide */
   1156     public static final int DISABLE_NETWORK_SUCCEEDED       = BASE + 19;
   1157 
   1158     /** @hide */
   1159     public static final int RSSI_PKTCNT_FETCH               = BASE + 20;
   1160     /** @hide */
   1161     public static final int RSSI_PKTCNT_FETCH_SUCCEEDED     = BASE + 21;
   1162     /** @hide */
   1163     public static final int RSSI_PKTCNT_FETCH_FAILED        = BASE + 22;
   1164 
   1165     /* For system use only */
   1166     /** @hide */
   1167     public static final int ENABLE_TRAFFIC_STATS_POLL       = BASE + 31;
   1168     /** @hide */
   1169     public static final int TRAFFIC_STATS_POLL              = BASE + 32;
   1170 
   1171 
   1172     /**
   1173      * Passed with {@link ActionListener#onFailure}.
   1174      * Indicates that the operation failed due to an internal error.
   1175      * @hide
   1176      */
   1177     public static final int ERROR                       = 0;
   1178 
   1179     /**
   1180      * Passed with {@link ActionListener#onFailure}.
   1181      * Indicates that the operation is already in progress
   1182      * @hide
   1183      */
   1184     public static final int IN_PROGRESS                 = 1;
   1185 
   1186     /**
   1187      * Passed with {@link ActionListener#onFailure}.
   1188      * Indicates that the operation failed because the framework is busy and
   1189      * unable to service the request
   1190      * @hide
   1191      */
   1192     public static final int BUSY                        = 2;
   1193 
   1194     /* WPS specific errors */
   1195     /** WPS overlap detected {@hide} */
   1196     public static final int WPS_OVERLAP_ERROR           = 3;
   1197     /** WEP on WPS is prohibited {@hide} */
   1198     public static final int WPS_WEP_PROHIBITED          = 4;
   1199     /** TKIP only prohibited {@hide} */
   1200     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
   1201     /** Authentication failure on WPS {@hide} */
   1202     public static final int WPS_AUTH_FAILURE            = 6;
   1203     /** WPS timed out {@hide} */
   1204     public static final int WPS_TIMED_OUT               = 7;
   1205 
   1206     /** Interface for callback invocation on an application action {@hide} */
   1207     public interface ActionListener {
   1208         /** The operation succeeded */
   1209         public void onSuccess();
   1210         /**
   1211          * The operation failed
   1212          * @param reason The reason for failure could be one of
   1213          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
   1214          */
   1215         public void onFailure(int reason);
   1216     }
   1217 
   1218     /** Interface for callback invocation on a start WPS action {@hide} */
   1219     public interface WpsListener {
   1220         /** WPS start succeeded */
   1221         public void onStartSuccess(String pin);
   1222 
   1223         /** WPS operation completed succesfully */
   1224         public void onCompletion();
   1225 
   1226         /**
   1227          * WPS operation failed
   1228          * @param reason The reason for failure could be one of
   1229          * {@link #IN_PROGRESS}, {@link #WPS_OVERLAP_ERROR},{@link #ERROR} or {@link #BUSY}
   1230          */
   1231         public void onFailure(int reason);
   1232     }
   1233 
   1234     /** Interface for callback invocation on a TX packet count poll action {@hide} */
   1235     public interface TxPacketCountListener {
   1236         /**
   1237          * The operation succeeded
   1238          * @param count TX packet counter
   1239          */
   1240         public void onSuccess(int count);
   1241         /**
   1242          * The operation failed
   1243          * @param reason The reason for failure could be one of
   1244          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
   1245          */
   1246         public void onFailure(int reason);
   1247     }
   1248 
   1249     private class ServiceHandler extends Handler {
   1250         ServiceHandler(Looper looper) {
   1251             super(looper);
   1252         }
   1253 
   1254         @Override
   1255         public void handleMessage(Message message) {
   1256             Object listener = removeListener(message.arg2);
   1257             switch (message.what) {
   1258                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
   1259                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
   1260                         mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
   1261                     } else {
   1262                         Log.e(TAG, "Failed to set up channel connection");
   1263                         // This will cause all further async API calls on the WifiManager
   1264                         // to fail and throw an exception
   1265                         mAsyncChannel = null;
   1266                     }
   1267                     mConnected.countDown();
   1268                     break;
   1269                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
   1270                     // Ignore
   1271                     break;
   1272                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
   1273                     Log.e(TAG, "Channel connection lost");
   1274                     // This will cause all further async API calls on the WifiManager
   1275                     // to fail and throw an exception
   1276                     mAsyncChannel = null;
   1277                     getLooper().quit();
   1278                     break;
   1279                     /* ActionListeners grouped together */
   1280                 case WifiManager.CONNECT_NETWORK_FAILED:
   1281                 case WifiManager.FORGET_NETWORK_FAILED:
   1282                 case WifiManager.SAVE_NETWORK_FAILED:
   1283                 case WifiManager.CANCEL_WPS_FAILED:
   1284                 case WifiManager.DISABLE_NETWORK_FAILED:
   1285                     if (listener != null) {
   1286                         ((ActionListener) listener).onFailure(message.arg1);
   1287                     }
   1288                     break;
   1289                     /* ActionListeners grouped together */
   1290                 case WifiManager.CONNECT_NETWORK_SUCCEEDED:
   1291                 case WifiManager.FORGET_NETWORK_SUCCEEDED:
   1292                 case WifiManager.SAVE_NETWORK_SUCCEEDED:
   1293                 case WifiManager.CANCEL_WPS_SUCCEDED:
   1294                 case WifiManager.DISABLE_NETWORK_SUCCEEDED:
   1295                     if (listener != null) {
   1296                         ((ActionListener) listener).onSuccess();
   1297                     }
   1298                     break;
   1299                 case WifiManager.START_WPS_SUCCEEDED:
   1300                     if (listener != null) {
   1301                         WpsResult result = (WpsResult) message.obj;
   1302                         ((WpsListener) listener).onStartSuccess(result.pin);
   1303                         //Listener needs to stay until completion or failure
   1304                         synchronized(mListenerMapLock) {
   1305                             mListenerMap.put(message.arg2, listener);
   1306                         }
   1307                     }
   1308                     break;
   1309                 case WifiManager.WPS_COMPLETED:
   1310                     if (listener != null) {
   1311                         ((WpsListener) listener).onCompletion();
   1312                     }
   1313                     break;
   1314                 case WifiManager.WPS_FAILED:
   1315                     if (listener != null) {
   1316                         ((WpsListener) listener).onFailure(message.arg1);
   1317                     }
   1318                     break;
   1319                 case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
   1320                     if (listener != null) {
   1321                         RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj;
   1322                         if (info != null)
   1323                             ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad);
   1324                         else
   1325                             ((TxPacketCountListener) listener).onFailure(ERROR);
   1326                     }
   1327                     break;
   1328                 case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
   1329                     if (listener != null) {
   1330                         ((TxPacketCountListener) listener).onFailure(message.arg1);
   1331                     }
   1332                     break;
   1333                 default:
   1334                     //ignore
   1335                     break;
   1336             }
   1337         }
   1338     }
   1339 
   1340     private int putListener(Object listener) {
   1341         if (listener == null) return INVALID_KEY;
   1342         int key;
   1343         synchronized (mListenerMapLock) {
   1344             do {
   1345                 key = mListenerKey++;
   1346             } while (key == INVALID_KEY);
   1347             mListenerMap.put(key, listener);
   1348         }
   1349         return key;
   1350     }
   1351 
   1352     private Object removeListener(int key) {
   1353         if (key == INVALID_KEY) return null;
   1354         synchronized (mListenerMapLock) {
   1355             Object listener = mListenerMap.get(key);
   1356             mListenerMap.remove(key);
   1357             return listener;
   1358         }
   1359     }
   1360 
   1361     private void init() {
   1362         mWifiServiceMessenger = getWifiServiceMessenger();
   1363         if (mWifiServiceMessenger == null) {
   1364             mAsyncChannel = null;
   1365             return;
   1366         }
   1367 
   1368         HandlerThread t = new HandlerThread("WifiManager");
   1369         t.start();
   1370         mHandler = new ServiceHandler(t.getLooper());
   1371         mAsyncChannel.connect(mContext, mHandler, mWifiServiceMessenger);
   1372         try {
   1373             mConnected.await();
   1374         } catch (InterruptedException e) {
   1375             Log.e(TAG, "interrupted wait at init");
   1376         }
   1377     }
   1378 
   1379     private void validateChannel() {
   1380         if (mAsyncChannel == null) throw new IllegalStateException(
   1381                 "No permission to access and change wifi or a bad initialization");
   1382     }
   1383 
   1384     /**
   1385      * Connect to a network with the given configuration. The network also
   1386      * gets added to the supplicant configuration.
   1387      *
   1388      * For a new network, this function is used instead of a
   1389      * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
   1390      * reconnect()
   1391      *
   1392      * @param config the set of variables that describe the configuration,
   1393      *            contained in a {@link WifiConfiguration} object.
   1394      * @param listener for callbacks on success or failure. Can be null.
   1395      * @throws IllegalStateException if the WifiManager instance needs to be
   1396      * initialized again
   1397      *
   1398      * @hide
   1399      */
   1400     public void connect(WifiConfiguration config, ActionListener listener) {
   1401         if (config == null) throw new IllegalArgumentException("config cannot be null");
   1402         validateChannel();
   1403         // Use INVALID_NETWORK_ID for arg1 when passing a config object
   1404         // arg1 is used to pass network id when the network already exists
   1405         mAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
   1406                 putListener(listener), config);
   1407     }
   1408 
   1409     /**
   1410      * Connect to a network with the given networkId.
   1411      *
   1412      * This function is used instead of a enableNetwork(), saveConfiguration() and
   1413      * reconnect()
   1414      *
   1415      * @param networkId the network id identifiying the network in the
   1416      *                supplicant configuration list
   1417      * @param listener for callbacks on success or failure. Can be null.
   1418      * @throws IllegalStateException if the WifiManager instance needs to be
   1419      * initialized again
   1420      * @hide
   1421      */
   1422     public void connect(int networkId, ActionListener listener) {
   1423         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   1424         validateChannel();
   1425         mAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
   1426     }
   1427 
   1428     /**
   1429      * Save the given network in the supplicant config. If the network already
   1430      * exists, the configuration is updated. A new network is enabled
   1431      * by default.
   1432      *
   1433      * For a new network, this function is used instead of a
   1434      * sequence of addNetwork(), enableNetwork() and saveConfiguration().
   1435      *
   1436      * For an existing network, it accomplishes the task of updateNetwork()
   1437      * and saveConfiguration()
   1438      *
   1439      * @param config the set of variables that describe the configuration,
   1440      *            contained in a {@link WifiConfiguration} object.
   1441      * @param listener for callbacks on success or failure. Can be null.
   1442      * @throws IllegalStateException if the WifiManager instance needs to be
   1443      * initialized again
   1444      * @hide
   1445      */
   1446     public void save(WifiConfiguration config, ActionListener listener) {
   1447         if (config == null) throw new IllegalArgumentException("config cannot be null");
   1448         validateChannel();
   1449         mAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
   1450     }
   1451 
   1452     /**
   1453      * Delete the network in the supplicant config.
   1454      *
   1455      * This function is used instead of a sequence of removeNetwork()
   1456      * and saveConfiguration().
   1457      *
   1458      * @param config the set of variables that describe the configuration,
   1459      *            contained in a {@link WifiConfiguration} object.
   1460      * @param listener for callbacks on success or failure. Can be null.
   1461      * @throws IllegalStateException if the WifiManager instance needs to be
   1462      * initialized again
   1463      * @hide
   1464      */
   1465     public void forget(int netId, ActionListener listener) {
   1466         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   1467         validateChannel();
   1468         mAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener));
   1469     }
   1470 
   1471     /**
   1472      * Disable network
   1473      *
   1474      * @param netId is the network Id
   1475      * @param listener for callbacks on success or failure. Can be null.
   1476      * @throws IllegalStateException if the WifiManager instance needs to be
   1477      * initialized again
   1478      * @hide
   1479      */
   1480     public void disable(int netId, ActionListener listener) {
   1481         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   1482         validateChannel();
   1483         mAsyncChannel.sendMessage(DISABLE_NETWORK, netId, putListener(listener));
   1484     }
   1485 
   1486     /**
   1487      * Start Wi-fi Protected Setup
   1488      *
   1489      * @param config WPS configuration
   1490      * @param listener for callbacks on success or failure. Can be null.
   1491      * @throws IllegalStateException if the WifiManager instance needs to be
   1492      * initialized again
   1493      * @hide
   1494      */
   1495     public void startWps(WpsInfo config, WpsListener listener) {
   1496         if (config == null) throw new IllegalArgumentException("config cannot be null");
   1497         validateChannel();
   1498         mAsyncChannel.sendMessage(START_WPS, 0, putListener(listener), config);
   1499     }
   1500 
   1501     /**
   1502      * Cancel any ongoing Wi-fi Protected Setup
   1503      *
   1504      * @param listener for callbacks on success or failure. Can be null.
   1505      * @throws IllegalStateException if the WifiManager instance needs to be
   1506      * initialized again
   1507      * @hide
   1508      */
   1509     public void cancelWps(ActionListener listener) {
   1510         validateChannel();
   1511         mAsyncChannel.sendMessage(CANCEL_WPS, 0, putListener(listener));
   1512     }
   1513 
   1514     /**
   1515      * Get a reference to WifiService handler. This is used by a client to establish
   1516      * an AsyncChannel communication with WifiService
   1517      *
   1518      * @return Messenger pointing to the WifiService handler
   1519      * @hide
   1520      */
   1521     public Messenger getWifiServiceMessenger() {
   1522         try {
   1523             return mService.getWifiServiceMessenger();
   1524         } catch (RemoteException e) {
   1525             return null;
   1526         } catch (SecurityException e) {
   1527             return null;
   1528         }
   1529     }
   1530 
   1531     /**
   1532      * Get a reference to WifiStateMachine handler.
   1533      * @return Messenger pointing to the WifiService handler
   1534      * @hide
   1535      */
   1536     public Messenger getWifiStateMachineMessenger() {
   1537         try {
   1538             return mService.getWifiStateMachineMessenger();
   1539         } catch (RemoteException e) {
   1540             return null;
   1541         }
   1542     }
   1543 
   1544     /**
   1545      * Returns the file in which IP and proxy configuration data is stored
   1546      * @hide
   1547      */
   1548     public String getConfigFile() {
   1549         try {
   1550             return mService.getConfigFile();
   1551         } catch (RemoteException e) {
   1552             return null;
   1553         }
   1554     }
   1555 
   1556     /**
   1557      * Allows an application to keep the Wi-Fi radio awake.
   1558      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
   1559      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
   1560      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
   1561      * WifiLocks are held in any application.
   1562      * <p>
   1563      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
   1564      * could function over a mobile network, if available.  A program that needs to download large
   1565      * files should hold a WifiLock to ensure that the download will complete, but a program whose
   1566      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
   1567      * affecting battery life.
   1568      * <p>
   1569      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
   1570      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
   1571      * is idle.
   1572      * <p>
   1573      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
   1574      * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
   1575      */
   1576     public class WifiLock {
   1577         private String mTag;
   1578         private final IBinder mBinder;
   1579         private int mRefCount;
   1580         int mLockType;
   1581         private boolean mRefCounted;
   1582         private boolean mHeld;
   1583         private WorkSource mWorkSource;
   1584 
   1585         private WifiLock(int lockType, String tag) {
   1586             mTag = tag;
   1587             mLockType = lockType;
   1588             mBinder = new Binder();
   1589             mRefCount = 0;
   1590             mRefCounted = true;
   1591             mHeld = false;
   1592         }
   1593 
   1594         /**
   1595          * Locks the Wi-Fi radio on until {@link #release} is called.
   1596          *
   1597          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
   1598          * reference count, and the radio will remain locked as long as the reference count is
   1599          * above zero.
   1600          *
   1601          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
   1602          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
   1603          * will be required, regardless of the number of times that {@code acquire} is called.
   1604          */
   1605         public void acquire() {
   1606             synchronized (mBinder) {
   1607                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
   1608                     try {
   1609                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
   1610                         synchronized (WifiManager.this) {
   1611                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
   1612                                 mService.releaseWifiLock(mBinder);
   1613                                 throw new UnsupportedOperationException(
   1614                                             "Exceeded maximum number of wifi locks");
   1615                             }
   1616                             mActiveLockCount++;
   1617                         }
   1618                     } catch (RemoteException ignore) {
   1619                     }
   1620                     mHeld = true;
   1621                 }
   1622             }
   1623         }
   1624 
   1625         /**
   1626          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
   1627          *
   1628          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
   1629          * reference count, and the radio will be unlocked only when the reference count reaches
   1630          * zero.  If the reference count goes below zero (that is, if {@code release} is called
   1631          * a greater number of times than {@link #acquire}), an exception is thrown.
   1632          *
   1633          * If this WifiLock is not reference-counted, the first call to {@code release} (after
   1634          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
   1635          * calls will be ignored.
   1636          */
   1637         public void release() {
   1638             synchronized (mBinder) {
   1639                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
   1640                     try {
   1641                         mService.releaseWifiLock(mBinder);
   1642                         synchronized (WifiManager.this) {
   1643                             mActiveLockCount--;
   1644                         }
   1645                     } catch (RemoteException ignore) {
   1646                     }
   1647                     mHeld = false;
   1648                 }
   1649                 if (mRefCount < 0) {
   1650                     throw new RuntimeException("WifiLock under-locked " + mTag);
   1651                 }
   1652             }
   1653         }
   1654 
   1655         /**
   1656          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
   1657          *
   1658          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
   1659          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
   1660          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
   1661          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
   1662          * radio whenever {@link #release} is called and it is locked.
   1663          *
   1664          * @param refCounted true if this WifiLock should keep a reference count
   1665          */
   1666         public void setReferenceCounted(boolean refCounted) {
   1667             mRefCounted = refCounted;
   1668         }
   1669 
   1670         /**
   1671          * Checks whether this WifiLock is currently held.
   1672          *
   1673          * @return true if this WifiLock is held, false otherwise
   1674          */
   1675         public boolean isHeld() {
   1676             synchronized (mBinder) {
   1677                 return mHeld;
   1678             }
   1679         }
   1680 
   1681         public void setWorkSource(WorkSource ws) {
   1682             synchronized (mBinder) {
   1683                 if (ws != null && ws.size() == 0) {
   1684                     ws = null;
   1685                 }
   1686                 boolean changed = true;
   1687                 if (ws == null) {
   1688                     mWorkSource = null;
   1689                 } else if (mWorkSource == null) {
   1690                     changed = mWorkSource != null;
   1691                     mWorkSource = new WorkSource(ws);
   1692                 } else {
   1693                     changed = mWorkSource.diff(ws);
   1694                     if (changed) {
   1695                         mWorkSource.set(ws);
   1696                     }
   1697                 }
   1698                 if (changed && mHeld) {
   1699                     try {
   1700                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
   1701                     } catch (RemoteException e) {
   1702                     }
   1703                 }
   1704             }
   1705         }
   1706 
   1707         public String toString() {
   1708             String s1, s2, s3;
   1709             synchronized (mBinder) {
   1710                 s1 = Integer.toHexString(System.identityHashCode(this));
   1711                 s2 = mHeld ? "held; " : "";
   1712                 if (mRefCounted) {
   1713                     s3 = "refcounted: refcount = " + mRefCount;
   1714                 } else {
   1715                     s3 = "not refcounted";
   1716                 }
   1717                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
   1718             }
   1719         }
   1720 
   1721         @Override
   1722         protected void finalize() throws Throwable {
   1723             super.finalize();
   1724             synchronized (mBinder) {
   1725                 if (mHeld) {
   1726                     try {
   1727                         mService.releaseWifiLock(mBinder);
   1728                         synchronized (WifiManager.this) {
   1729                             mActiveLockCount--;
   1730                         }
   1731                     } catch (RemoteException ignore) {
   1732                     }
   1733                 }
   1734             }
   1735         }
   1736     }
   1737 
   1738     /**
   1739      * Creates a new WifiLock.
   1740      *
   1741      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
   1742      * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for
   1743      * descriptions of the types of Wi-Fi locks.
   1744      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
   1745      *            never shown to the user under normal conditions, but should be descriptive
   1746      *            enough to identify your application and the specific WifiLock within it, if it
   1747      *            holds multiple WifiLocks.
   1748      *
   1749      * @return a new, unacquired WifiLock with the given tag.
   1750      *
   1751      * @see WifiLock
   1752      */
   1753     public WifiLock createWifiLock(int lockType, String tag) {
   1754         return new WifiLock(lockType, tag);
   1755     }
   1756 
   1757     /**
   1758      * Creates a new WifiLock.
   1759      *
   1760      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
   1761      *            never shown to the user under normal conditions, but should be descriptive
   1762      *            enough to identify your application and the specific WifiLock within it, if it
   1763      *            holds multiple WifiLocks.
   1764      *
   1765      * @return a new, unacquired WifiLock with the given tag.
   1766      *
   1767      * @see WifiLock
   1768      */
   1769     public WifiLock createWifiLock(String tag) {
   1770         return new WifiLock(WIFI_MODE_FULL, tag);
   1771     }
   1772 
   1773 
   1774     /**
   1775      * Create a new MulticastLock
   1776      *
   1777      * @param tag a tag for the MulticastLock to identify it in debugging
   1778      *            messages.  This string is never shown to the user under
   1779      *            normal conditions, but should be descriptive enough to
   1780      *            identify your application and the specific MulticastLock
   1781      *            within it, if it holds multiple MulticastLocks.
   1782      *
   1783      * @return a new, unacquired MulticastLock with the given tag.
   1784      *
   1785      * @see MulticastLock
   1786      */
   1787     public MulticastLock createMulticastLock(String tag) {
   1788         return new MulticastLock(tag);
   1789     }
   1790 
   1791     /**
   1792      * Allows an application to receive Wifi Multicast packets.
   1793      * Normally the Wifi stack filters out packets not explicitly
   1794      * addressed to this device.  Acquring a MulticastLock will
   1795      * cause the stack to receive packets addressed to multicast
   1796      * addresses.  Processing these extra packets can cause a noticable
   1797      * battery drain and should be disabled when not needed.
   1798      */
   1799     public class MulticastLock {
   1800         private String mTag;
   1801         private final IBinder mBinder;
   1802         private int mRefCount;
   1803         private boolean mRefCounted;
   1804         private boolean mHeld;
   1805 
   1806         private MulticastLock(String tag) {
   1807             mTag = tag;
   1808             mBinder = new Binder();
   1809             mRefCount = 0;
   1810             mRefCounted = true;
   1811             mHeld = false;
   1812         }
   1813 
   1814         /**
   1815          * Locks Wifi Multicast on until {@link #release} is called.
   1816          *
   1817          * If this MulticastLock is reference-counted each call to
   1818          * {@code acquire} will increment the reference count, and the
   1819          * wifi interface will receive multicast packets as long as the
   1820          * reference count is above zero.
   1821          *
   1822          * If this MulticastLock is not reference-counted, the first call to
   1823          * {@code acquire} will turn on the multicast packets, but subsequent
   1824          * calls will be ignored.  Only one call to {@link #release} will
   1825          * be required, regardless of the number of times that {@code acquire}
   1826          * is called.
   1827          *
   1828          * Note that other applications may also lock Wifi Multicast on.
   1829          * Only they can relinquish their lock.
   1830          *
   1831          * Also note that applications cannot leave Multicast locked on.
   1832          * When an app exits or crashes, any Multicast locks will be released.
   1833          */
   1834         public void acquire() {
   1835             synchronized (mBinder) {
   1836                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
   1837                     try {
   1838                         mService.acquireMulticastLock(mBinder, mTag);
   1839                         synchronized (WifiManager.this) {
   1840                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
   1841                                 mService.releaseMulticastLock();
   1842                                 throw new UnsupportedOperationException(
   1843                                         "Exceeded maximum number of wifi locks");
   1844                             }
   1845                             mActiveLockCount++;
   1846                         }
   1847                     } catch (RemoteException ignore) {
   1848                     }
   1849                     mHeld = true;
   1850                 }
   1851             }
   1852         }
   1853 
   1854         /**
   1855          * Unlocks Wifi Multicast, restoring the filter of packets
   1856          * not addressed specifically to this device and saving power.
   1857          *
   1858          * If this MulticastLock is reference-counted, each call to
   1859          * {@code release} will decrement the reference count, and the
   1860          * multicast packets will only stop being received when the reference
   1861          * count reaches zero.  If the reference count goes below zero (that
   1862          * is, if {@code release} is called a greater number of times than
   1863          * {@link #acquire}), an exception is thrown.
   1864          *
   1865          * If this MulticastLock is not reference-counted, the first call to
   1866          * {@code release} (after the radio was multicast locked using
   1867          * {@link #acquire}) will unlock the multicast, and subsequent calls
   1868          * will be ignored.
   1869          *
   1870          * Note that if any other Wifi Multicast Locks are still outstanding
   1871          * this {@code release} call will not have an immediate effect.  Only
   1872          * when all applications have released all their Multicast Locks will
   1873          * the Multicast filter be turned back on.
   1874          *
   1875          * Also note that when an app exits or crashes all of its Multicast
   1876          * Locks will be automatically released.
   1877          */
   1878         public void release() {
   1879             synchronized (mBinder) {
   1880                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
   1881                     try {
   1882                         mService.releaseMulticastLock();
   1883                         synchronized (WifiManager.this) {
   1884                             mActiveLockCount--;
   1885                         }
   1886                     } catch (RemoteException ignore) {
   1887                     }
   1888                     mHeld = false;
   1889                 }
   1890                 if (mRefCount < 0) {
   1891                     throw new RuntimeException("MulticastLock under-locked "
   1892                             + mTag);
   1893                 }
   1894             }
   1895         }
   1896 
   1897         /**
   1898          * Controls whether this is a reference-counted or non-reference-
   1899          * counted MulticastLock.
   1900          *
   1901          * Reference-counted MulticastLocks keep track of the number of calls
   1902          * to {@link #acquire} and {@link #release}, and only stop the
   1903          * reception of multicast packets when every call to {@link #acquire}
   1904          * has been balanced with a call to {@link #release}.  Non-reference-
   1905          * counted MulticastLocks allow the reception of multicast packets
   1906          * whenever {@link #acquire} is called and stop accepting multicast
   1907          * packets whenever {@link #release} is called.
   1908          *
   1909          * @param refCounted true if this MulticastLock should keep a reference
   1910          * count
   1911          */
   1912         public void setReferenceCounted(boolean refCounted) {
   1913             mRefCounted = refCounted;
   1914         }
   1915 
   1916         /**
   1917          * Checks whether this MulticastLock is currently held.
   1918          *
   1919          * @return true if this MulticastLock is held, false otherwise
   1920          */
   1921         public boolean isHeld() {
   1922             synchronized (mBinder) {
   1923                 return mHeld;
   1924             }
   1925         }
   1926 
   1927         public String toString() {
   1928             String s1, s2, s3;
   1929             synchronized (mBinder) {
   1930                 s1 = Integer.toHexString(System.identityHashCode(this));
   1931                 s2 = mHeld ? "held; " : "";
   1932                 if (mRefCounted) {
   1933                     s3 = "refcounted: refcount = " + mRefCount;
   1934                 } else {
   1935                     s3 = "not refcounted";
   1936                 }
   1937                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
   1938             }
   1939         }
   1940 
   1941         @Override
   1942         protected void finalize() throws Throwable {
   1943             super.finalize();
   1944             setReferenceCounted(false);
   1945             release();
   1946         }
   1947     }
   1948 
   1949     /**
   1950      * Check multicast filter status.
   1951      *
   1952      * @return true if multicast packets are allowed.
   1953      *
   1954      * @hide pending API council approval
   1955      */
   1956     public boolean isMulticastEnabled() {
   1957         try {
   1958             return mService.isMulticastEnabled();
   1959         } catch (RemoteException e) {
   1960             return false;
   1961         }
   1962     }
   1963 
   1964     /**
   1965      * Initialize the multicast filtering to 'on'
   1966      * @hide no intent to publish
   1967      */
   1968     public boolean initializeMulticastFiltering() {
   1969         try {
   1970             mService.initializeMulticastFiltering();
   1971             return true;
   1972         } catch (RemoteException e) {
   1973              return false;
   1974         }
   1975     }
   1976 
   1977     /** @hide */
   1978     public void captivePortalCheckComplete() {
   1979         try {
   1980             mService.captivePortalCheckComplete();
   1981         } catch (RemoteException e) {}
   1982     }
   1983 
   1984     protected void finalize() throws Throwable {
   1985         try {
   1986             if (mHandler != null && mHandler.getLooper() != null) {
   1987                 mHandler.getLooper().quit();
   1988             }
   1989         } finally {
   1990             super.finalize();
   1991         }
   1992     }
   1993 }
   1994