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