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