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(), null);
    803         } catch (RemoteException e) { return false; }
    804     }
    805     /** @hide */
    806     public boolean requestBatchedScan(BatchedScanSettings requested, WorkSource workSource) {
    807         try {
    808             return mService.requestBatchedScan(requested, new Binder(), workSource);
    809         } catch (RemoteException e) { return false; }
    810     }
    811 
    812     /**
    813      * Check if the Batched Scan feature is supported.
    814      *
    815      * @return false if not supported.
    816      * @hide
    817      */
    818     public boolean isBatchedScanSupported() {
    819         try {
    820             return mService.isBatchedScanSupported();
    821         } catch (RemoteException e) { return false; }
    822     }
    823 
    824     /**
    825      * End a requested batch scan for this applicaiton.  Note that batched scan may
    826      * still occur if other apps are using them.
    827      *
    828      * @param requested {@link BatchedScanSettings} the scan settings you previously requested
    829      *        and now wish to stop.  A value of null here will stop all scans requested by the
    830      *        calling App.
    831      * @hide
    832      */
    833     public void stopBatchedScan(BatchedScanSettings requested) {
    834         try {
    835             mService.stopBatchedScan(requested);
    836         } catch (RemoteException e) {}
    837     }
    838 
    839     /**
    840      * Retrieve the latest batched scan result.  This should be called immediately after
    841      * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received.
    842      * @hide
    843      */
    844     public List<BatchedScanResult> getBatchedScanResults() {
    845         try {
    846             return mService.getBatchedScanResults(mContext.getOpPackageName());
    847         } catch (RemoteException e) {
    848             return null;
    849         }
    850     }
    851 
    852     /**
    853      * Force a re-reading of batched scan results.  This will attempt
    854      * to read more information from the chip, but will do so at the expense
    855      * of previous data.  Rate limited to the current scan frequency.
    856      *
    857      * pollBatchedScan will always wait 1 period from the start of the batch
    858      * before trying to read from the chip, so if your #scans/batch == 1 this will
    859      * have no effect.
    860      *
    861      * If you had already waited 1 period before calling, this should have
    862      * immediate (though async) effect.
    863      *
    864      * If you call before that 1 period is up this will set up a timer and fetch
    865      * results when the 1 period is up.
    866      *
    867      * Servicing a pollBatchedScan request (immediate or after timed delay) starts a
    868      * new batch, so if you were doing 10 scans/batch and called in the 4th scan, you
    869      * would get data in the 4th and then again 10 scans later.
    870      * @hide
    871      */
    872     public void pollBatchedScan() {
    873         try {
    874             mService.pollBatchedScan();
    875         } catch (RemoteException e) { }
    876     }
    877 
    878     /**
    879      * Return dynamic information about the current Wi-Fi connection, if any is active.
    880      * @return the Wi-Fi information, contained in {@link WifiInfo}.
    881      */
    882     public WifiInfo getConnectionInfo() {
    883         try {
    884             return mService.getConnectionInfo();
    885         } catch (RemoteException e) {
    886             return null;
    887         }
    888     }
    889 
    890     /**
    891      * Return the results of the latest access point scan.
    892      * @return the list of access points found in the most recent scan.
    893      */
    894     public List<ScanResult> getScanResults() {
    895         try {
    896             return mService.getScanResults(mContext.getOpPackageName());
    897         } catch (RemoteException e) {
    898             return null;
    899         }
    900     }
    901 
    902     /**
    903      * Check if scanning is always available.
    904      *
    905      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
    906      * even when Wi-Fi is turned off.
    907      *
    908      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
    909      */
    910     public boolean isScanAlwaysAvailable() {
    911         try {
    912             return mService.isScanAlwaysAvailable();
    913         } catch (RemoteException e) {
    914             return false;
    915         }
    916     }
    917 
    918     /**
    919      * Tell the supplicant to persist the current list of configured networks.
    920      * <p>
    921      * Note: It is possible for this method to change the network IDs of
    922      * existing networks. You should assume the network IDs can be different
    923      * after calling this method.
    924      *
    925      * @return {@code true} if the operation succeeded
    926      */
    927     public boolean saveConfiguration() {
    928         try {
    929             return mService.saveConfiguration();
    930         } catch (RemoteException e) {
    931             return false;
    932         }
    933     }
    934 
    935     /**
    936      * Set the country code.
    937      * @param countryCode country code in ISO 3166 format.
    938      * @param persist {@code true} if this needs to be remembered
    939      *
    940      * @hide
    941      */
    942     public void setCountryCode(String country, boolean persist) {
    943         try {
    944             mService.setCountryCode(country, persist);
    945         } catch (RemoteException e) { }
    946     }
    947 
    948     /**
    949      * Set the operational frequency band.
    950      * @param band  One of
    951      *     {@link #WIFI_FREQUENCY_BAND_AUTO},
    952      *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
    953      *     {@link #WIFI_FREQUENCY_BAND_2GHZ},
    954      * @param persist {@code true} if this needs to be remembered
    955      * @hide
    956      */
    957     public void setFrequencyBand(int band, boolean persist) {
    958         try {
    959             mService.setFrequencyBand(band, persist);
    960         } catch (RemoteException e) { }
    961     }
    962 
    963     /**
    964      * Get the operational frequency band.
    965      * @return One of
    966      *     {@link #WIFI_FREQUENCY_BAND_AUTO},
    967      *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
    968      *     {@link #WIFI_FREQUENCY_BAND_2GHZ} or
    969      *     {@code -1} on failure.
    970      * @hide
    971      */
    972     public int getFrequencyBand() {
    973         try {
    974             return mService.getFrequencyBand();
    975         } catch (RemoteException e) {
    976             return -1;
    977         }
    978     }
    979 
    980     /**
    981      * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
    982      * @return {@code true} if supported, {@code false} otherwise.
    983      * @hide
    984      */
    985     public boolean isDualBandSupported() {
    986         try {
    987             return mService.isDualBandSupported();
    988         } catch (RemoteException e) {
    989             return false;
    990         }
    991     }
    992 
    993     /**
    994      * Return the DHCP-assigned addresses from the last successful DHCP request,
    995      * if any.
    996      * @return the DHCP information
    997      */
    998     public DhcpInfo getDhcpInfo() {
    999         try {
   1000             return mService.getDhcpInfo();
   1001         } catch (RemoteException e) {
   1002             return null;
   1003         }
   1004     }
   1005 
   1006     /**
   1007      * Enable or disable Wi-Fi.
   1008      * @param enabled {@code true} to enable, {@code false} to disable.
   1009      * @return {@code true} if the operation succeeds (or if the existing state
   1010      *         is the same as the requested state).
   1011      */
   1012     public boolean setWifiEnabled(boolean enabled) {
   1013         try {
   1014             return mService.setWifiEnabled(enabled);
   1015         } catch (RemoteException e) {
   1016             return false;
   1017         }
   1018     }
   1019 
   1020     /**
   1021      * Gets the Wi-Fi enabled state.
   1022      * @return One of {@link #WIFI_STATE_DISABLED},
   1023      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
   1024      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
   1025      * @see #isWifiEnabled()
   1026      */
   1027     public int getWifiState() {
   1028         try {
   1029             return mService.getWifiEnabledState();
   1030         } catch (RemoteException e) {
   1031             return WIFI_STATE_UNKNOWN;
   1032         }
   1033     }
   1034 
   1035     /**
   1036      * Return whether Wi-Fi is enabled or disabled.
   1037      * @return {@code true} if Wi-Fi is enabled
   1038      * @see #getWifiState()
   1039      */
   1040     public boolean isWifiEnabled() {
   1041         return getWifiState() == WIFI_STATE_ENABLED;
   1042     }
   1043 
   1044     /**
   1045      * Return TX packet counter, for CTS test of WiFi watchdog.
   1046      * @param listener is the interface to receive result
   1047      *
   1048      * @hide for CTS test only
   1049      */
   1050     public void getTxPacketCount(TxPacketCountListener listener) {
   1051         validateChannel();
   1052         sAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
   1053     }
   1054 
   1055     /**
   1056      * Calculates the level of the signal. This should be used any time a signal
   1057      * is being shown.
   1058      *
   1059      * @param rssi The power of the signal measured in RSSI.
   1060      * @param numLevels The number of levels to consider in the calculated
   1061      *            level.
   1062      * @return A level of the signal, given in the range of 0 to numLevels-1
   1063      *         (both inclusive).
   1064      */
   1065     public static int calculateSignalLevel(int rssi, int numLevels) {
   1066         if (rssi <= MIN_RSSI) {
   1067             return 0;
   1068         } else if (rssi >= MAX_RSSI) {
   1069             return numLevels - 1;
   1070         } else {
   1071             float inputRange = (MAX_RSSI - MIN_RSSI);
   1072             float outputRange = (numLevels - 1);
   1073             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
   1074         }
   1075     }
   1076 
   1077     /**
   1078      * Compares two signal strengths.
   1079      *
   1080      * @param rssiA The power of the first signal measured in RSSI.
   1081      * @param rssiB The power of the second signal measured in RSSI.
   1082      * @return Returns <0 if the first signal is weaker than the second signal,
   1083      *         0 if the two signals have the same strength, and >0 if the first
   1084      *         signal is stronger than the second signal.
   1085      */
   1086     public static int compareSignalLevel(int rssiA, int rssiB) {
   1087         return rssiA - rssiB;
   1088     }
   1089 
   1090     /**
   1091      * Start AccessPoint mode with the specified
   1092      * configuration. If the radio is already running in
   1093      * AP mode, update the new configuration
   1094      * Note that starting in access point mode disables station
   1095      * mode operation
   1096      * @param wifiConfig SSID, security and channel details as
   1097      *        part of WifiConfiguration
   1098      * @return {@code true} if the operation succeeds, {@code false} otherwise
   1099      *
   1100      * @hide Dont open up yet
   1101      */
   1102     public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
   1103         try {
   1104             mService.setWifiApEnabled(wifiConfig, enabled);
   1105             return true;
   1106         } catch (RemoteException e) {
   1107             return false;
   1108         }
   1109     }
   1110 
   1111     /**
   1112      * Gets the Wi-Fi enabled state.
   1113      * @return One of {@link #WIFI_AP_STATE_DISABLED},
   1114      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
   1115      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
   1116      * @see #isWifiApEnabled()
   1117      *
   1118      * @hide Dont open yet
   1119      */
   1120     public int getWifiApState() {
   1121         try {
   1122             return mService.getWifiApEnabledState();
   1123         } catch (RemoteException e) {
   1124             return WIFI_AP_STATE_FAILED;
   1125         }
   1126     }
   1127 
   1128     /**
   1129      * Return whether Wi-Fi AP is enabled or disabled.
   1130      * @return {@code true} if Wi-Fi AP is enabled
   1131      * @see #getWifiApState()
   1132      *
   1133      * @hide Dont open yet
   1134      */
   1135     public boolean isWifiApEnabled() {
   1136         return getWifiApState() == WIFI_AP_STATE_ENABLED;
   1137     }
   1138 
   1139     /**
   1140      * Gets the Wi-Fi AP Configuration.
   1141      * @return AP details in WifiConfiguration
   1142      *
   1143      * @hide Dont open yet
   1144      */
   1145     public WifiConfiguration getWifiApConfiguration() {
   1146         try {
   1147             return mService.getWifiApConfiguration();
   1148         } catch (RemoteException e) {
   1149             return null;
   1150         }
   1151     }
   1152 
   1153     /**
   1154      * Sets the Wi-Fi AP Configuration.
   1155      * @return {@code true} if the operation succeeded, {@code false} otherwise
   1156      *
   1157      * @hide Dont open yet
   1158      */
   1159     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
   1160         try {
   1161             mService.setWifiApConfiguration(wifiConfig);
   1162             return true;
   1163         } catch (RemoteException e) {
   1164             return false;
   1165         }
   1166     }
   1167 
   1168    /**
   1169      * Start the driver and connect to network.
   1170      *
   1171      * This function will over-ride WifiLock and device idle status. For example,
   1172      * even if the device is idle or there is only a scan-only lock held,
   1173      * a start wifi would mean that wifi connection is kept active until
   1174      * a stopWifi() is sent.
   1175      *
   1176      * This API is used by WifiStateTracker
   1177      *
   1178      * @return {@code true} if the operation succeeds else {@code false}
   1179      * @hide
   1180      */
   1181     public boolean startWifi() {
   1182         try {
   1183             mService.startWifi();
   1184             return true;
   1185         } catch (RemoteException e) {
   1186             return false;
   1187         }
   1188     }
   1189 
   1190     /**
   1191      * Disconnect from a network (if any) and stop the driver.
   1192      *
   1193      * This function will over-ride WifiLock and device idle status. Wi-Fi
   1194      * stays inactive until a startWifi() is issued.
   1195      *
   1196      * This API is used by WifiStateTracker
   1197      *
   1198      * @return {@code true} if the operation succeeds else {@code false}
   1199      * @hide
   1200      */
   1201     public boolean stopWifi() {
   1202         try {
   1203             mService.stopWifi();
   1204             return true;
   1205         } catch (RemoteException e) {
   1206             return false;
   1207         }
   1208     }
   1209 
   1210     /**
   1211      * Add a bssid to the supplicant blacklist
   1212      *
   1213      * This API is used by WifiWatchdogService
   1214      *
   1215      * @return {@code true} if the operation succeeds else {@code false}
   1216      * @hide
   1217      */
   1218     public boolean addToBlacklist(String bssid) {
   1219         try {
   1220             mService.addToBlacklist(bssid);
   1221             return true;
   1222         } catch (RemoteException e) {
   1223             return false;
   1224         }
   1225     }
   1226 
   1227     /**
   1228      * Clear the supplicant blacklist
   1229      *
   1230      * This API is used by WifiWatchdogService
   1231      *
   1232      * @return {@code true} if the operation succeeds else {@code false}
   1233      * @hide
   1234      */
   1235     public boolean clearBlacklist() {
   1236         try {
   1237             mService.clearBlacklist();
   1238             return true;
   1239         } catch (RemoteException e) {
   1240             return false;
   1241         }
   1242     }
   1243 
   1244 
   1245     /**
   1246      * Enable/Disable TDLS on a specific local route.
   1247      *
   1248      * <p>
   1249      * TDLS enables two wireless endpoints to talk to each other directly
   1250      * without going through the access point that is managing the local
   1251      * network. It saves bandwidth and improves quality of the link.
   1252      * </p>
   1253      * <p>
   1254      * This API enables/disables the option of using TDLS. If enabled, the
   1255      * underlying hardware is free to use TDLS or a hop through the access
   1256      * point. If disabled, existing TDLS session is torn down and
   1257      * hardware is restricted to use access point for transferring wireless
   1258      * packets. Default value for all routes is 'disabled', meaning restricted
   1259      * to use access point for transferring packets.
   1260      * </p>
   1261      *
   1262      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
   1263      * @param enable true = setup and false = tear down TDLS
   1264      */
   1265     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
   1266         try {
   1267             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
   1268         } catch (RemoteException e) {
   1269             // Just ignore the exception
   1270         }
   1271     }
   1272 
   1273     /**
   1274      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
   1275      * this version allows you to specify remote endpoint with a MAC address.
   1276      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
   1277      * @param enable true = setup and false = tear down TDLS
   1278      */
   1279     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
   1280         try {
   1281             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
   1282         } catch (RemoteException e) {
   1283             // Just ignore the exception
   1284         }
   1285     }
   1286 
   1287     /* TODO: deprecate synchronous API and open up the following API */
   1288 
   1289     private static final int BASE = Protocol.BASE_WIFI_MANAGER;
   1290 
   1291     /* Commands to WifiService */
   1292     /** @hide */
   1293     public static final int CONNECT_NETWORK                 = BASE + 1;
   1294     /** @hide */
   1295     public static final int CONNECT_NETWORK_FAILED          = BASE + 2;
   1296     /** @hide */
   1297     public static final int CONNECT_NETWORK_SUCCEEDED       = BASE + 3;
   1298 
   1299     /** @hide */
   1300     public static final int FORGET_NETWORK                  = BASE + 4;
   1301     /** @hide */
   1302     public static final int FORGET_NETWORK_FAILED           = BASE + 5;
   1303     /** @hide */
   1304     public static final int FORGET_NETWORK_SUCCEEDED        = BASE + 6;
   1305 
   1306     /** @hide */
   1307     public static final int SAVE_NETWORK                    = BASE + 7;
   1308     /** @hide */
   1309     public static final int SAVE_NETWORK_FAILED             = BASE + 8;
   1310     /** @hide */
   1311     public static final int SAVE_NETWORK_SUCCEEDED          = BASE + 9;
   1312 
   1313     /** @hide */
   1314     public static final int START_WPS                       = BASE + 10;
   1315     /** @hide */
   1316     public static final int START_WPS_SUCCEEDED             = BASE + 11;
   1317     /** @hide */
   1318     public static final int WPS_FAILED                      = BASE + 12;
   1319     /** @hide */
   1320     public static final int WPS_COMPLETED                   = BASE + 13;
   1321 
   1322     /** @hide */
   1323     public static final int CANCEL_WPS                      = BASE + 14;
   1324     /** @hide */
   1325     public static final int CANCEL_WPS_FAILED               = BASE + 15;
   1326     /** @hide */
   1327     public static final int CANCEL_WPS_SUCCEDED             = BASE + 16;
   1328 
   1329     /** @hide */
   1330     public static final int DISABLE_NETWORK                 = BASE + 17;
   1331     /** @hide */
   1332     public static final int DISABLE_NETWORK_FAILED          = BASE + 18;
   1333     /** @hide */
   1334     public static final int DISABLE_NETWORK_SUCCEEDED       = BASE + 19;
   1335 
   1336     /** @hide */
   1337     public static final int RSSI_PKTCNT_FETCH               = BASE + 20;
   1338     /** @hide */
   1339     public static final int RSSI_PKTCNT_FETCH_SUCCEEDED     = BASE + 21;
   1340     /** @hide */
   1341     public static final int RSSI_PKTCNT_FETCH_FAILED        = BASE + 22;
   1342 
   1343 
   1344     /**
   1345      * Passed with {@link ActionListener#onFailure}.
   1346      * Indicates that the operation failed due to an internal error.
   1347      * @hide
   1348      */
   1349     public static final int ERROR                       = 0;
   1350 
   1351     /**
   1352      * Passed with {@link ActionListener#onFailure}.
   1353      * Indicates that the operation is already in progress
   1354      * @hide
   1355      */
   1356     public static final int IN_PROGRESS                 = 1;
   1357 
   1358     /**
   1359      * Passed with {@link ActionListener#onFailure}.
   1360      * Indicates that the operation failed because the framework is busy and
   1361      * unable to service the request
   1362      * @hide
   1363      */
   1364     public static final int BUSY                        = 2;
   1365 
   1366     /* WPS specific errors */
   1367     /** WPS overlap detected {@hide} */
   1368     public static final int WPS_OVERLAP_ERROR           = 3;
   1369     /** WEP on WPS is prohibited {@hide} */
   1370     public static final int WPS_WEP_PROHIBITED          = 4;
   1371     /** TKIP only prohibited {@hide} */
   1372     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
   1373     /** Authentication failure on WPS {@hide} */
   1374     public static final int WPS_AUTH_FAILURE            = 6;
   1375     /** WPS timed out {@hide} */
   1376     public static final int WPS_TIMED_OUT               = 7;
   1377 
   1378     /**
   1379      * Passed with {@link ActionListener#onFailure}.
   1380      * Indicates that the operation failed due to invalid inputs
   1381      * @hide
   1382      */
   1383     public static final int INVALID_ARGS                = 8;
   1384 
   1385     /** Interface for callback invocation on an application action {@hide} */
   1386     public interface ActionListener {
   1387         /** The operation succeeded */
   1388         public void onSuccess();
   1389         /**
   1390          * The operation failed
   1391          * @param reason The reason for failure could be one of
   1392          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
   1393          */
   1394         public void onFailure(int reason);
   1395     }
   1396 
   1397     /** Interface for callback invocation on a start WPS action {@hide} */
   1398     public interface WpsListener {
   1399         /** WPS start succeeded */
   1400         public void onStartSuccess(String pin);
   1401 
   1402         /** WPS operation completed succesfully */
   1403         public void onCompletion();
   1404 
   1405         /**
   1406          * WPS operation failed
   1407          * @param reason The reason for failure could be one of
   1408          * {@link #IN_PROGRESS}, {@link #WPS_OVERLAP_ERROR},{@link #ERROR} or {@link #BUSY}
   1409          */
   1410         public void onFailure(int reason);
   1411     }
   1412 
   1413     /** Interface for callback invocation on a TX packet count poll action {@hide} */
   1414     public interface TxPacketCountListener {
   1415         /**
   1416          * The operation succeeded
   1417          * @param count TX packet counter
   1418          */
   1419         public void onSuccess(int count);
   1420         /**
   1421          * The operation failed
   1422          * @param reason The reason for failure could be one of
   1423          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
   1424          */
   1425         public void onFailure(int reason);
   1426     }
   1427 
   1428     private static class ServiceHandler extends Handler {
   1429         ServiceHandler(Looper looper) {
   1430             super(looper);
   1431         }
   1432 
   1433         @Override
   1434         public void handleMessage(Message message) {
   1435             Object listener = removeListener(message.arg2);
   1436             switch (message.what) {
   1437                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
   1438                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
   1439                         sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
   1440                     } else {
   1441                         Log.e(TAG, "Failed to set up channel connection");
   1442                         // This will cause all further async API calls on the WifiManager
   1443                         // to fail and throw an exception
   1444                         sAsyncChannel = null;
   1445                     }
   1446                     sConnected.countDown();
   1447                     break;
   1448                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
   1449                     // Ignore
   1450                     break;
   1451                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
   1452                     Log.e(TAG, "Channel connection lost");
   1453                     // This will cause all further async API calls on the WifiManager
   1454                     // to fail and throw an exception
   1455                     sAsyncChannel = null;
   1456                     getLooper().quit();
   1457                     break;
   1458                     /* ActionListeners grouped together */
   1459                 case WifiManager.CONNECT_NETWORK_FAILED:
   1460                 case WifiManager.FORGET_NETWORK_FAILED:
   1461                 case WifiManager.SAVE_NETWORK_FAILED:
   1462                 case WifiManager.CANCEL_WPS_FAILED:
   1463                 case WifiManager.DISABLE_NETWORK_FAILED:
   1464                     if (listener != null) {
   1465                         ((ActionListener) listener).onFailure(message.arg1);
   1466                     }
   1467                     break;
   1468                     /* ActionListeners grouped together */
   1469                 case WifiManager.CONNECT_NETWORK_SUCCEEDED:
   1470                 case WifiManager.FORGET_NETWORK_SUCCEEDED:
   1471                 case WifiManager.SAVE_NETWORK_SUCCEEDED:
   1472                 case WifiManager.CANCEL_WPS_SUCCEDED:
   1473                 case WifiManager.DISABLE_NETWORK_SUCCEEDED:
   1474                     if (listener != null) {
   1475                         ((ActionListener) listener).onSuccess();
   1476                     }
   1477                     break;
   1478                 case WifiManager.START_WPS_SUCCEEDED:
   1479                     if (listener != null) {
   1480                         WpsResult result = (WpsResult) message.obj;
   1481                         ((WpsListener) listener).onStartSuccess(result.pin);
   1482                         //Listener needs to stay until completion or failure
   1483                         synchronized(sListenerMapLock) {
   1484                             sListenerMap.put(message.arg2, listener);
   1485                         }
   1486                     }
   1487                     break;
   1488                 case WifiManager.WPS_COMPLETED:
   1489                     if (listener != null) {
   1490                         ((WpsListener) listener).onCompletion();
   1491                     }
   1492                     break;
   1493                 case WifiManager.WPS_FAILED:
   1494                     if (listener != null) {
   1495                         ((WpsListener) listener).onFailure(message.arg1);
   1496                     }
   1497                     break;
   1498                 case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
   1499                     if (listener != null) {
   1500                         RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj;
   1501                         if (info != null)
   1502                             ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad);
   1503                         else
   1504                             ((TxPacketCountListener) listener).onFailure(ERROR);
   1505                     }
   1506                     break;
   1507                 case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
   1508                     if (listener != null) {
   1509                         ((TxPacketCountListener) listener).onFailure(message.arg1);
   1510                     }
   1511                     break;
   1512                 default:
   1513                     //ignore
   1514                     break;
   1515             }
   1516         }
   1517     }
   1518 
   1519     private static int putListener(Object listener) {
   1520         if (listener == null) return INVALID_KEY;
   1521         int key;
   1522         synchronized (sListenerMapLock) {
   1523             do {
   1524                 key = sListenerKey++;
   1525             } while (key == INVALID_KEY);
   1526             sListenerMap.put(key, listener);
   1527         }
   1528         return key;
   1529     }
   1530 
   1531     private static Object removeListener(int key) {
   1532         if (key == INVALID_KEY) return null;
   1533         synchronized (sListenerMapLock) {
   1534             Object listener = sListenerMap.get(key);
   1535             sListenerMap.remove(key);
   1536             return listener;
   1537         }
   1538     }
   1539 
   1540     private void init() {
   1541         synchronized (sThreadRefLock) {
   1542             if (++sThreadRefCount == 1) {
   1543                 Messenger messenger = getWifiServiceMessenger();
   1544                 if (messenger == null) {
   1545                     sAsyncChannel = null;
   1546                     return;
   1547                 }
   1548 
   1549                 sHandlerThread = new HandlerThread("WifiManager");
   1550                 sAsyncChannel = new AsyncChannel();
   1551                 sConnected = new CountDownLatch(1);
   1552 
   1553                 sHandlerThread.start();
   1554                 Handler handler = new ServiceHandler(sHandlerThread.getLooper());
   1555                 sAsyncChannel.connect(mContext, handler, messenger);
   1556                 try {
   1557                     sConnected.await();
   1558                 } catch (InterruptedException e) {
   1559                     Log.e(TAG, "interrupted wait at init");
   1560                 }
   1561             }
   1562         }
   1563     }
   1564 
   1565     private void validateChannel() {
   1566         if (sAsyncChannel == null) throw new IllegalStateException(
   1567                 "No permission to access and change wifi or a bad initialization");
   1568     }
   1569 
   1570     /**
   1571      * Connect to a network with the given configuration. The network also
   1572      * gets added to the supplicant configuration.
   1573      *
   1574      * For a new network, this function is used instead of a
   1575      * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
   1576      * reconnect()
   1577      *
   1578      * @param config the set of variables that describe the configuration,
   1579      *            contained in a {@link WifiConfiguration} object.
   1580      * @param listener for callbacks on success or failure. Can be null.
   1581      * @throws IllegalStateException if the WifiManager instance needs to be
   1582      * initialized again
   1583      *
   1584      * @hide
   1585      */
   1586     public void connect(WifiConfiguration config, ActionListener listener) {
   1587         if (config == null) throw new IllegalArgumentException("config cannot be null");
   1588         validateChannel();
   1589         // Use INVALID_NETWORK_ID for arg1 when passing a config object
   1590         // arg1 is used to pass network id when the network already exists
   1591         sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
   1592                 putListener(listener), config);
   1593     }
   1594 
   1595     /**
   1596      * Connect to a network with the given networkId.
   1597      *
   1598      * This function is used instead of a enableNetwork(), saveConfiguration() and
   1599      * reconnect()
   1600      *
   1601      * @param networkId the network id identifiying the network in the
   1602      *                supplicant configuration list
   1603      * @param listener for callbacks on success or failure. Can be null.
   1604      * @throws IllegalStateException if the WifiManager instance needs to be
   1605      * initialized again
   1606      * @hide
   1607      */
   1608     public void connect(int networkId, ActionListener listener) {
   1609         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   1610         validateChannel();
   1611         sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
   1612     }
   1613 
   1614     /**
   1615      * Save the given network in the supplicant config. If the network already
   1616      * exists, the configuration is updated. A new network is enabled
   1617      * by default.
   1618      *
   1619      * For a new network, this function is used instead of a
   1620      * sequence of addNetwork(), enableNetwork() and saveConfiguration().
   1621      *
   1622      * For an existing network, it accomplishes the task of updateNetwork()
   1623      * and saveConfiguration()
   1624      *
   1625      * @param config the set of variables that describe the configuration,
   1626      *            contained in a {@link WifiConfiguration} object.
   1627      * @param listener for callbacks on success or failure. Can be null.
   1628      * @throws IllegalStateException if the WifiManager instance needs to be
   1629      * initialized again
   1630      * @hide
   1631      */
   1632     public void save(WifiConfiguration config, ActionListener listener) {
   1633         if (config == null) throw new IllegalArgumentException("config cannot be null");
   1634         validateChannel();
   1635         sAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
   1636     }
   1637 
   1638     /**
   1639      * Delete the network in the supplicant config.
   1640      *
   1641      * This function is used instead of a sequence of removeNetwork()
   1642      * and saveConfiguration().
   1643      *
   1644      * @param config the set of variables that describe the configuration,
   1645      *            contained in a {@link WifiConfiguration} object.
   1646      * @param listener for callbacks on success or failure. Can be null.
   1647      * @throws IllegalStateException if the WifiManager instance needs to be
   1648      * initialized again
   1649      * @hide
   1650      */
   1651     public void forget(int netId, ActionListener listener) {
   1652         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   1653         validateChannel();
   1654         sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener));
   1655     }
   1656 
   1657     /**
   1658      * Disable network
   1659      *
   1660      * @param netId is the network Id
   1661      * @param listener for callbacks on success or failure. Can be null.
   1662      * @throws IllegalStateException if the WifiManager instance needs to be
   1663      * initialized again
   1664      * @hide
   1665      */
   1666     public void disable(int netId, ActionListener listener) {
   1667         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   1668         validateChannel();
   1669         sAsyncChannel.sendMessage(DISABLE_NETWORK, netId, putListener(listener));
   1670     }
   1671 
   1672     /**
   1673      * Start Wi-fi Protected Setup
   1674      *
   1675      * @param config WPS configuration
   1676      * @param listener for callbacks on success or failure. Can be null.
   1677      * @throws IllegalStateException if the WifiManager instance needs to be
   1678      * initialized again
   1679      * @hide
   1680      */
   1681     public void startWps(WpsInfo config, WpsListener listener) {
   1682         if (config == null) throw new IllegalArgumentException("config cannot be null");
   1683         validateChannel();
   1684         sAsyncChannel.sendMessage(START_WPS, 0, putListener(listener), config);
   1685     }
   1686 
   1687     /**
   1688      * Cancel any ongoing Wi-fi Protected Setup
   1689      *
   1690      * @param listener for callbacks on success or failure. Can be null.
   1691      * @throws IllegalStateException if the WifiManager instance needs to be
   1692      * initialized again
   1693      * @hide
   1694      */
   1695     public void cancelWps(ActionListener listener) {
   1696         validateChannel();
   1697         sAsyncChannel.sendMessage(CANCEL_WPS, 0, putListener(listener));
   1698     }
   1699 
   1700     /**
   1701      * Get a reference to WifiService handler. This is used by a client to establish
   1702      * an AsyncChannel communication with WifiService
   1703      *
   1704      * @return Messenger pointing to the WifiService handler
   1705      * @hide
   1706      */
   1707     public Messenger getWifiServiceMessenger() {
   1708         try {
   1709             return mService.getWifiServiceMessenger();
   1710         } catch (RemoteException e) {
   1711             return null;
   1712         } catch (SecurityException e) {
   1713             return null;
   1714         }
   1715     }
   1716 
   1717     /**
   1718      * Get a reference to WifiStateMachine handler.
   1719      * @return Messenger pointing to the WifiService handler
   1720      * @hide
   1721      */
   1722     public Messenger getWifiStateMachineMessenger() {
   1723         try {
   1724             return mService.getWifiStateMachineMessenger();
   1725         } catch (RemoteException e) {
   1726             return null;
   1727         }
   1728     }
   1729 
   1730     /**
   1731      * Returns the file in which IP and proxy configuration data is stored
   1732      * @hide
   1733      */
   1734     public String getConfigFile() {
   1735         try {
   1736             return mService.getConfigFile();
   1737         } catch (RemoteException e) {
   1738             return null;
   1739         }
   1740     }
   1741 
   1742     /**
   1743      * Allows an application to keep the Wi-Fi radio awake.
   1744      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
   1745      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
   1746      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
   1747      * WifiLocks are held in any application.
   1748      * <p>
   1749      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
   1750      * could function over a mobile network, if available.  A program that needs to download large
   1751      * files should hold a WifiLock to ensure that the download will complete, but a program whose
   1752      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
   1753      * affecting battery life.
   1754      * <p>
   1755      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
   1756      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
   1757      * is idle.
   1758      * <p>
   1759      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
   1760      * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
   1761      */
   1762     public class WifiLock {
   1763         private String mTag;
   1764         private final IBinder mBinder;
   1765         private int mRefCount;
   1766         int mLockType;
   1767         private boolean mRefCounted;
   1768         private boolean mHeld;
   1769         private WorkSource mWorkSource;
   1770 
   1771         private WifiLock(int lockType, String tag) {
   1772             mTag = tag;
   1773             mLockType = lockType;
   1774             mBinder = new Binder();
   1775             mRefCount = 0;
   1776             mRefCounted = true;
   1777             mHeld = false;
   1778         }
   1779 
   1780         /**
   1781          * Locks the Wi-Fi radio on until {@link #release} is called.
   1782          *
   1783          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
   1784          * reference count, and the radio will remain locked as long as the reference count is
   1785          * above zero.
   1786          *
   1787          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
   1788          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
   1789          * will be required, regardless of the number of times that {@code acquire} is called.
   1790          */
   1791         public void acquire() {
   1792             synchronized (mBinder) {
   1793                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
   1794                     try {
   1795                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
   1796                         synchronized (WifiManager.this) {
   1797                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
   1798                                 mService.releaseWifiLock(mBinder);
   1799                                 throw new UnsupportedOperationException(
   1800                                             "Exceeded maximum number of wifi locks");
   1801                             }
   1802                             mActiveLockCount++;
   1803                         }
   1804                     } catch (RemoteException ignore) {
   1805                     }
   1806                     mHeld = true;
   1807                 }
   1808             }
   1809         }
   1810 
   1811         /**
   1812          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
   1813          *
   1814          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
   1815          * reference count, and the radio will be unlocked only when the reference count reaches
   1816          * zero.  If the reference count goes below zero (that is, if {@code release} is called
   1817          * a greater number of times than {@link #acquire}), an exception is thrown.
   1818          *
   1819          * If this WifiLock is not reference-counted, the first call to {@code release} (after
   1820          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
   1821          * calls will be ignored.
   1822          */
   1823         public void release() {
   1824             synchronized (mBinder) {
   1825                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
   1826                     try {
   1827                         mService.releaseWifiLock(mBinder);
   1828                         synchronized (WifiManager.this) {
   1829                             mActiveLockCount--;
   1830                         }
   1831                     } catch (RemoteException ignore) {
   1832                     }
   1833                     mHeld = false;
   1834                 }
   1835                 if (mRefCount < 0) {
   1836                     throw new RuntimeException("WifiLock under-locked " + mTag);
   1837                 }
   1838             }
   1839         }
   1840 
   1841         /**
   1842          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
   1843          *
   1844          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
   1845          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
   1846          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
   1847          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
   1848          * radio whenever {@link #release} is called and it is locked.
   1849          *
   1850          * @param refCounted true if this WifiLock should keep a reference count
   1851          */
   1852         public void setReferenceCounted(boolean refCounted) {
   1853             mRefCounted = refCounted;
   1854         }
   1855 
   1856         /**
   1857          * Checks whether this WifiLock is currently held.
   1858          *
   1859          * @return true if this WifiLock is held, false otherwise
   1860          */
   1861         public boolean isHeld() {
   1862             synchronized (mBinder) {
   1863                 return mHeld;
   1864             }
   1865         }
   1866 
   1867         public void setWorkSource(WorkSource ws) {
   1868             synchronized (mBinder) {
   1869                 if (ws != null && ws.size() == 0) {
   1870                     ws = null;
   1871                 }
   1872                 boolean changed = true;
   1873                 if (ws == null) {
   1874                     mWorkSource = null;
   1875                 } else {
   1876                     ws.clearNames();
   1877                     if (mWorkSource == null) {
   1878                         changed = mWorkSource != null;
   1879                         mWorkSource = new WorkSource(ws);
   1880                     } else {
   1881                         changed = mWorkSource.diff(ws);
   1882                         if (changed) {
   1883                             mWorkSource.set(ws);
   1884                         }
   1885                     }
   1886                 }
   1887                 if (changed && mHeld) {
   1888                     try {
   1889                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
   1890                     } catch (RemoteException e) {
   1891                     }
   1892                 }
   1893             }
   1894         }
   1895 
   1896         public String toString() {
   1897             String s1, s2, s3;
   1898             synchronized (mBinder) {
   1899                 s1 = Integer.toHexString(System.identityHashCode(this));
   1900                 s2 = mHeld ? "held; " : "";
   1901                 if (mRefCounted) {
   1902                     s3 = "refcounted: refcount = " + mRefCount;
   1903                 } else {
   1904                     s3 = "not refcounted";
   1905                 }
   1906                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
   1907             }
   1908         }
   1909 
   1910         @Override
   1911         protected void finalize() throws Throwable {
   1912             super.finalize();
   1913             synchronized (mBinder) {
   1914                 if (mHeld) {
   1915                     try {
   1916                         mService.releaseWifiLock(mBinder);
   1917                         synchronized (WifiManager.this) {
   1918                             mActiveLockCount--;
   1919                         }
   1920                     } catch (RemoteException ignore) {
   1921                     }
   1922                 }
   1923             }
   1924         }
   1925     }
   1926 
   1927     /**
   1928      * Creates a new WifiLock.
   1929      *
   1930      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
   1931      * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for
   1932      * descriptions of the types of Wi-Fi locks.
   1933      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
   1934      *            never shown to the user under normal conditions, but should be descriptive
   1935      *            enough to identify your application and the specific WifiLock within it, if it
   1936      *            holds multiple WifiLocks.
   1937      *
   1938      * @return a new, unacquired WifiLock with the given tag.
   1939      *
   1940      * @see WifiLock
   1941      */
   1942     public WifiLock createWifiLock(int lockType, String tag) {
   1943         return new WifiLock(lockType, tag);
   1944     }
   1945 
   1946     /**
   1947      * Creates a new WifiLock.
   1948      *
   1949      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
   1950      *            never shown to the user under normal conditions, but should be descriptive
   1951      *            enough to identify your application and the specific WifiLock within it, if it
   1952      *            holds multiple WifiLocks.
   1953      *
   1954      * @return a new, unacquired WifiLock with the given tag.
   1955      *
   1956      * @see WifiLock
   1957      */
   1958     public WifiLock createWifiLock(String tag) {
   1959         return new WifiLock(WIFI_MODE_FULL, tag);
   1960     }
   1961 
   1962 
   1963     /**
   1964      * Create a new MulticastLock
   1965      *
   1966      * @param tag a tag for the MulticastLock to identify it in debugging
   1967      *            messages.  This string is never shown to the user under
   1968      *            normal conditions, but should be descriptive enough to
   1969      *            identify your application and the specific MulticastLock
   1970      *            within it, if it holds multiple MulticastLocks.
   1971      *
   1972      * @return a new, unacquired MulticastLock with the given tag.
   1973      *
   1974      * @see MulticastLock
   1975      */
   1976     public MulticastLock createMulticastLock(String tag) {
   1977         return new MulticastLock(tag);
   1978     }
   1979 
   1980     /**
   1981      * Allows an application to receive Wifi Multicast packets.
   1982      * Normally the Wifi stack filters out packets not explicitly
   1983      * addressed to this device.  Acquring a MulticastLock will
   1984      * cause the stack to receive packets addressed to multicast
   1985      * addresses.  Processing these extra packets can cause a noticable
   1986      * battery drain and should be disabled when not needed.
   1987      */
   1988     public class MulticastLock {
   1989         private String mTag;
   1990         private final IBinder mBinder;
   1991         private int mRefCount;
   1992         private boolean mRefCounted;
   1993         private boolean mHeld;
   1994 
   1995         private MulticastLock(String tag) {
   1996             mTag = tag;
   1997             mBinder = new Binder();
   1998             mRefCount = 0;
   1999             mRefCounted = true;
   2000             mHeld = false;
   2001         }
   2002 
   2003         /**
   2004          * Locks Wifi Multicast on until {@link #release} is called.
   2005          *
   2006          * If this MulticastLock is reference-counted each call to
   2007          * {@code acquire} will increment the reference count, and the
   2008          * wifi interface will receive multicast packets as long as the
   2009          * reference count is above zero.
   2010          *
   2011          * If this MulticastLock is not reference-counted, the first call to
   2012          * {@code acquire} will turn on the multicast packets, but subsequent
   2013          * calls will be ignored.  Only one call to {@link #release} will
   2014          * be required, regardless of the number of times that {@code acquire}
   2015          * is called.
   2016          *
   2017          * Note that other applications may also lock Wifi Multicast on.
   2018          * Only they can relinquish their lock.
   2019          *
   2020          * Also note that applications cannot leave Multicast locked on.
   2021          * When an app exits or crashes, any Multicast locks will be released.
   2022          */
   2023         public void acquire() {
   2024             synchronized (mBinder) {
   2025                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
   2026                     try {
   2027                         mService.acquireMulticastLock(mBinder, mTag);
   2028                         synchronized (WifiManager.this) {
   2029                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
   2030                                 mService.releaseMulticastLock();
   2031                                 throw new UnsupportedOperationException(
   2032                                         "Exceeded maximum number of wifi locks");
   2033                             }
   2034                             mActiveLockCount++;
   2035                         }
   2036                     } catch (RemoteException ignore) {
   2037                     }
   2038                     mHeld = true;
   2039                 }
   2040             }
   2041         }
   2042 
   2043         /**
   2044          * Unlocks Wifi Multicast, restoring the filter of packets
   2045          * not addressed specifically to this device and saving power.
   2046          *
   2047          * If this MulticastLock is reference-counted, each call to
   2048          * {@code release} will decrement the reference count, and the
   2049          * multicast packets will only stop being received when the reference
   2050          * count reaches zero.  If the reference count goes below zero (that
   2051          * is, if {@code release} is called a greater number of times than
   2052          * {@link #acquire}), an exception is thrown.
   2053          *
   2054          * If this MulticastLock is not reference-counted, the first call to
   2055          * {@code release} (after the radio was multicast locked using
   2056          * {@link #acquire}) will unlock the multicast, and subsequent calls
   2057          * will be ignored.
   2058          *
   2059          * Note that if any other Wifi Multicast Locks are still outstanding
   2060          * this {@code release} call will not have an immediate effect.  Only
   2061          * when all applications have released all their Multicast Locks will
   2062          * the Multicast filter be turned back on.
   2063          *
   2064          * Also note that when an app exits or crashes all of its Multicast
   2065          * Locks will be automatically released.
   2066          */
   2067         public void release() {
   2068             synchronized (mBinder) {
   2069                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
   2070                     try {
   2071                         mService.releaseMulticastLock();
   2072                         synchronized (WifiManager.this) {
   2073                             mActiveLockCount--;
   2074                         }
   2075                     } catch (RemoteException ignore) {
   2076                     }
   2077                     mHeld = false;
   2078                 }
   2079                 if (mRefCount < 0) {
   2080                     throw new RuntimeException("MulticastLock under-locked "
   2081                             + mTag);
   2082                 }
   2083             }
   2084         }
   2085 
   2086         /**
   2087          * Controls whether this is a reference-counted or non-reference-
   2088          * counted MulticastLock.
   2089          *
   2090          * Reference-counted MulticastLocks keep track of the number of calls
   2091          * to {@link #acquire} and {@link #release}, and only stop the
   2092          * reception of multicast packets when every call to {@link #acquire}
   2093          * has been balanced with a call to {@link #release}.  Non-reference-
   2094          * counted MulticastLocks allow the reception of multicast packets
   2095          * whenever {@link #acquire} is called and stop accepting multicast
   2096          * packets whenever {@link #release} is called.
   2097          *
   2098          * @param refCounted true if this MulticastLock should keep a reference
   2099          * count
   2100          */
   2101         public void setReferenceCounted(boolean refCounted) {
   2102             mRefCounted = refCounted;
   2103         }
   2104 
   2105         /**
   2106          * Checks whether this MulticastLock is currently held.
   2107          *
   2108          * @return true if this MulticastLock is held, false otherwise
   2109          */
   2110         public boolean isHeld() {
   2111             synchronized (mBinder) {
   2112                 return mHeld;
   2113             }
   2114         }
   2115 
   2116         public String toString() {
   2117             String s1, s2, s3;
   2118             synchronized (mBinder) {
   2119                 s1 = Integer.toHexString(System.identityHashCode(this));
   2120                 s2 = mHeld ? "held; " : "";
   2121                 if (mRefCounted) {
   2122                     s3 = "refcounted: refcount = " + mRefCount;
   2123                 } else {
   2124                     s3 = "not refcounted";
   2125                 }
   2126                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
   2127             }
   2128         }
   2129 
   2130         @Override
   2131         protected void finalize() throws Throwable {
   2132             super.finalize();
   2133             setReferenceCounted(false);
   2134             release();
   2135         }
   2136     }
   2137 
   2138     /**
   2139      * Check multicast filter status.
   2140      *
   2141      * @return true if multicast packets are allowed.
   2142      *
   2143      * @hide pending API council approval
   2144      */
   2145     public boolean isMulticastEnabled() {
   2146         try {
   2147             return mService.isMulticastEnabled();
   2148         } catch (RemoteException e) {
   2149             return false;
   2150         }
   2151     }
   2152 
   2153     /**
   2154      * Initialize the multicast filtering to 'on'
   2155      * @hide no intent to publish
   2156      */
   2157     public boolean initializeMulticastFiltering() {
   2158         try {
   2159             mService.initializeMulticastFiltering();
   2160             return true;
   2161         } catch (RemoteException e) {
   2162              return false;
   2163         }
   2164     }
   2165 
   2166     /** @hide */
   2167     public void captivePortalCheckComplete() {
   2168         try {
   2169             mService.captivePortalCheckComplete();
   2170         } catch (RemoteException e) {}
   2171     }
   2172 
   2173     protected void finalize() throws Throwable {
   2174         try {
   2175             synchronized (sThreadRefLock) {
   2176                 if (--sThreadRefCount == 0 && sAsyncChannel != null) {
   2177                     sAsyncChannel.disconnect();
   2178                 }
   2179             }
   2180         } finally {
   2181             super.finalize();
   2182         }
   2183     }
   2184 }
   2185