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.net.DhcpInfo;
     22 import android.os.Binder;
     23 import android.os.IBinder;
     24 import android.os.Handler;
     25 import android.os.RemoteException;
     26 import android.os.WorkSource;
     27 
     28 import java.util.List;
     29 
     30 /**
     31  * This class provides the primary API for managing all aspects of Wi-Fi
     32  * connectivity. Get an instance of this class by calling
     33  * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
     34 
     35  * It deals with several categories of items:
     36  * <ul>
     37  * <li>The list of configured networks. The list can be viewed and updated,
     38  * and attributes of individual entries can be modified.</li>
     39  * <li>The currently active Wi-Fi network, if any. Connectivity can be
     40  * established or torn down, and dynamic information about the state of
     41  * the network can be queried.</li>
     42  * <li>Results of access point scans, containing enough information to
     43  * make decisions about what access point to connect to.</li>
     44  * <li>It defines the names of various Intent actions that are broadcast
     45  * upon any sort of change in Wi-Fi state.
     46  * </ul>
     47  * This is the API to use when performing Wi-Fi specific operations. To
     48  * perform operations that pertain to network connectivity at an abstract
     49  * level, use {@link android.net.ConnectivityManager}.
     50  */
     51 public class WifiManager {
     52 
     53     // Supplicant error codes:
     54     /**
     55      * The error code if there was a problem authenticating.
     56      */
     57     public static final int ERROR_AUTHENTICATING = 1;
     58 
     59     /**
     60      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
     61      * enabling, disabling, or unknown. One extra provides this state as an int.
     62      * Another extra provides the previous state, if available.
     63      *
     64      * @see #EXTRA_WIFI_STATE
     65      * @see #EXTRA_PREVIOUS_WIFI_STATE
     66      */
     67     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     68     public static final String WIFI_STATE_CHANGED_ACTION =
     69         "android.net.wifi.WIFI_STATE_CHANGED";
     70     /**
     71      * The lookup key for an int that indicates whether Wi-Fi is enabled,
     72      * disabled, enabling, disabling, or unknown.  Retrieve it with
     73      * {@link android.content.Intent#getIntExtra(String,int)}.
     74      *
     75      * @see #WIFI_STATE_DISABLED
     76      * @see #WIFI_STATE_DISABLING
     77      * @see #WIFI_STATE_ENABLED
     78      * @see #WIFI_STATE_ENABLING
     79      * @see #WIFI_STATE_UNKNOWN
     80      */
     81     public static final String EXTRA_WIFI_STATE = "wifi_state";
     82     /**
     83      * The previous Wi-Fi state.
     84      *
     85      * @see #EXTRA_WIFI_STATE
     86      */
     87     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
     88 
     89     /**
     90      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
     91      * it finishes successfully.
     92      *
     93      * @see #WIFI_STATE_CHANGED_ACTION
     94      * @see #getWifiState()
     95      */
     96     public static final int WIFI_STATE_DISABLING = 0;
     97     /**
     98      * Wi-Fi is disabled.
     99      *
    100      * @see #WIFI_STATE_CHANGED_ACTION
    101      * @see #getWifiState()
    102      */
    103     public static final int WIFI_STATE_DISABLED = 1;
    104     /**
    105      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
    106      * it finishes successfully.
    107      *
    108      * @see #WIFI_STATE_CHANGED_ACTION
    109      * @see #getWifiState()
    110      */
    111     public static final int WIFI_STATE_ENABLING = 2;
    112     /**
    113      * Wi-Fi is enabled.
    114      *
    115      * @see #WIFI_STATE_CHANGED_ACTION
    116      * @see #getWifiState()
    117      */
    118     public static final int WIFI_STATE_ENABLED = 3;
    119     /**
    120      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
    121      * or disabling.
    122      *
    123      * @see #WIFI_STATE_CHANGED_ACTION
    124      * @see #getWifiState()
    125      */
    126     public static final int WIFI_STATE_UNKNOWN = 4;
    127 
    128     /**
    129      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
    130      * enabling, disabling, or failed.
    131      *
    132      * @hide
    133      */
    134     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    135     public static final String WIFI_AP_STATE_CHANGED_ACTION =
    136         "android.net.wifi.WIFI_AP_STATE_CHANGED";
    137 
    138     /**
    139      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
    140      * disabled, enabling, disabling, or failed.  Retrieve it with
    141      * {@link android.content.Intent#getIntExtra(String,int)}.
    142      *
    143      * @see #WIFI_AP_STATE_DISABLED
    144      * @see #WIFI_AP_STATE_DISABLING
    145      * @see #WIFI_AP_STATE_ENABLED
    146      * @see #WIFI_AP_STATE_ENABLING
    147      * @see #WIFI_AP_STATE_FAILED
    148      *
    149      * @hide
    150      */
    151     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
    152     /**
    153      * The previous Wi-Fi state.
    154      *
    155      * @see #EXTRA_WIFI_AP_STATE
    156      *
    157      * @hide
    158      */
    159     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
    160     /**
    161      * Wi-Fi AP is currently being disabled. The state will change to
    162      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
    163      *
    164      * @see #WIFI_AP_STATE_CHANGED_ACTION
    165      * @see #getWifiApState()
    166      *
    167      * @hide
    168      */
    169     public static final int WIFI_AP_STATE_DISABLING = 0;
    170     /**
    171      * Wi-Fi AP is disabled.
    172      *
    173      * @see #WIFI_AP_STATE_CHANGED_ACTION
    174      * @see #getWifiState()
    175      *
    176      * @hide
    177      */
    178     public static final int WIFI_AP_STATE_DISABLED = 1;
    179     /**
    180      * Wi-Fi AP is currently being enabled. The state will change to
    181      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
    182      *
    183      * @see #WIFI_AP_STATE_CHANGED_ACTION
    184      * @see #getWifiApState()
    185      *
    186      * @hide
    187      */
    188     public static final int WIFI_AP_STATE_ENABLING = 2;
    189     /**
    190      * Wi-Fi AP is enabled.
    191      *
    192      * @see #WIFI_AP_STATE_CHANGED_ACTION
    193      * @see #getWifiApState()
    194      *
    195      * @hide
    196      */
    197     public static final int WIFI_AP_STATE_ENABLED = 3;
    198     /**
    199      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
    200      * enabling or disabling
    201      *
    202      * @see #WIFI_AP_STATE_CHANGED_ACTION
    203      * @see #getWifiApState()
    204      *
    205      * @hide
    206      */
    207     public static final int WIFI_AP_STATE_FAILED = 4;
    208 
    209     /**
    210      * Broadcast intent action indicating that a connection to the supplicant has
    211      * been established (and it is now possible
    212      * to perform Wi-Fi operations) or the connection to the supplicant has been
    213      * lost. One extra provides the connection state as a boolean, where {@code true}
    214      * means CONNECTED.
    215      * @see #EXTRA_SUPPLICANT_CONNECTED
    216      */
    217     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    218     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
    219         "android.net.wifi.supplicant.CONNECTION_CHANGE";
    220     /**
    221      * The lookup key for a boolean that indicates whether a connection to
    222      * the supplicant daemon has been gained or lost. {@code true} means
    223      * a connection now exists.
    224      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
    225      */
    226     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
    227     /**
    228      * Broadcast intent action indicating that the state of Wi-Fi connectivity
    229      * has changed. One extra provides the new state
    230      * in the form of a {@link android.net.NetworkInfo} object. If the new state is
    231      * CONNECTED, a second extra may provide the BSSID of the access point,
    232      * as a {@code String}.
    233      * @see #EXTRA_NETWORK_INFO
    234      * @see #EXTRA_BSSID
    235      */
    236     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    237     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
    238     /**
    239      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
    240      * Wi-Fi network. Retrieve with
    241      * {@link android.content.Intent#getParcelableExtra(String)}.
    242      */
    243     public static final String EXTRA_NETWORK_INFO = "networkInfo";
    244     /**
    245      * The lookup key for a String giving the BSSID of the access point to which
    246      * we are connected. Only present when the new state is CONNECTED.
    247      * Retrieve with
    248      * {@link android.content.Intent#getStringExtra(String)}.
    249      */
    250     public static final String EXTRA_BSSID = "bssid";
    251     /**
    252      * Broadcast intent action indicating that the state of establishing a connection to
    253      * an access point has changed.One extra provides the new
    254      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
    255      * is not generally the most useful thing to look at if you are just interested in
    256      * the overall state of connectivity.
    257      * @see #EXTRA_NEW_STATE
    258      * @see #EXTRA_SUPPLICANT_ERROR
    259      */
    260     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    261     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
    262         "android.net.wifi.supplicant.STATE_CHANGE";
    263     /**
    264      * The lookup key for a {@link SupplicantState} describing the new state
    265      * Retrieve with
    266      * {@link android.content.Intent#getParcelableExtra(String)}.
    267      */
    268     public static final String EXTRA_NEW_STATE = "newState";
    269 
    270     /**
    271      * The lookup key for a {@link SupplicantState} describing the supplicant
    272      * error code if any
    273      * Retrieve with
    274      * {@link android.content.Intent#getIntExtra(String, int)}.
    275      * @see #ERROR_AUTHENTICATING
    276      */
    277     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
    278 
    279     /**
    280      * An access point scan has completed, and results are available from the supplicant.
    281      * Call {@link #getScanResults()} to obtain the results.
    282      */
    283     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    284     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
    285     /**
    286      * The RSSI (signal strength) has changed.
    287      * @see #EXTRA_NEW_RSSI
    288      */
    289     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    290     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
    291     /**
    292      * The lookup key for an {@code int} giving the new RSSI in dBm.
    293      */
    294     public static final String EXTRA_NEW_RSSI = "newRssi";
    295 
    296     /**
    297      * The network IDs of the configured networks could have changed.
    298      */
    299     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    300     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
    301 
    302     /**
    303      * Activity Action: Pick a Wi-Fi network to connect to.
    304      * <p>Input: Nothing.
    305      * <p>Output: Nothing.
    306      */
    307     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    308     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
    309 
    310     /**
    311      * In this Wi-Fi lock mode, Wi-Fi will behave as in the mode
    312      * {@link #WIFI_MODE_FULL} but it operates at high performance
    313      * at the expense of power. This mode should be used
    314      * only when the wifi connection needs to have minimum loss and low
    315      * latency as it can impact the battery life.
    316      * @hide
    317      */
    318     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
    319 
    320     /**
    321      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
    322      * and will behave normally, i.e., it will attempt to automatically
    323      * establish a connection to a remembered access point that is
    324      * within range, and will do periodic scans if there are remembered
    325      * access points but none are in range.
    326      */
    327     public static final int WIFI_MODE_FULL = 1;
    328     /**
    329      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
    330      * but the only operation that will be supported is initiation of
    331      * scans, and the subsequent reporting of scan results. No attempts
    332      * will be made to automatically connect to remembered access points,
    333      * nor will periodic scans be automatically performed looking for
    334      * remembered access points. Scans must be explicitly requested by
    335      * an application in this mode.
    336      */
    337     public static final int WIFI_MODE_SCAN_ONLY = 2;
    338 
    339     /** Anything worse than or equal to this will show 0 bars. */
    340     private static final int MIN_RSSI = -100;
    341 
    342     /** Anything better than or equal to this will show the max bars. */
    343     private static final int MAX_RSSI = -55;
    344 
    345     IWifiManager mService;
    346     Handler mHandler;
    347 
    348     /* Maximum number of active locks we allow.
    349      * This limit was added to prevent apps from creating a ridiculous number
    350      * of locks and crashing the system by overflowing the global ref table.
    351      */
    352     private static final int MAX_ACTIVE_LOCKS = 50;
    353 
    354     /* Number of currently active WifiLocks and MulticastLocks */
    355     private int mActiveLockCount;
    356 
    357     /**
    358      * Create a new WifiManager instance.
    359      * Applications will almost always want to use
    360      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
    361      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
    362      * @param service the Binder interface
    363      * @param handler target for messages
    364      * @hide - hide this because it takes in a parameter of type IWifiManager, which
    365      * is a system private class.
    366      */
    367     public WifiManager(IWifiManager service, Handler handler) {
    368         mService = service;
    369         mHandler = handler;
    370     }
    371 
    372     /**
    373      * Return a list of all the networks configured in the supplicant.
    374      * Not all fields of WifiConfiguration are returned. Only the following
    375      * fields are filled in:
    376      * <ul>
    377      * <li>networkId</li>
    378      * <li>SSID</li>
    379      * <li>BSSID</li>
    380      * <li>priority</li>
    381      * <li>allowedProtocols</li>
    382      * <li>allowedKeyManagement</li>
    383      * <li>allowedAuthAlgorithms</li>
    384      * <li>allowedPairwiseCiphers</li>
    385      * <li>allowedGroupCiphers</li>
    386      * </ul>
    387      * @return a list of network configurations in the form of a list
    388      * of {@link WifiConfiguration} objects.
    389      */
    390     public List<WifiConfiguration> getConfiguredNetworks() {
    391         try {
    392             return mService.getConfiguredNetworks();
    393         } catch (RemoteException e) {
    394             return null;
    395         }
    396     }
    397 
    398     /**
    399      * Add a new network description to the set of configured networks.
    400      * The {@code networkId} field of the supplied configuration object
    401      * is ignored.
    402      * <p/>
    403      * The new network will be marked DISABLED by default. To enable it,
    404      * called {@link #enableNetwork}.
    405      *
    406      * @param config the set of variables that describe the configuration,
    407      *            contained in a {@link WifiConfiguration} object.
    408      * @return the ID of the newly created network description. This is used in
    409      *         other operations to specified the network to be acted upon.
    410      *         Returns {@code -1} on failure.
    411      */
    412     public int addNetwork(WifiConfiguration config) {
    413         if (config == null) {
    414             return -1;
    415         }
    416         config.networkId = -1;
    417         return addOrUpdateNetwork(config);
    418     }
    419 
    420     /**
    421      * Update the network description of an existing configured network.
    422      *
    423      * @param config the set of variables that describe the configuration,
    424      *            contained in a {@link WifiConfiguration} object. It may
    425      *            be sparse, so that only the items that are being changed
    426      *            are non-<code>null</code>. The {@code networkId} field
    427      *            must be set to the ID of the existing network being updated.
    428      * @return Returns the {@code networkId} of the supplied
    429      *         {@code WifiConfiguration} on success.
    430      *         <br/>
    431      *         Returns {@code -1} on failure, including when the {@code networkId}
    432      *         field of the {@code WifiConfiguration} does not refer to an
    433      *         existing network.
    434      */
    435     public int updateNetwork(WifiConfiguration config) {
    436         if (config == null || config.networkId < 0) {
    437             return -1;
    438         }
    439         return addOrUpdateNetwork(config);
    440     }
    441 
    442     /**
    443      * Internal method for doing the RPC that creates a new network description
    444      * or updates an existing one.
    445      *
    446      * @param config The possibly sparse object containing the variables that
    447      *         are to set or updated in the network description.
    448      * @return the ID of the network on success, {@code -1} on failure.
    449      */
    450     private int addOrUpdateNetwork(WifiConfiguration config) {
    451         try {
    452             return mService.addOrUpdateNetwork(config);
    453         } catch (RemoteException e) {
    454             return -1;
    455         }
    456     }
    457 
    458     /**
    459      * Remove the specified network from the list of configured networks.
    460      * This may result in the asynchronous delivery of state change
    461      * events.
    462      * @param netId the integer that identifies the network configuration
    463      * to the supplicant
    464      * @return {@code true} if the operation succeeded
    465      */
    466     public boolean removeNetwork(int netId) {
    467         try {
    468             return mService.removeNetwork(netId);
    469         } catch (RemoteException e) {
    470             return false;
    471         }
    472     }
    473 
    474     /**
    475      * Allow a previously configured network to be associated with. If
    476      * <code>disableOthers</code> is true, then all other configured
    477      * networks are disabled, and an attempt to connect to the selected
    478      * network is initiated. This may result in the asynchronous delivery
    479      * of state change events.
    480      * @param netId the ID of the network in the list of configured networks
    481      * @param disableOthers if true, disable all other networks. The way to
    482      * select a particular network to connect to is specify {@code true}
    483      * for this parameter.
    484      * @return {@code true} if the operation succeeded
    485      */
    486     public boolean enableNetwork(int netId, boolean disableOthers) {
    487         try {
    488             return mService.enableNetwork(netId, disableOthers);
    489         } catch (RemoteException e) {
    490             return false;
    491         }
    492     }
    493 
    494     /**
    495      * Disable a configured network. The specified network will not be
    496      * a candidate for associating. This may result in the asynchronous
    497      * delivery of state change events.
    498      * @param netId the ID of the network as returned by {@link #addNetwork}.
    499      * @return {@code true} if the operation succeeded
    500      */
    501     public boolean disableNetwork(int netId) {
    502         try {
    503             return mService.disableNetwork(netId);
    504         } catch (RemoteException e) {
    505             return false;
    506         }
    507     }
    508 
    509     /**
    510      * Disassociate from the currently active access point. This may result
    511      * in the asynchronous delivery of state change events.
    512      * @return {@code true} if the operation succeeded
    513      */
    514     public boolean disconnect() {
    515         try {
    516             return mService.disconnect();
    517         } catch (RemoteException e) {
    518             return false;
    519         }
    520     }
    521 
    522     /**
    523      * Reconnect to the currently active access point, if we are currently
    524      * disconnected. This may result in the asynchronous delivery of state
    525      * change events.
    526      * @return {@code true} if the operation succeeded
    527      */
    528     public boolean reconnect() {
    529         try {
    530             return mService.reconnect();
    531         } catch (RemoteException e) {
    532             return false;
    533         }
    534     }
    535 
    536     /**
    537      * Reconnect to the currently active access point, even if we are already
    538      * connected. This may result in the asynchronous delivery of state
    539      * change events.
    540      * @return {@code true} if the operation succeeded
    541      */
    542     public boolean reassociate() {
    543         try {
    544             return mService.reassociate();
    545         } catch (RemoteException e) {
    546             return false;
    547         }
    548     }
    549 
    550     /**
    551      * Check that the supplicant daemon is responding to requests.
    552      * @return {@code true} if we were able to communicate with the supplicant and
    553      * it returned the expected response to the PING message.
    554      */
    555     public boolean pingSupplicant() {
    556         if (mService == null)
    557             return false;
    558         try {
    559             return mService.pingSupplicant();
    560         } catch (RemoteException e) {
    561             return false;
    562         }
    563     }
    564 
    565     /**
    566      * Request a scan for access points. Returns immediately. The availability
    567      * of the results is made known later by means of an asynchronous event sent
    568      * on completion of the scan.
    569      * @return {@code true} if the operation succeeded, i.e., the scan was initiated
    570      */
    571     public boolean startScan() {
    572         try {
    573             mService.startScan(false);
    574             return true;
    575         } catch (RemoteException e) {
    576             return false;
    577         }
    578     }
    579 
    580     /**
    581      * Request a scan for access points. Returns immediately. The availability
    582      * of the results is made known later by means of an asynchronous event sent
    583      * on completion of the scan.
    584      * This is a variant of startScan that forces an active scan, even if passive
    585      * scans are the current default
    586      * @return {@code true} if the operation succeeded, i.e., the scan was initiated
    587      *
    588      * @hide
    589      */
    590     public boolean startScanActive() {
    591         try {
    592             mService.startScan(true);
    593             return true;
    594         } catch (RemoteException e) {
    595             return false;
    596         }
    597     }
    598 
    599     /**
    600      * Return dynamic information about the current Wi-Fi connection, if any is active.
    601      * @return the Wi-Fi information, contained in {@link WifiInfo}.
    602      */
    603     public WifiInfo getConnectionInfo() {
    604         try {
    605             return mService.getConnectionInfo();
    606         } catch (RemoteException e) {
    607             return null;
    608         }
    609     }
    610 
    611     /**
    612      * Return the results of the latest access point scan.
    613      * @return the list of access points found in the most recent scan.
    614      */
    615     public List<ScanResult> getScanResults() {
    616         try {
    617             return mService.getScanResults();
    618         } catch (RemoteException e) {
    619             return null;
    620         }
    621     }
    622 
    623     /**
    624      * Tell the supplicant to persist the current list of configured networks.
    625      * <p>
    626      * Note: It is possible for this method to change the network IDs of
    627      * existing networks. You should assume the network IDs can be different
    628      * after calling this method.
    629      *
    630      * @return {@code true} if the operation succeeded
    631      */
    632     public boolean saveConfiguration() {
    633         try {
    634             return mService.saveConfiguration();
    635         } catch (RemoteException e) {
    636             return false;
    637         }
    638     }
    639 
    640     /**
    641      * Return the number of frequency channels that are allowed
    642      * to be used in the current regulatory domain.
    643      * @return the number of allowed channels, or {@code -1} if an error occurs
    644      *
    645      * @hide pending API council
    646      */
    647     public int getNumAllowedChannels() {
    648         try {
    649             return mService.getNumAllowedChannels();
    650         } catch (RemoteException e) {
    651             return -1;
    652         }
    653     }
    654 
    655     /**
    656      * Set the number of frequency channels that are allowed to be used
    657      * in the current regulatory domain. This method should be used only
    658      * if the correct number of channels cannot be determined automatically
    659      * for some reason.
    660      * @param numChannels the number of allowed channels. Must be greater than 0
    661      * and less than or equal to 16.
    662      * @param persist {@code true} if you want this remembered
    663      * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
    664      * {@code numChannels} is out of range.
    665      *
    666      * @hide pending API council
    667      */
    668     public boolean setNumAllowedChannels(int numChannels, boolean persist) {
    669         try {
    670             return mService.setNumAllowedChannels(numChannels, persist);
    671         } catch (RemoteException e) {
    672             return false;
    673         }
    674     }
    675 
    676     /**
    677      * Return the list of valid values for the number of allowed radio channels
    678      * for various regulatory domains.
    679      * @return the list of channel counts, or {@code null} if the operation fails
    680      *
    681      * @hide pending API council review
    682      */
    683     public int[] getValidChannelCounts() {
    684         try {
    685             return mService.getValidChannelCounts();
    686         } catch (RemoteException e) {
    687             return null;
    688         }
    689    }
    690 
    691     /**
    692      * Return the DHCP-assigned addresses from the last successful DHCP request,
    693      * if any.
    694      * @return the DHCP information
    695      */
    696     public DhcpInfo getDhcpInfo() {
    697         try {
    698             return mService.getDhcpInfo();
    699         } catch (RemoteException e) {
    700             return null;
    701         }
    702     }
    703 
    704 
    705     /**
    706      * Enable or disable Wi-Fi.
    707      * @param enabled {@code true} to enable, {@code false} to disable.
    708      * @return {@code true} if the operation succeeds (or if the existing state
    709      *         is the same as the requested state).
    710      */
    711     public boolean setWifiEnabled(boolean enabled) {
    712         try {
    713             return mService.setWifiEnabled(enabled);
    714         } catch (RemoteException e) {
    715             return false;
    716         }
    717     }
    718 
    719     /**
    720      * Gets the Wi-Fi enabled state.
    721      * @return One of {@link #WIFI_STATE_DISABLED},
    722      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
    723      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
    724      * @see #isWifiEnabled()
    725      */
    726     public int getWifiState() {
    727         try {
    728             return mService.getWifiEnabledState();
    729         } catch (RemoteException e) {
    730             return WIFI_STATE_UNKNOWN;
    731         }
    732     }
    733 
    734     /**
    735      * Return whether Wi-Fi is enabled or disabled.
    736      * @return {@code true} if Wi-Fi is enabled
    737      * @see #getWifiState()
    738      */
    739     public boolean isWifiEnabled() {
    740         return getWifiState() == WIFI_STATE_ENABLED;
    741     }
    742 
    743     /**
    744      * Calculates the level of the signal. This should be used any time a signal
    745      * is being shown.
    746      *
    747      * @param rssi The power of the signal measured in RSSI.
    748      * @param numLevels The number of levels to consider in the calculated
    749      *            level.
    750      * @return A level of the signal, given in the range of 0 to numLevels-1
    751      *         (both inclusive).
    752      */
    753     public static int calculateSignalLevel(int rssi, int numLevels) {
    754         if (rssi <= MIN_RSSI) {
    755             return 0;
    756         } else if (rssi >= MAX_RSSI) {
    757             return numLevels - 1;
    758         } else {
    759             int partitionSize = (MAX_RSSI - MIN_RSSI) / (numLevels - 1);
    760             return (rssi - MIN_RSSI) / partitionSize;
    761         }
    762     }
    763 
    764     /**
    765      * Compares two signal strengths.
    766      *
    767      * @param rssiA The power of the first signal measured in RSSI.
    768      * @param rssiB The power of the second signal measured in RSSI.
    769      * @return Returns <0 if the first signal is weaker than the second signal,
    770      *         0 if the two signals have the same strength, and >0 if the first
    771      *         signal is stronger than the second signal.
    772      */
    773     public static int compareSignalLevel(int rssiA, int rssiB) {
    774         return rssiA - rssiB;
    775     }
    776 
    777     /**
    778      * Start AccessPoint mode with the specified
    779      * configuration. If the radio is already running in
    780      * AP mode, update the new configuration
    781      * Note that starting in access point mode disables station
    782      * mode operation
    783      * @param wifiConfig SSID, security and channel details as
    784      *        part of WifiConfiguration
    785      * @return {@code true} if the operation succeeds, {@code false} otherwise
    786      *
    787      * @hide Dont open up yet
    788      */
    789     public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
    790         try {
    791             return mService.setWifiApEnabled(wifiConfig, enabled);
    792         } catch (RemoteException e) {
    793             return false;
    794         }
    795     }
    796 
    797     /**
    798      * Gets the Wi-Fi enabled state.
    799      * @return One of {@link #WIFI_AP_STATE_DISABLED},
    800      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
    801      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
    802      * @see #isWifiApEnabled()
    803      *
    804      * @hide Dont open yet
    805      */
    806     public int getWifiApState() {
    807         try {
    808             return mService.getWifiApEnabledState();
    809         } catch (RemoteException e) {
    810             return WIFI_AP_STATE_FAILED;
    811         }
    812     }
    813 
    814     /**
    815      * Return whether Wi-Fi AP is enabled or disabled.
    816      * @return {@code true} if Wi-Fi AP is enabled
    817      * @see #getWifiApState()
    818      *
    819      * @hide Dont open yet
    820      */
    821     public boolean isWifiApEnabled() {
    822         return getWifiApState() == WIFI_AP_STATE_ENABLED;
    823     }
    824 
    825     /**
    826      * Gets the Wi-Fi AP Configuration.
    827      * @return AP details in WifiConfiguration
    828      *
    829      * @hide Dont open yet
    830      */
    831     public WifiConfiguration getWifiApConfiguration() {
    832         try {
    833             return mService.getWifiApConfiguration();
    834         } catch (RemoteException e) {
    835             return null;
    836         }
    837     }
    838 
    839     /**
    840      * Sets the Wi-Fi AP Configuration.
    841      * @return {@code true} if the operation succeeded, {@code false} otherwise
    842      *
    843      * @hide Dont open yet
    844      */
    845     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
    846         try {
    847             mService.setWifiApConfiguration(wifiConfig);
    848             return true;
    849         } catch (RemoteException e) {
    850             return false;
    851         }
    852     }
    853 
    854     /**
    855      * Allows an application to keep the Wi-Fi radio awake.
    856      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
    857      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
    858      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
    859      * WifiLocks are held in any application.
    860      *
    861      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
    862      * could function over a mobile network, if available.  A program that needs to download large
    863      * files should hold a WifiLock to ensure that the download will complete, but a program whose
    864      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
    865      * affecting battery life.
    866      *
    867      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
    868      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
    869      * is idle.
    870      */
    871     public class WifiLock {
    872         private String mTag;
    873         private final IBinder mBinder;
    874         private int mRefCount;
    875         int mLockType;
    876         private boolean mRefCounted;
    877         private boolean mHeld;
    878         private WorkSource mWorkSource;
    879 
    880         private WifiLock(int lockType, String tag) {
    881             mTag = tag;
    882             mLockType = lockType;
    883             mBinder = new Binder();
    884             mRefCount = 0;
    885             mRefCounted = true;
    886             mHeld = false;
    887         }
    888 
    889         /**
    890          * Locks the Wi-Fi radio on until {@link #release} is called.
    891          *
    892          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
    893          * reference count, and the radio will remain locked as long as the reference count is
    894          * above zero.
    895          *
    896          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
    897          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
    898          * will be required, regardless of the number of times that {@code acquire} is called.
    899          */
    900         public void acquire() {
    901             synchronized (mBinder) {
    902                 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
    903                     try {
    904                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
    905                         synchronized (WifiManager.this) {
    906                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
    907                                 mService.releaseWifiLock(mBinder);
    908                                 throw new UnsupportedOperationException(
    909                                             "Exceeded maximum number of wifi locks");
    910                             }
    911                             mActiveLockCount++;
    912                         }
    913                     } catch (RemoteException ignore) {
    914                     }
    915                     mHeld = true;
    916                 }
    917             }
    918         }
    919 
    920         /**
    921          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
    922          *
    923          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
    924          * reference count, and the radio will be unlocked only when the reference count reaches
    925          * zero.  If the reference count goes below zero (that is, if {@code release} is called
    926          * a greater number of times than {@link #acquire}), an exception is thrown.
    927          *
    928          * If this WifiLock is not reference-counted, the first call to {@code release} (after
    929          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
    930          * calls will be ignored.
    931          */
    932         public void release() {
    933             synchronized (mBinder) {
    934                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
    935                     try {
    936                         mService.releaseWifiLock(mBinder);
    937                         synchronized (WifiManager.this) {
    938                             mActiveLockCount--;
    939                         }
    940                     } catch (RemoteException ignore) {
    941                     }
    942                     mHeld = false;
    943                 }
    944                 if (mRefCount < 0) {
    945                     throw new RuntimeException("WifiLock under-locked " + mTag);
    946                 }
    947             }
    948         }
    949 
    950         /**
    951          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
    952          *
    953          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
    954          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
    955          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
    956          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
    957          * radio whenever {@link #release} is called and it is locked.
    958          *
    959          * @param refCounted true if this WifiLock should keep a reference count
    960          */
    961         public void setReferenceCounted(boolean refCounted) {
    962             mRefCounted = refCounted;
    963         }
    964 
    965         /**
    966          * Checks whether this WifiLock is currently held.
    967          *
    968          * @return true if this WifiLock is held, false otherwise
    969          */
    970         public boolean isHeld() {
    971             synchronized (mBinder) {
    972                 return mHeld;
    973             }
    974         }
    975 
    976         public void setWorkSource(WorkSource ws) {
    977             synchronized (mBinder) {
    978                 if (ws != null && ws.size() == 0) {
    979                     ws = null;
    980                 }
    981                 boolean changed = true;
    982                 if (ws == null) {
    983                     mWorkSource = null;
    984                 } else if (mWorkSource == null) {
    985                     changed = mWorkSource != null;
    986                     mWorkSource = new WorkSource(ws);
    987                 } else {
    988                     changed = mWorkSource.diff(ws);
    989                     if (changed) {
    990                         mWorkSource.set(ws);
    991                     }
    992                 }
    993                 if (changed && mHeld) {
    994                     try {
    995                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
    996                     } catch (RemoteException e) {
    997                     }
    998                 }
    999             }
   1000         }
   1001 
   1002         public String toString() {
   1003             String s1, s2, s3;
   1004             synchronized (mBinder) {
   1005                 s1 = Integer.toHexString(System.identityHashCode(this));
   1006                 s2 = mHeld ? "held; " : "";
   1007                 if (mRefCounted) {
   1008                     s3 = "refcounted: refcount = " + mRefCount;
   1009                 } else {
   1010                     s3 = "not refcounted";
   1011                 }
   1012                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
   1013             }
   1014         }
   1015 
   1016         @Override
   1017         protected void finalize() throws Throwable {
   1018             super.finalize();
   1019             synchronized (mBinder) {
   1020                 if (mHeld) {
   1021                     try {
   1022                         mService.releaseWifiLock(mBinder);
   1023                         synchronized (WifiManager.this) {
   1024                             mActiveLockCount--;
   1025                         }
   1026                     } catch (RemoteException ignore) {
   1027                     }
   1028                 }
   1029             }
   1030         }
   1031     }
   1032 
   1033     /**
   1034      * Creates a new WifiLock.
   1035      *
   1036      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
   1037      * and {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks.
   1038      *
   1039      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
   1040      *            never shown to the user under normal conditions, but should be descriptive
   1041      *            enough to identify your application and the specific WifiLock within it, if it
   1042      *            holds multiple WifiLocks.
   1043      *
   1044      * @return a new, unacquired WifiLock with the given tag.
   1045      *
   1046      * @see WifiLock
   1047      */
   1048     public WifiLock createWifiLock(int lockType, String tag) {
   1049         return new WifiLock(lockType, tag);
   1050     }
   1051 
   1052     /**
   1053      * Creates a new WifiLock.
   1054      *
   1055      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
   1056      *            never shown to the user under normal conditions, but should be descriptive
   1057      *            enough to identify your application and the specific WifiLock within it, if it
   1058      *            holds multiple WifiLocks.
   1059      *
   1060      * @return a new, unacquired WifiLock with the given tag.
   1061      *
   1062      * @see WifiLock
   1063      */
   1064     public WifiLock createWifiLock(String tag) {
   1065         return new WifiLock(WIFI_MODE_FULL, tag);
   1066     }
   1067 
   1068 
   1069     /**
   1070      * Create a new MulticastLock
   1071      *
   1072      * @param tag a tag for the MulticastLock to identify it in debugging
   1073      *            messages.  This string is never shown to the user under
   1074      *            normal conditions, but should be descriptive enough to
   1075      *            identify your application and the specific MulticastLock
   1076      *            within it, if it holds multiple MulticastLocks.
   1077      *
   1078      * @return a new, unacquired MulticastLock with the given tag.
   1079      *
   1080      * @see MulticastLock
   1081      */
   1082     public MulticastLock createMulticastLock(String tag) {
   1083         return new MulticastLock(tag);
   1084     }
   1085 
   1086     /**
   1087      * Allows an application to receive Wifi Multicast packets.
   1088      * Normally the Wifi stack filters out packets not explicitly
   1089      * addressed to this device.  Acquring a MulticastLock will
   1090      * cause the stack to receive packets addressed to multicast
   1091      * addresses.  Processing these extra packets can cause a noticable
   1092      * battery drain and should be disabled when not needed.
   1093      */
   1094     public class MulticastLock {
   1095         private String mTag;
   1096         private final IBinder mBinder;
   1097         private int mRefCount;
   1098         private boolean mRefCounted;
   1099         private boolean mHeld;
   1100 
   1101         private MulticastLock(String tag) {
   1102             mTag = tag;
   1103             mBinder = new Binder();
   1104             mRefCount = 0;
   1105             mRefCounted = true;
   1106             mHeld = false;
   1107         }
   1108 
   1109         /**
   1110          * Locks Wifi Multicast on until {@link #release} is called.
   1111          *
   1112          * If this MulticastLock is reference-counted each call to
   1113          * {@code acquire} will increment the reference count, and the
   1114          * wifi interface will receive multicast packets as long as the
   1115          * reference count is above zero.
   1116          *
   1117          * If this MulticastLock is not reference-counted, the first call to
   1118          * {@code acquire} will turn on the multicast packets, but subsequent
   1119          * calls will be ignored.  Only one call to {@link #release} will
   1120          * be required, regardless of the number of times that {@code acquire}
   1121          * is called.
   1122          *
   1123          * Note that other applications may also lock Wifi Multicast on.
   1124          * Only they can relinquish their lock.
   1125          *
   1126          * Also note that applications cannot leave Multicast locked on.
   1127          * When an app exits or crashes, any Multicast locks will be released.
   1128          */
   1129         public void acquire() {
   1130             synchronized (mBinder) {
   1131                 if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
   1132                     try {
   1133                         mService.acquireMulticastLock(mBinder, mTag);
   1134                         synchronized (WifiManager.this) {
   1135                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
   1136                                 mService.releaseMulticastLock();
   1137                                 throw new UnsupportedOperationException(
   1138                                         "Exceeded maximum number of wifi locks");
   1139                             }
   1140                             mActiveLockCount++;
   1141                         }
   1142                     } catch (RemoteException ignore) {
   1143                     }
   1144                     mHeld = true;
   1145                 }
   1146             }
   1147         }
   1148 
   1149         /**
   1150          * Unlocks Wifi Multicast, restoring the filter of packets
   1151          * not addressed specifically to this device and saving power.
   1152          *
   1153          * If this MulticastLock is reference-counted, each call to
   1154          * {@code release} will decrement the reference count, and the
   1155          * multicast packets will only stop being received when the reference
   1156          * count reaches zero.  If the reference count goes below zero (that
   1157          * is, if {@code release} is called a greater number of times than
   1158          * {@link #acquire}), an exception is thrown.
   1159          *
   1160          * If this MulticastLock is not reference-counted, the first call to
   1161          * {@code release} (after the radio was multicast locked using
   1162          * {@link #acquire}) will unlock the multicast, and subsequent calls
   1163          * will be ignored.
   1164          *
   1165          * Note that if any other Wifi Multicast Locks are still outstanding
   1166          * this {@code release} call will not have an immediate effect.  Only
   1167          * when all applications have released all their Multicast Locks will
   1168          * the Multicast filter be turned back on.
   1169          *
   1170          * Also note that when an app exits or crashes all of its Multicast
   1171          * Locks will be automatically released.
   1172          */
   1173         public void release() {
   1174             synchronized (mBinder) {
   1175                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
   1176                     try {
   1177                         mService.releaseMulticastLock();
   1178                         synchronized (WifiManager.this) {
   1179                             mActiveLockCount--;
   1180                         }
   1181                     } catch (RemoteException ignore) {
   1182                     }
   1183                     mHeld = false;
   1184                 }
   1185                 if (mRefCount < 0) {
   1186                     throw new RuntimeException("MulticastLock under-locked "
   1187                             + mTag);
   1188                 }
   1189             }
   1190         }
   1191 
   1192         /**
   1193          * Controls whether this is a reference-counted or non-reference-
   1194          * counted MulticastLock.
   1195          *
   1196          * Reference-counted MulticastLocks keep track of the number of calls
   1197          * to {@link #acquire} and {@link #release}, and only stop the
   1198          * reception of multicast packets when every call to {@link #acquire}
   1199          * has been balanced with a call to {@link #release}.  Non-reference-
   1200          * counted MulticastLocks allow the reception of multicast packets
   1201          * whenever {@link #acquire} is called and stop accepting multicast
   1202          * packets whenever {@link #release} is called.
   1203          *
   1204          * @param refCounted true if this MulticastLock should keep a reference
   1205          * count
   1206          */
   1207         public void setReferenceCounted(boolean refCounted) {
   1208             mRefCounted = refCounted;
   1209         }
   1210 
   1211         /**
   1212          * Checks whether this MulticastLock is currently held.
   1213          *
   1214          * @return true if this MulticastLock is held, false otherwise
   1215          */
   1216         public boolean isHeld() {
   1217             synchronized (mBinder) {
   1218                 return mHeld;
   1219             }
   1220         }
   1221 
   1222         public String toString() {
   1223             String s1, s2, s3;
   1224             synchronized (mBinder) {
   1225                 s1 = Integer.toHexString(System.identityHashCode(this));
   1226                 s2 = mHeld ? "held; " : "";
   1227                 if (mRefCounted) {
   1228                     s3 = "refcounted: refcount = " + mRefCount;
   1229                 } else {
   1230                     s3 = "not refcounted";
   1231                 }
   1232                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
   1233             }
   1234         }
   1235 
   1236         @Override
   1237         protected void finalize() throws Throwable {
   1238             super.finalize();
   1239             setReferenceCounted(false);
   1240             release();
   1241         }
   1242     }
   1243 
   1244     /**
   1245      * Check multicast filter status.
   1246      *
   1247      * @return true if multicast packets are allowed.
   1248      *
   1249      * @hide pending API council approval
   1250      */
   1251     public boolean isMulticastEnabled() {
   1252         try {
   1253             return mService.isMulticastEnabled();
   1254         } catch (RemoteException e) {
   1255             return false;
   1256         }
   1257     }
   1258 
   1259     /**
   1260      * Initialize the multicast filtering to 'on'
   1261      * @hide no intent to publish
   1262      */
   1263     public boolean initializeMulticastFiltering() {
   1264         try {
   1265             mService.initializeMulticastFiltering();
   1266             return true;
   1267         } catch (RemoteException e) {
   1268              return false;
   1269         }
   1270     }
   1271 }
   1272