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