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